#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
+from __future__ import print_function
import sys
-import re
-import traceback
-import os.path
-import optparse
+
+import CRL
import Cfg
-import Hurricane
-from Hurricane import DbU
-from Hurricane import DataBase
-from Hurricane import UpdateSession
-from Hurricane import Breakpoint
from Hurricane import Box
from Hurricane import Transformation
-from Hurricane import Instance
-from Hurricane import Net
-from Hurricane import Contact
-from Hurricane import Vertical
-from Hurricane import Pad
-from Hurricane import Pin
-from Hurricane import NetExternalComponents
-import Viewer
-import CRL
-import Etesian
-import Anabatic
-import Katana
-import Unicorn
-from helpers import l, u, n
-import clocktree.ClockTree
-import plugins.RSavePlugin
-import plugins.ClockTreePlugin
-import symbolic.cmos
-
-af = CRL.AllianceFramework.get()
+from coriolis2.settings import af
+from utils import Module, SessionManager, Config
+import symbolic.cmos # do not remove
-def toDbU(l): return DbU.fromLambda(l)
+BIT_WIDTH = 16
-def createVertical(contacts, x, layer, width=None):
- def yincrease(lhs, rhs):
- return int(lhs.getY() - rhs.getY())
+def coriolis_setup():
+ with Config(Cfg.Parameter.Priority.UserFile) as cfg:
+ cfg.misc_catchCore = False
+ cfg.misc_info = False
+ cfg.misc_paranoid = False
+ cfg.misc_bug = False
+ cfg.misc_logMode = True
+ cfg.misc_verboseLevel1 = True
+ cfg.misc_verboseLevel2 = True
+ cfg.etesian_effort = 2
+ cfg.etesian_spaceMargin = "20.0%"
+ cfg.etesian_aspectRatio = "100.0%"
+ cfg.etesian_uniformDensity = True
+ cfg.anabatic_edgeLenght = 24
+ cfg.anabatic_edgeWidth = 8
+ cfg.anabatic_topRoutingLayer = 'METAL5'
+ cfg.katana_searchHalo = 30
+ cfg.katana_eventsLimit = 1000000
+ cfg.katana_hTracksReservedLocal = 7
+ cfg.katana_vTracksReservedLocal = 6
- contacts.sort(yincrease)
+ env = af.getEnvironment()
+ env.setCLOCK('^clk$|m_clock')
+ env.setPOWER('vdd')
+ env.setGROUND('vss')
- if width is None: width = l(2.0)
- for i in range(1, len(contacts)):
- print "create vert", contacts[i - 1], contacts[i], layer, x, width
- v = Vertical.create(contacts[i - 1], contacts[i], layer, x, width)
- print "v", v
-
-
-def createHorizontal(contactPaths, y, layer, width=None):
- def xincrease(lhs, rhs):
- return int(lhs.getX() - rhs.getX())
+class AddSub(Module):
- contacts = contactPaths
-
- if width is None: width = toDbU(2.0)
+ def build(self):
+ """ Main routine. """
- contacts.sort(xincrease)
+ with SessionManager():
+ self.compute_ab()
+ self.create_pins()
- for i in range(1, len(contacts)):
- Horizontal.create(contacts[i - 1], contacts[i], layer, y, width)
+ if self.editor:
+ self.editor.setCell(self.cell)
-
-def build_downtrace(net, layer, x, y, y1):
- contacts = \
- [Contact.create(net, layer, l(x), l(y), l(2.0), l(2.0))
- , Contact.create(net, layer, l(x), l(y1), l(2.0), l(2.0))
- ]
-
- createVertical(contacts, l(x), layer)
- print "slaves", contacts[-1].getSlaveComponents()
- for component in contacts[-1].getSlaveComponents():
- NetExternalComponents.setExternal(component)
-
-
-def placeAndRoute(cell):
- etesian = Etesian.EtesianEngine.create(cell)
- etesian.place()
-
- katana = Katana.KatanaEngine.create(cell)
- katana.digitalInit()
- katana.runGlobalRouter(Katana.Flags.NoFlags)
- katana.loadGlobalRouting(Anabatic.EngineLoadGrByNet)
- katana.layerAssign(Anabatic.EngineNoNetLayerAssign)
- katana.runNegociate(Katana.Flags.NoFlags)
- katana.finalizeLayout()
- success = katana.isDetailedRoutingSuccess()
- katana.destroy()
-
- return success
-
-
-def coriolisSetup():
- Cfg.Configuration.pushDefaultPriority(Cfg.Parameter.Priority.UserFile)
-
- cellsTop = '~/alliance-check-toolkit/cells'
- env = af.getEnvironment()
- env.addSYSTEM_LIBRARY(library=cellsTop + '/nsxlib',
- mode=CRL.Environment.Prepend)
- env.addSYSTEM_LIBRARY(library=cellsTop + '/mpxlib',
- mode=CRL.Environment.Prepend)
-
- Cfg.getParamBool('misc.catchCore').setBool(False)
- Cfg.getParamBool('misc.info').setBool(False)
- Cfg.getParamBool('misc.paranoid').setBool(False)
- Cfg.getParamBool('misc.bug').setBool(False)
- Cfg.getParamBool('misc.logMode').setBool(True)
- Cfg.getParamBool('misc.verboseLevel1').setBool(True)
- Cfg.getParamBool('misc.verboseLevel2').setBool(True)
- # Cfg.getParamInt ( 'misc.minTraceLevel' ).setInt ( 111 )
- # Cfg.getParamInt ( 'misc.maxTraceLevel' ).setInt ( 112 )
- Cfg.getParamEnumerate('etesian.effort').setInt(2)
- Cfg.getParamPercentage('etesian.spaceMargin').setPercentage(20.0)
- Cfg.getParamPercentage('etesian.aspectRatio').setPercentage(100.0)
- Cfg.getParamBool('etesian.uniformDensity').setBool(True)
- Cfg.getParamInt('anabatic.edgeLenght').setInt(24)
- Cfg.getParamInt('anabatic.edgeWidth').setInt(8)
- Cfg.getParamString('anabatic.topRoutingLayer').setString('METAL5')
- Cfg.getParamInt('katana.searchHalo').setInt(30)
- Cfg.getParamInt('katana.eventsLimit').setInt(1000000)
- Cfg.getParamInt('katana.hTracksReservedLocal').setInt(7)
- Cfg.getParamInt('katana.vTracksReservedLocal').setInt(6)
- # Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1000) )
-
- env = af.getEnvironment()
- env.setCLOCK('^clk$|m_clock')
- env.setPOWER('vdd')
- env.setGROUND('vss')
-
- Cfg.Configuration.popDefaultPriority()
-
-
-# -------------------------------------------------------------------------------
-# add()
-
-def add(**kw):
- editor = None
- if kw.has_key('editor') and kw['editor']:
- editor = kw['editor']
-
- db = DataBase.getDB()
- print db, dir(db)
- METAL2 = DataBase.getDB().getTechnology().getLayer('METAL2')
- METAL3 = DataBase.getDB().getTechnology().getLayer('METAL3')
- METAL5 = DataBase.getDB().getTechnology().getLayer('METAL5')
- BLOCKAGE2 = DataBase.getDB().getTechnology().getLayer('BLOCKAGE2')
- BLOCKAGE3 = DataBase.getDB().getTechnology().getLayer('BLOCKAGE3')
- BLOCKAGE4 = DataBase.getDB().getTechnology().getLayer('BLOCKAGE4')
- BLOCKAGE5 = DataBase.getDB().getTechnology().getLayer('BLOCKAGE5')
-
- cell = af.getCell('add', CRL.Catalog.State.Logical)
- print cell.getNet('a(0)')
-
- if not cell:
- print '[ERROR] Unable to load cell "add.vst", aborting .'
- return False
-
- kw['cell'] = cell
-
- width = 350.0
- height = 400.0
-
- ab = Box(l(0.0)
- , l(0.0)
- , l(width)
- , l(height))
-
- cellGauge = af.getCellGauge()
- spaceMargin = (Cfg.getParamPercentage(
- 'etesian.spaceMargin').asPercentage() + 5) / 100.0
- aspectRatio = Cfg.getParamPercentage(
- 'etesian.aspectRatio').asPercentage() / 100.0
- clocktree.ClockTree.computeAbutmentBox(cell, spaceMargin, aspectRatio,
- cellGauge)
- ab2 = cell.getAbutmentBox()
- print "box", ab, ab.getHeight(), ab.getWidth()
- print "calc box", ab2, ab2.getHeight(), ab2.getWidth()
-
- # height = ab.getHeight()
- # width = ab.getWidth()
-
- UpdateSession.open()
- cell.setAbutmentBox(ab)
-
- for i in range(16):
- if True:
- x = 20.0 * i + 10.0
- y = height
- pin = Pin.create(cell.getNet('a(%d)' % i)
- , 'a(%d).0' % i
- , Pin.Direction.NORTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(x), l(y - 0) # Position.
- , l(2.0), l(2.0) # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
- for i in range(16):
- if True:
- pin = Pin.create(cell.getNet('o(%d)' % i)
- , 'o(%d).0' % i
- , Pin.Direction.SOUTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(10.0 * i + 100.0), l(0) # Position.
- , l(2.0), l(2.0) # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- for i in range(16):
- if True:
- net = cell.getNet('b(%d)' % i)
- x = 20.0 * i + 10.0 + 10
- y = height - 0
- # build_downtrace(net, METAL3, x, y+11, y)
- # continue
- pin = Pin.create(net
- , 'b(%d).0' % i
- , Pin.Direction.NORTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(x), l(y - 0) # Position.
- , l(2.0), l(2.0) # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
- if False:
- pin = Pin.create(cell.getNet('rst')
- , 'p_reset.0'
- , Pin.Direction.WEST
- , Pin.PlacementStatus.FIXED
- , METAL2
- , l(0.0)
- , l(140.0)
- , l(2.0)
- , l(2.0)
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- UpdateSession.close()
-
- if True:
- if editor: editor.setCell(cell)
-
- placeAndRoute(cell)
-
- UpdateSession.open()
- blockageNet = cell.getNet('blockagenet')
-
- ab = cell.getAbutmentBox()
- ab.inflate(toDbU(-5.0))
- Pad.create(net, BLOCKAGE2, ab)
- Pad.create(net, BLOCKAGE3, ab)
- Pad.create(net, BLOCKAGE4, ab)
- # Pad.create( net, BLOCKAGE5, ab )
- UpdateSession.close()
-
- if False:
- UpdateSession.open()
- cell.setAbutmentBox(ab)
- for i in range(16):
- if True:
- net = cell.getNet('b(%d)' % i)
- x = 20.0 * i + 10.0 + 10
- y = height - 10
- build_downtrace(net, METAL2, x, y, y + 10)
- UpdateSession.close()
-
- # af.saveCell( cell, CRL.Catalog.State.Views )
- plugins.RSavePlugin.ScriptMain(**kw)
-
-
-# -------------------------------------------------------------------------------
-# sub
-
-def sub(**kw):
- editor = None
- if kw.has_key('editor') and kw['editor']:
- editor = kw['editor']
-
- db = DataBase.getDB()
- print db, dir(db)
- METAL2 = DataBase.getDB().getTechnology().getLayer('METAL2')
- METAL3 = DataBase.getDB().getTechnology().getLayer('METAL3')
- METAL5 = DataBase.getDB().getTechnology().getLayer('METAL5')
- BLOCKAGE2 = DataBase.getDB().getTechnology().getLayer('BLOCKAGE2')
- BLOCKAGE3 = DataBase.getDB().getTechnology().getLayer('BLOCKAGE3')
- BLOCKAGE4 = DataBase.getDB().getTechnology().getLayer('BLOCKAGE4')
- BLOCKAGE5 = DataBase.getDB().getTechnology().getLayer('BLOCKAGE5')
-
- cell = af.getCell('sub', CRL.Catalog.State.Logical)
- print cell.getNet('a(0)')
-
- if not cell:
- print '[ERROR] Unable to load cell "alu16.vst", aborting .'
- return False
- kw['cell'] = cell
-
- width = 350.0
- height = 400.0
-
- ab = Box(l(0.0)
- , l(0.0)
- , l(width)
- , l(height))
-
- cellGauge = af.getCellGauge()
- spaceMargin = (Cfg.getParamPercentage(
- 'etesian.spaceMargin').asPercentage() + 5) / 100.0
- aspectRatio = Cfg.getParamPercentage(
- 'etesian.aspectRatio').asPercentage() / 100.0
- clocktree.ClockTree.computeAbutmentBox(cell, spaceMargin, aspectRatio,
- cellGauge)
- ab2 = cell.getAbutmentBox()
- print "box", ab, ab.getHeight(), ab.getWidth()
- print "calc box", ab2, ab2.getHeight(), ab2.getWidth()
-
- # height = ab.getHeight()
- # width = ab.getWidth()
-
- UpdateSession.open()
- cell.setAbutmentBox(ab)
-
- for i in range(16):
- if True:
- x = 20.0 * i + 10.0
- y = height
- pin = Pin.create(cell.getNet('a(%d)' % i)
- , 'a(%d).0' % i
- , Pin.Direction.NORTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(x), l(y - 0) # Position.
- , l(2.0), l(2.0) # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- for i in range(16):
- if True:
- pin = Pin.create(cell.getNet('o(%d)' % i)
- , 'o(%d).0' % i
- , Pin.Direction.SOUTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(10.0 * i + 100.0), l(0) # Position.
- , l(2.0), l(2.0) # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- for i in range(16):
- if True:
- net = cell.getNet('b(%d)' % i)
- x = 20.0 * i + 10.0 + 10
- y = height - 0
- # build_downtrace(net, METAL3, x, y+11, y)
- # continue
- pin = Pin.create(net
- , 'b(%d).0' % i
- , Pin.Direction.NORTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(x), l(y) # Position.
- , l(2.0), l(2.0) # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- if False:
- pin = Pin.create(cell.getNet('rst')
- , 'p_reset.0'
- , Pin.Direction.WEST
- , Pin.PlacementStatus.FIXED
- , METAL2
- , l(0.0)
- , l(140.0)
- , l(2.0)
- , l(2.0)
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
- UpdateSession.close()
-
- if True:
- if editor: editor.setCell(cell)
-
- placeAndRoute(cell)
-
- UpdateSession.open()
- blockageNet = cell.getNet('blockagenet')
-
- ab = cell.getAbutmentBox()
- ab.inflate(toDbU(-5.0))
- Pad.create(net, BLOCKAGE2, ab)
- Pad.create(net, BLOCKAGE3, ab)
- Pad.create(net, BLOCKAGE4, ab)
- # Pad.create( net, BLOCKAGE5, ab )
- UpdateSession.close()
-
- if False:
- UpdateSession.open()
- cell.setAbutmentBox(ab)
- for i in range(16):
- if True:
- net = cell.getNet('b(%d)' % i)
- x = 20.0 * i + 10.0 + 10
- y = height - 10
- build_downtrace(net, METAL2, x, y, y + 10)
- UpdateSession.close()
-
- # af.saveCell( cell, CRL.Catalog.State.Views )
- plugins.RSavePlugin.ScriptMain(**kw)
-
-
-# -------------------------------------------------------------------------------
-# alu16()
-
-def alu16(**kw):
- editor = None
- if kw.has_key('editor') and kw['editor']:
- editor = kw['editor']
-
- db = DataBase.getDB()
- print db, dir(db)
- METAL2 = DataBase.getDB().getTechnology().getLayer('METAL2')
- METAL3 = DataBase.getDB().getTechnology().getLayer('METAL3')
-
- cell = af.getCell('add', CRL.Catalog.State.Views)
- cell = af.getCell('sub', CRL.Catalog.State.Views)
- cell = af.getCell('alu16', CRL.Catalog.State.Logical)
- if not cell:
- print '[ERROR] Unable to load cell "alu16.vst", aborting .'
- return False
- kw['cell'] = cell
-
- ab = Box(l(0.0)
- , l(0.0)
- , l(1050.0)
- , l(700.0))
-
- UpdateSession.open()
- cell.setAbutmentBox(ab)
-
- ins = cell.getInstance('subckt_48_add')
- ins.setTransformation(Transformation(toDbU(100.0), toDbU(150.0),
- Transformation.Orientation.ID))
- ins.setPlacementStatus(Instance.PlacementStatus.FIXED)
-
- ins = cell.getInstance('subckt_49_sub')
- ins.setTransformation(Transformation(toDbU(600.0), toDbU(150.0),
- Transformation.Orientation.ID))
- ins.setPlacementStatus(Instance.PlacementStatus.FIXED)
-
- yNorth = cell.getAbutmentBox().getYMax()
-
- for i in range(16):
- Pin.create(cell.getNet('a(%d)' % i)
- , 'a(%d).0' % i
- , Pin.Direction.SOUTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(60.0 * i + 50.0), l(0.0) # Position.
- , l(2.0), l(2.0) # Size.
- )
- Pin.create(cell.getNet('b(%d)' % i)
- , 'b(%d).0' % i
- , Pin.Direction.SOUTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(60.0 * i + 80.0), l(0.0) # Position.
- , l(2.0), l(2.0) # Size.
- )
- Pin.create(cell.getNet('o(%d)' % i)
- , 'o(%d).0' % i
- , Pin.Direction.NORTH
- , Pin.PlacementStatus.FIXED
- , METAL3
- , l(60.0 * i + 50.0), yNorth # Position.
- , l(2.0), l(2.0) # Size.
- )
-
- Pin.create(cell.getNet('rst')
- , 'rst.0'
- , Pin.Direction.WEST
- , Pin.PlacementStatus.FIXED
- , METAL2
- , l(0.0)
- , l(140.0)
- , l(2.0)
- , l(2.0)
- )
- UpdateSession.close()
-
- if editor: editor.setCell(cell)
-
- print "editor", editor, dir(editor)
-
- success = placeAndRoute(cell)
-
- af.saveCell(cell, CRL.Catalog.State.Views)
- plugins.RSavePlugin.ScriptMain(**kw)
-
- return success
-
-
-def ScriptMain(**kw):
- coriolisSetup()
- add(**kw)
- sub(**kw)
- success = alu16(**kw)
- return success
+ result = self.place_and_route()
+
+ with SessionManager():
+ self.create_pads()
+
+ self.save()
+ return result
+
+
+class ALU16(Module):
+
+ def save(self):
+ self.name = self.name + '_r'
+ self.af.saveCell(self.cell, CRL.Catalog.State.Views)
+ super(ALU16, self).save()
+
+ def build(self):
+
+ h_margin = 25.0
+ v_margin = 10.0
+
+ if not self.build_submodules():
+ return False
+
+ # at this point we have the (auto-calculated) submodules' dimensions
+ # in their `ab` properties.
+
+ add, sub = self.submodules
+
+ with SessionManager():
+ self.compute_ab()
+
+ width = self.from_dbu(
+ self.ab.getWidth() + add.ab.getWidth() + sub.ab.getWidth()
+ ) + 4*h_margin
+ height = self.from_dbu(max([
+ self.ab.getHeight(), add.ab.getHeight(), sub.ab.getHeight()
+ ])) + 2*v_margin
+
+ # experiment, over-ride
+ width = 1300
+ height = 370
+
+ self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
+
+ add_wid = self.from_dbu(add.ab.getWidth())
+ sub_ht = self.from_dbu(sub.ab.getHeight())
+ self.place_submodule(add, h_margin, v_margin+add_wid)
+ self.place_submodule(sub, width-sub.ab_width-h_margin+sub_ht-45,
+ v_margin)
+
+ # TODO: replace with some form of lazy evaluation?
+ y_north = self.from_dbu(self.ab.getYMax())
+ for pin_conf in self.north_pins:
+ pin_conf['y'] = y_north
+
+ self.create_pins()
+
+ if self.editor:
+ self.editor.setCell(self.cell)
+
+ # place first (in middle, between two)
+ # this puts all the remaining cells (little ones)
+ # into this (small) space so that they do not go
+ # "all over the place" around the add and sub
+
+ # XXX this doesn't work: box is far too big, covers the entire
+ # area (including "under" the add and sub)
+ self.ab = Box(
+ self.to_dbu((width-self.ab_width)/2 - h_margin),
+ self.to_dbu(v_margin),
+ self.to_dbu((width+self.ab_width)/2 + h_margin),
+ self.to_dbu(height - v_margin)
+ )
+ self.ab = Box(self.to_dbu(450), self.to_dbu(15),
+ self.to_dbu(835), self.to_dbu(370))
+ self.place() # place only
+
+ # then route (globally)
+ # this connects up not just in the remaining (little) cells,
+ # it connects *to add and sub and the outside world as well*
+ self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
+ result = self.route()
+
+ self.save()
+ return result
+
+
+def ScriptMain(editor=None, **kwargs):
+ coriolis_setup()
+
+ add = AddSub(
+ 'add', editor,
+ north_pins=[
+ {'net': 'a({})', 'x': 165.0, 'delta': -10.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 160.0, 'delta': -10.0, 'repeat': BIT_WIDTH},
+ {'net': 'o({})', 'x': 340.0, 'delta': -10.0, 'repeat': BIT_WIDTH},
+ ],
+ south_pins=[
+ ],
+ pads={
+ 'b({})'.format(BIT_WIDTH-1): (
+ 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
+ ),
+ },
+ orientation=Transformation.Orientation.R3,
+ )
+ sub = AddSub(
+ 'sub', editor,
+ north_pins=[
+ {'net': 'a({})', 'x': 180.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 185.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'o({})', 'x': 10.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ ],
+ south_pins=[
+ ],
+ pads={
+ 'b({})'.format(BIT_WIDTH-1): (
+ 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
+ ),
+ },
+ orientation=Transformation.Orientation.R1,
+ )
+
+ alu16 = ALU16(
+ 'alu16', editor, submodules=[add, sub],
+ north_pins=[
+ {'net': 'o({})', 'x': 500.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'op'},
+ ],
+ south_pins=[
+ {'net': 'a({})', 'x': 500.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 700.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ ],
+ west_pins=[
+ {'net': 'rst', 'y': 140.0, 'layer': 'METAL2'},
+ ],
+ )
+ return alu16.build()
if __name__ == '__main__':
- try:
- kw = {}
- success = ScriptMain(**kw)
- shellSuccess = 0
- if not success: shellSuccess = 1
- except ImportError, e:
- showPythonTrace(__file__, e, False)
- sys.exit(1)
- except Exception, e:
- showPythonTrace(__file__, e)
- sys.exit(2)
+ kwargs = {}
+ success = ScriptMain(**kwargs)
+ shellSuccess = 0
+ if not success:
+ shellSuccess = 1
sys.exit(shellSuccess)
-
-