commit
db0adbcc02
|
@ -690,10 +690,10 @@ namespace Anabatic {
|
|||
bool Vertex::isH () const
|
||||
{
|
||||
GCell* gcell = getGCell();
|
||||
if (gcell->isDevice()) return isiHorizontal();
|
||||
else if ((gcell->isHChannel())||(gcell->isHRail())) return true;
|
||||
else if (gcell->isStrut()| gcell->isMatrix() ) return ((gcell->getWidth() > gcell->getHeight())||(gcell->getWidth() == gcell->getHeight()));
|
||||
else return false;
|
||||
if ( gcell->isDevice()) return isiHorizontal();
|
||||
else if ((gcell->isHChannel()) or (gcell->isHRail())) return true;
|
||||
else if ( gcell->isStrut() or gcell->isMatrix()) return ((gcell->getWidth() > gcell->getHeight())||(gcell->getWidth() == gcell->getHeight()));
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ def _routing ():
|
|||
cfg.katana.globalRipupLimit = 5
|
||||
cfg.katana.globalRipupLimit = [1, None]
|
||||
cfg.katana.longGlobalRipupLimit = 5
|
||||
cfg.chip.padCoreSide = 'South'
|
||||
cfg.chip.padCoreSide = 'North'
|
||||
# Plugins setup
|
||||
cfg.clockTree.minimumSide = u(5.04) * 6
|
||||
cfg.clockTree.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2'
|
||||
|
|
|
@ -99,6 +99,10 @@ def _routing():
|
|||
)
|
||||
af.addCellGauge(cg)
|
||||
af.setCellGauge('StdCell3V3Lib')
|
||||
lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 )
|
||||
lg5.setType( CRL.RoutingLayerGauge.PowerSupply )
|
||||
env = af.getEnvironment()
|
||||
env.setRegister( '.*sff.*' )
|
||||
|
||||
# Place & Route setup
|
||||
with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
|
||||
|
@ -162,17 +166,8 @@ def _routing():
|
|||
cfg.katana.globalRipupLimit = 5
|
||||
cfg.katana.globalRipupLimit = [1, None]
|
||||
cfg.katana.longGlobalRipupLimit = 5
|
||||
cfg.chip.padCoreSide = 'South'
|
||||
|
||||
# Plugins setup
|
||||
with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
|
||||
cfg.viewer.minimumSize = 500
|
||||
cfg.viewer.pixelThreshold = 10
|
||||
cfg.chip.block.rails.count = 5
|
||||
cfg.chip.block.rails.hWidth = u(2.68)
|
||||
cfg.chip.block.rails.vWidth = u(2.68)
|
||||
cfg.chip.block.rails.hSpacing = u(0.7)
|
||||
cfg.chip.block.rails.vSpacing = u(0.7)
|
||||
cfg.clockTree.minimumSide = l(600)
|
||||
cfg.clockTree.buffer = 'buf_x1'
|
||||
cfg.clockTree.placerEngine = 'Etesian'
|
||||
|
|
|
@ -27,8 +27,9 @@ def _routing ():
|
|||
cfg.chip.block.rails.vWidth = u(30.0)
|
||||
cfg.chip.block.rails.hSpacing = u( 6.0)
|
||||
cfg.chip.block.rails.vSpacing = u( 6.0)
|
||||
cfg.chip.padCorner = 'gf180mcu_fd_io__cor_5lm'
|
||||
cfg.chip.padSpacers = 'gf180mcu_fd_io__fill10_5lm,gf180mcu_fd_io__fill5_5lm,gf180mcu_fd_io__fill1_5lm'
|
||||
#cfg.chip.padCorner = 'gf180mcu_fd_io__cor'
|
||||
#cfg.chip.padSpacers = 'gf180mcu_fd_io__fill10,gf180mcu_fd_io__fill5,gf180mcu_fd_io__fill1'
|
||||
cfg.chip.padCoreSide = 'North'
|
||||
af = AllianceFramework.get()
|
||||
cg = CellGauge.create( 'LEF.GF_IO_Site'
|
||||
, 'Metal2' # pin layer name.
|
||||
|
@ -57,7 +58,6 @@ def _loadIoLib ( pdkDir ):
|
|||
print( ' o Setup GF180MCU I/O library in {}.'.format( ioLib.getName() ))
|
||||
io.vprint( 1, ' o Setup GF180MCU I/O library in {}.'.format( ioLib.getName() ))
|
||||
cellsDir = pdkDir / 'libraries' / 'gf180mcu_fd_io' / 'latest' / 'cells'
|
||||
print( cellsDir )
|
||||
for lefFile in cellsDir.glob( '*/*_5lm.lef' ):
|
||||
print( lefFile )
|
||||
gdsFile = lefFile.with_suffix( '.gds' )
|
||||
|
@ -65,6 +65,12 @@ def _loadIoLib ( pdkDir ):
|
|||
Gds.setTopCellName( gdsFile.stem[:-4] )
|
||||
Gds.load( ioLib, gdsFile.as_posix(), Gds.Layer_0_IsBoundary|Gds.NoBlockages )
|
||||
LefImport.load( lefFile.as_posix() )
|
||||
# Demote the VDD/VSS nets until we understand how that works.
|
||||
for cell in ioLib.getCells():
|
||||
for net in cell.getNets():
|
||||
if net.getName() in ('VDD', 'VSS'):
|
||||
net.setExternal( False )
|
||||
net.setGlobal( False )
|
||||
af.wrapLibrary( ioLib, 1 )
|
||||
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/dreal.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/sv2v.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/svase.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/surelog.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/yosys.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/yosysnp.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/blif2vst.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/pnr.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/klayout.py
|
||||
|
@ -65,6 +65,7 @@
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/niolib.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/libresocio.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/sky130.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/gf180mcu.py
|
||||
)
|
||||
set ( pyPluginChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/__init__.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/constants.py
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask
|
||||
|
@ -37,6 +38,9 @@ class Clean ( FlowTask ):
|
|||
if filePath.is_file():
|
||||
print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
|
||||
filePath.unlink()
|
||||
elif filePath.is_dir():
|
||||
print( ' - {:<40} [removed (directory)]'.format( filePath.as_posix() ))
|
||||
shutil.rmtree( filePath )
|
||||
else:
|
||||
print( ' - {}'.format( filePath.as_posix() ))
|
||||
if doExtrasClean and len(self.extrasGlobs):
|
||||
|
|
|
@ -24,7 +24,7 @@ class PnR ( FlowTask ):
|
|||
textMode = True
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, targets=[], depends=[], script=None ):
|
||||
def mkRule ( rule, targets=[], depends=[], script=None, topName=None ):
|
||||
"""
|
||||
Creates a new rule instance (``doit`` task).
|
||||
|
||||
|
@ -36,11 +36,12 @@ class PnR ( FlowTask ):
|
|||
:param script: A callable, typically a ``scriptMain()`` function. The only
|
||||
requirement is that it should accept one keyworded argument (``**kw``).
|
||||
"""
|
||||
return PnR( rule, targets, depends, script )
|
||||
return PnR( rule, targets, depends, script, topName )
|
||||
|
||||
def __init__ ( self, rule, targets, depends, script ):
|
||||
def __init__ ( self, rule, targets, depends, script, topName ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.script = script
|
||||
self.topName = topName
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
|
@ -70,8 +71,11 @@ class PnR ( FlowTask ):
|
|||
if self.script and not callable(self.script):
|
||||
e = ErrorMessage( 1, 'PnR.doTask(): "script" argument is *not* callable.' )
|
||||
return TaskFailed( e )
|
||||
kw = {}
|
||||
if self.script:
|
||||
self.script( **{} )
|
||||
if self.topName:
|
||||
kw[ 'loadCell' ] = self.topName
|
||||
self.script( **kw )
|
||||
if not PnR.textMode:
|
||||
# Run in graphic mode.
|
||||
ha = Viewer.HApplication.create( [] )
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
import os.path
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask
|
||||
|
||||
|
||||
def printCommand ( command ):
|
||||
commandBin = command[0]
|
||||
print( commandBin, command[1] )
|
||||
for arg in command[2:]:
|
||||
print( ' '*len(commandBin), arg )
|
||||
|
||||
|
||||
class Surelog ( FlowTask ):
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, depends, top, incdirs=[], libdirs=[], defines=[], options=[], flags=0 ):
|
||||
return Surelog( rule, depends, top, incdirs, libdirs, defines, options, flags )
|
||||
|
||||
def __init__ ( self, rule, depends, top, incdirs, libdirs, defines, options, flags ):
|
||||
self.flags = flags
|
||||
self.top = top
|
||||
self.incdirs = incdirs
|
||||
self.libdirs = libdirs
|
||||
self.defines = defines
|
||||
self.options = options
|
||||
self.success = True
|
||||
targets = FlowTask._normFileList( [ self.top + '.uhdm' ] )
|
||||
depends = FlowTask._normFileList( depends )
|
||||
super().__init__( rule, targets, depends )
|
||||
self.addClean( targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
return '<surelog {} top={}>'.format( self.main, self.top )
|
||||
|
||||
@property
|
||||
def main ( self ):
|
||||
return self.file_depend( 0 )
|
||||
|
||||
def doTask ( self ):
|
||||
from ..helpers.io import ErrorMessage
|
||||
for incdir in self.incdirs:
|
||||
if not Path(incdir).is_dir():
|
||||
e = ErrorMessage( 1, [ 'Surelog.doTask(): Include directory not found "{}"'
|
||||
, '"{}"'.format( incdir ) ] )
|
||||
return TaskFailed( e )
|
||||
command = [ 'surelog', '-parse' ]
|
||||
command += [ ' '.join( self.options ) ]
|
||||
command += [ '-D{}'.format(d) for d in self.defines ]
|
||||
command += [ '-I{}'.format(i) for i in self.incdirs ]
|
||||
for libdir in self.libdirs:
|
||||
command += [ '-L', libdir ]
|
||||
command += [ '-top', self.top ]
|
||||
command += [ depend.as_posix() for depend in self.depends ]
|
||||
printCommand( command )
|
||||
status = subprocess.call( command )
|
||||
if status != 0: return False
|
||||
shutil.move( 'slpp_all/surelog.uhdm', self.file_target(0) )
|
||||
return True
|
||||
|
||||
def create_doit_tasks ( self ):
|
||||
return { 'basename' : self.basename
|
||||
, 'actions' : [ self.doTask ]
|
||||
, 'doc' : 'Run {}.'.format( self )
|
||||
, 'file_dep' : self.file_dep
|
||||
, 'targets' : self.targets
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
import os.path
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from pyosys import libyosys as yosys
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask
|
||||
|
||||
|
@ -19,11 +18,12 @@ class Sv2v ( FlowTask ):
|
|||
FlagLog = 0x00000001
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, targets, depends, top=None, incdirs=[], libdirs=[], defines=[], flags=0 ):
|
||||
def mkRule ( rule, targets, depends, top, incdirs=[], libdirs=[], defines=[], flags=0 ):
|
||||
return Sv2v( rule, targets, depends, top, incdirs, libdirs, defines, flags )
|
||||
|
||||
def __init__ ( self, rule, targets, depends, top, incdirs, libdirs, defines, flags ):
|
||||
self.flags = flags
|
||||
self.top = top
|
||||
self.incdirs = incdirs
|
||||
self.libdirs = libdirs
|
||||
self.defines = defines
|
||||
|
@ -31,10 +31,6 @@ class Sv2v ( FlowTask ):
|
|||
self.success = True
|
||||
targets = FlowTask._normFileList( targets )
|
||||
depends = FlowTask._normFileList( depends )
|
||||
if top is not None:
|
||||
self.top = top
|
||||
else:
|
||||
self.top = depends[0].stem
|
||||
if targets == []:
|
||||
targets.append( self.top + '.v' )
|
||||
#if self.flags & Sv2v.FlagLog:
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import os.path
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from pyosys import libyosys as yosys
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask
|
||||
|
||||
|
@ -19,11 +18,12 @@ class Svase ( FlowTask ):
|
|||
FlagLog = 0x00000001
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, targets, depends, top=None, incdirs=[], libdirs=[], defines=[], svargs=[], flags=0 ):
|
||||
def mkRule ( rule, targets, depends, top, incdirs=[], libdirs=[], defines=[], svargs=[], flags=0 ):
|
||||
return Svase( rule, targets, depends, top, incdirs, libdirs, defines, svargs, flags )
|
||||
|
||||
def __init__ ( self, rule, targets, depends, top, incdirs, libdirs, defines, svargs, flags ):
|
||||
self.flags = flags
|
||||
self.top = top
|
||||
self.svargs = svargs
|
||||
self.incdirs = incdirs
|
||||
self.libdirs = libdirs
|
||||
|
@ -32,15 +32,12 @@ class Svase ( FlowTask ):
|
|||
self.success = True
|
||||
targets = FlowTask._normFileList( targets )
|
||||
depends = FlowTask._normFileList( depends )
|
||||
if top is not None:
|
||||
self.top = top
|
||||
else:
|
||||
self.top = depends[0].stem
|
||||
if targets == []:
|
||||
targets.append( self.top + '.v' )
|
||||
#if self.flags & Svase.FlagLog:
|
||||
# self.log = Path( self.top + '.log' )
|
||||
# targets.append( self.log )
|
||||
targets.append( './slang-args.txt' )
|
||||
super().__init__( rule, targets, depends )
|
||||
self.addClean( targets )
|
||||
|
||||
|
|
|
@ -284,7 +284,6 @@ def setupGf180mcu_c4m ( checkToolkit=None
|
|||
cfg.misc.verboseLevel2 = True
|
||||
cfg.etesian.graphics = 3
|
||||
cfg.etesian.spaceMargin = 0.10
|
||||
cfg.anabatic.topRoutingLayer = 'metal6'
|
||||
cfg.katana.eventsLimit = 4000000
|
||||
af = CRL.AllianceFramework.get()
|
||||
lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 )
|
||||
|
|
|
@ -1,16 +1,27 @@
|
|||
|
||||
import os.path
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask
|
||||
|
||||
usePyYosys = True
|
||||
try:
|
||||
from pyosys import libyosys as yosys
|
||||
except:
|
||||
usePyYosys = False
|
||||
|
||||
|
||||
class BadLiberty ( Exception ): pass
|
||||
|
||||
|
||||
class Yosys ( FlowTask ):
|
||||
|
||||
_liberty = None
|
||||
FlagLog = 0x00000001
|
||||
FlagQuiet = 0x00000002
|
||||
FlagSystemVerilog = 0x00000004
|
||||
_liberty = None
|
||||
|
||||
@staticmethod
|
||||
def setLiberty ( liberty ):
|
||||
|
@ -25,20 +36,58 @@ class Yosys ( FlowTask ):
|
|||
Yosys._liberty = liberty
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, depends, top=None, blackboxes=[], flattens=[] ):
|
||||
return Yosys( rule, depends, top, blackboxes, flattens )
|
||||
def mkRule ( rule
|
||||
, depends
|
||||
, top =None
|
||||
, blackboxes=[]
|
||||
, flattens =[]
|
||||
, svOptions =None
|
||||
, svDefines =None
|
||||
, svIncdirs =None
|
||||
, svLibdirs =None
|
||||
, script =[]
|
||||
, flags =0 ):
|
||||
return Yosys( rule
|
||||
, depends
|
||||
, top
|
||||
, blackboxes
|
||||
, flattens
|
||||
, svOptions
|
||||
, svDefines
|
||||
, svIncdirs
|
||||
, svLibdirs
|
||||
, script
|
||||
, flags )
|
||||
|
||||
def __init__ ( self, rule, depends, top, blackboxes, flattens ):
|
||||
def __init__ ( self, rule
|
||||
, depends
|
||||
, top
|
||||
, blackboxes
|
||||
, flattens
|
||||
, svOptions
|
||||
, svDefines
|
||||
, svIncdirs
|
||||
, svLibdirs
|
||||
, script
|
||||
, flags ):
|
||||
super().__init__( rule, [], depends )
|
||||
self.success = True
|
||||
self.blackboxes = blackboxes
|
||||
self.flattens = flattens
|
||||
self.depends += blackboxes
|
||||
self.svOptions = svOptions
|
||||
self.svDefines = svDefines
|
||||
self.svIncdirs = svIncdirs
|
||||
self.svLibdirs = svLibdirs
|
||||
self.flags = flags
|
||||
self.script = script
|
||||
self.success = True
|
||||
if top is not None:
|
||||
self.top = top
|
||||
else:
|
||||
self.top = self.main.stem
|
||||
self.targets = [ Path( self.top + '.blif') ]
|
||||
if not usePyYosys:
|
||||
self.targets.append( Path( self.top + '.ys' ))
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
|
@ -53,11 +102,6 @@ class Yosys ( FlowTask ):
|
|||
def main ( self ):
|
||||
return self.file_depend( 0 )
|
||||
|
||||
def _run_pass ( self, command ):
|
||||
from pyosys import libyosys as yosys
|
||||
if self.success is not True: return
|
||||
yosys.run_pass( command, self.tool )
|
||||
|
||||
def _loadDesign ( self, design ):
|
||||
from ..helpers.io import ErrorMessage
|
||||
if self.success is not True: return
|
||||
|
@ -66,13 +110,49 @@ class Yosys ( FlowTask ):
|
|||
self.success = TaskFailed( e )
|
||||
return
|
||||
design = Path( design )
|
||||
if design.suffix == '.v' : self._run_pass( 'read_verilog -sv {}'.format( design.as_posix() ))
|
||||
elif design.suffix == '.il': self._run_pass( 'read_ilang {}'.format( design.as_posix() ))
|
||||
if design.suffix == '.v' :
|
||||
self.script.append( 'read_verilog -sv {}'.format( design.as_posix() ))
|
||||
elif design.suffix == '.il' : self.script.append( 'read_ilang {}'.format( design.as_posix() ))
|
||||
elif design.suffix == '.uhdm':
|
||||
self.script.append( 'plugin -i systemverilog' )
|
||||
self.script.append( 'read_uhdm {}'.format( design.as_posix() ))
|
||||
else:
|
||||
e = ErrorMessage( 1, 'Yosys._loadDesign(): Unsupported input format for "{}".'.format( design ))
|
||||
self.success = TaskFailed( e )
|
||||
return
|
||||
|
||||
def _loadSVDesign ( self ):
|
||||
from ..helpers.io import ErrorMessage
|
||||
if self.success is not True: return
|
||||
self.script.append( 'plugin -i systemverilog' )
|
||||
svFileArgs = ''
|
||||
for svFile in self.depends:
|
||||
if not isinstance(svFile,Path):
|
||||
svFile = Path( svFile )
|
||||
if not svFile.is_file():
|
||||
print( '[WARNING] Can\'t find SV file "{}".'.format( svFile.as_posix() ))
|
||||
continue
|
||||
svFileArgs += ' {}'.format( svFile.as_posix() )
|
||||
defineArgs = ''
|
||||
for define in self.svDefines:
|
||||
defineArgs += ' -D{}'.format( define )
|
||||
includeArgs = ''
|
||||
for incdir in self.svIncdirs:
|
||||
includeArgs += ' -I{}'.format( incdir )
|
||||
libArgs = ''
|
||||
for libdir in self.svLibdirs:
|
||||
libArgs += ' -L {}'.format( libdir )
|
||||
options = ' '.join( self.svOptions )
|
||||
scriptArgs = { 'options' :options
|
||||
, 'defines' :defineArgs
|
||||
, 'includes' :includeArgs
|
||||
, 'libraries':libArgs
|
||||
, 'svFiles' :svFileArgs
|
||||
, 'top' : self.top }
|
||||
self.script.append( 'read_systemverilog {options} -top {top} {defines} {includes} {libraries} {svFiles}' \
|
||||
.format( **scriptArgs ))
|
||||
|
||||
|
||||
def _loadBlackboxes ( self ):
|
||||
if self.success is not True: return
|
||||
for blackbox in self.blackboxes:
|
||||
|
@ -81,11 +161,34 @@ class Yosys ( FlowTask ):
|
|||
def _doFlattens ( self ):
|
||||
if self.success is not True: return
|
||||
flattens = ' '.join( self.flattens )
|
||||
self._run_pass( 'flatten {}\n'.format( flattens ))
|
||||
self._run_pass( 'hierarchy -top {}\n'.format( self.top ))
|
||||
self.script.append( 'flatten {}'.format( flattens ))
|
||||
self.script.append( 'hierarchy -top {}'.format( self.top ))
|
||||
|
||||
def _runScript ( self ):
|
||||
from ..helpers.io import ErrorMessage
|
||||
if usePyYosys:
|
||||
tool = yosys.Design()
|
||||
for command in self.script:
|
||||
yosys.run_pass( command, tool )
|
||||
|
||||
if shutil.which( 'yosys' ): command = [ 'yosys' ]
|
||||
elif shutil.which( 'yowasp-yosys' ): command = [ 'yowasp-yosys' ]
|
||||
else:
|
||||
e = ErrorMessage( 1, [ 'Yosys._runScript(): Neither "yosys" nor "yowasp-yosys" has been found' ] )
|
||||
self.success = TaskFailed( e )
|
||||
return
|
||||
ysFile = self.targets[-1].as_posix()
|
||||
with open( ysFile, 'w' ) as ysFd:
|
||||
ysFd.write( '\n'.join( self.script ).format( liberty =str(self.liberty)
|
||||
, cellname=self.main.stem
|
||||
, top =self.top ))
|
||||
if self.flags & Yosys.FlagQuiet: command += [ '-q' ]
|
||||
if self.flags & Yosys.FlagLog: command += [ '-l', self.log.as_posix() ]
|
||||
command += [ '-s', ysFile ]
|
||||
status = subprocess.call( command )
|
||||
self.success = (status == 0)
|
||||
|
||||
def doTask ( self ):
|
||||
from pyosys import libyosys as yosys
|
||||
from ..helpers.io import ErrorMessage
|
||||
if self.liberty is None:
|
||||
e = ErrorMessage( 1, [ 'Yosys.doTask(): "liberty" has not been set' ] )
|
||||
|
@ -94,18 +197,21 @@ class Yosys ( FlowTask ):
|
|||
e = ErrorMessage( 1, [ 'Yosys.doTask(): File not found "{}"'
|
||||
, '"{}"'.format( self.liberty.as_posix() ) ] )
|
||||
return TaskFailed( e )
|
||||
#print( 'Yosys.doTask() on "{}"'.format( self.design ))
|
||||
self.tool = yosys.Design()
|
||||
#print( 'Yosys.doTask() on "{}"'.format( self.main ))
|
||||
self._loadBlackboxes()
|
||||
self._loadDesign( self.main )
|
||||
self._run_pass( 'hierarchy -check -top {}'.format( self.top ))
|
||||
self._run_pass( 'synth -top {}'.format( self.top ))
|
||||
if self.flags & Yosys.FlagSystemVerilog:
|
||||
self._loadSVDesign()
|
||||
else:
|
||||
self._loadDesign( self.main )
|
||||
self.script.append( 'hierarchy -check -top {}'.format( self.top ))
|
||||
self.script.append( 'synth -top {}'.format( self.top ))
|
||||
self._doFlattens()
|
||||
self._run_pass( 'memory' )
|
||||
self._run_pass( 'dfflibmap -liberty {}'.format( self.liberty.as_posix() ))
|
||||
self._run_pass( 'abc -liberty {}'.format( self.liberty.as_posix() ))
|
||||
self._run_pass( 'clean' )
|
||||
self._run_pass( 'write_blif {}'.format( self.targets[0] ))
|
||||
self.script.append( 'memory' )
|
||||
self.script.append( 'dfflibmap -liberty {}'.format( self.liberty.as_posix() ))
|
||||
self.script.append( 'abc -liberty {}'.format( self.liberty.as_posix() ))
|
||||
self.script.append( 'clean')
|
||||
self.script.append( 'write_blif {}'.format( self.targets[0] ))
|
||||
self._runScript()
|
||||
return self.success
|
||||
|
||||
def create_doit_tasks ( self ):
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import os.path
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from pyosys import libyosys as yosys
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask
|
||||
|
||||
|
|
|
@ -484,6 +484,19 @@ class Block ( object ):
|
|||
trace( 550, '\tCORE AB is {}\n'.format(self.conf.cell.getAbutmentBox()) )
|
||||
if self.conf.isCoreBlock:
|
||||
self.conf.setupICore()
|
||||
minHCorona = self.conf.minHCorona
|
||||
minVCorona = self.conf.minVCorona
|
||||
innerBb = Box( self.conf.coreAb )
|
||||
innerBb.inflate( minHCorona, minVCorona )
|
||||
coronaAb = self.conf.corona.getAbutmentBox()
|
||||
if innerBb.getWidth() > coronaAb.getWidth():
|
||||
raise ErrorMessage( 1, 'Core is too wide to fit into the corona, needs {} but only has {}.' \
|
||||
.format( DbU.getValueString(innerBb .getWidth())
|
||||
, DbU.getValueString(coronaAb.getWidth()) ) )
|
||||
if innerBb.getHeight() > coronaAb.getHeight():
|
||||
raise ErrorMessage( 1, 'Core is too tall to fit into the corona, needs {} but only has {}.' \
|
||||
.format( DbU.getValueString(innerBb .getHeight())
|
||||
, DbU.getValueString(coronaAb.getHeight()) ) )
|
||||
self.conf.setRoutingBb( self.conf.cellPnR.getAbutmentBox() )
|
||||
|
||||
def flattenNets ( self ):
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import sys
|
||||
import re
|
||||
import os.path
|
||||
import collections
|
||||
from operator import itemgetter
|
||||
from ... import Cfg
|
||||
from ...Hurricane import DataBase, Breakpoint, DbU, Box, Transformation, \
|
||||
|
@ -1449,7 +1450,22 @@ class BlockConf ( GaugeConf ):
|
|||
for ioPinSpec in self.ioPinsArg:
|
||||
self.ioPins.append( IoPin( *ioPinSpec ) )
|
||||
for line in range(len(self.ioPadsArg)):
|
||||
self.chipConf.addIoPad( self.ioPadsArg[line], line )
|
||||
bits = []
|
||||
if not isinstance(self.ioPadsArg[line][-1],str) \
|
||||
and isinstance(self.ioPadsArg[line][-1],collections.Iterable):
|
||||
bits = self.ioPadsArg[line][-1]
|
||||
elif isinstance(self.ioPadsArg[line][-1],int):
|
||||
bits = range( self.ioPadsArg[line][-1] )
|
||||
if bits != []:
|
||||
for bit in bits:
|
||||
spec = [ self.ioPadsArg[line][0]
|
||||
, self.ioPadsArg[line][1]
|
||||
]
|
||||
for i in range( 2, len(self.ioPadsArg[line])-1 ):
|
||||
spec.append( self.ioPadsArg[line][i].format( bit ))
|
||||
self.chipConf.addIoPad( spec, line )
|
||||
else:
|
||||
self.chipConf.addIoPad( self.ioPadsArg[line], line )
|
||||
trace( 550, ',-' )
|
||||
|
||||
@property
|
||||
|
|
|
@ -99,11 +99,14 @@ class Chip ( Block ):
|
|||
trace( 550, '\tminHCorona={}\n'.format(DbU.getValueString( minHCorona )))
|
||||
trace( 550, '\tminVCorona={}\n'.format(DbU.getValueString( minVCorona )))
|
||||
else:
|
||||
print( ' - Using harness.' )
|
||||
self.padsCorona = harnessPads.Corona( self )
|
||||
self.padsCorona.doLayout()
|
||||
innerBb = Box( self.conf.coreAb )
|
||||
innerBb.inflate( minHCorona, minVCorona )
|
||||
coronaAb = self.conf.corona.getAbutmentBox()
|
||||
trace( 550, '\tinnerBb:{}\n'.format(innerBb) )
|
||||
trace( 550, '\tcoronaAb:{}\n'.format(coronaAb) )
|
||||
if innerBb.getWidth() > coronaAb.getWidth():
|
||||
raise ErrorMessage( 1, 'Core is too wide to fit into the corona, needs {} but only has {}.' \
|
||||
.format( DbU.getValueString(innerBb .getWidth())
|
||||
|
|
|
@ -693,11 +693,11 @@ class Corona ( object ):
|
|||
if plug.getMasterNet().isGlobal():
|
||||
net = self.conf.cell.getNet( plug.getMasterNet().getName() )
|
||||
if not net:
|
||||
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is not connected and there is no global net (in pad \"%s").' \
|
||||
% plug.getMasterNet().getName(), padCell.getName() )
|
||||
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "{}" is not connected and there is no global net (in pad "{}").' \
|
||||
.format( plug.getMasterNet().getName(), padCell.getName() ))
|
||||
else:
|
||||
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \
|
||||
% plug.getMasterNet().getName(), padCell.getName() )
|
||||
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "{}" is neither connected nor global (in pad "{}").' \
|
||||
.format( plug.getMasterNet().getName(), padCell.getName() ))
|
||||
if net:
|
||||
self.padRails.append( ( net
|
||||
, component.getLayer()
|
||||
|
|
|
@ -375,6 +375,7 @@ class IoPad ( object ):
|
|||
or self.nets[0].chipExtNetName.startswith('io_in') \
|
||||
or self.nets[0].chipExtNetName.startswith('io_out')
|
||||
if hasEnable:
|
||||
trace( 550, '\tself.nets = {}\n'.format( self.nets ))
|
||||
if len(self.nets) < 2:
|
||||
enableNet = self.coreToChip.newEnableForNet( self.nets[0] )
|
||||
self.nets.append( self.coreToChip.getIoNet( enableNet ) )
|
||||
|
@ -387,6 +388,7 @@ class IoPad ( object ):
|
|||
connexions.append( ( self.nets[0].chipIntNet , padInfo.inputNet ) )
|
||||
connexions.append( ( self.coreToChip.newDummyNet(), padInfo.outputNet ) )
|
||||
if hasEnable:
|
||||
trace( 550, '\tenable Pad={} <-> {}\n'.format( padInfo.enableNet, self.nets[1].chipIntNet ))
|
||||
connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) )
|
||||
elif (self.direction == IoPad.TRI_OUT) and (len(self.nets) < 2):
|
||||
self.nets[0].setFlags( IoNet.DoExtNet )
|
||||
|
@ -415,6 +417,11 @@ class IoPad ( object ):
|
|||
connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) )
|
||||
connexions.append( ( self.nets[1].chipIntNet, padInfo.outputNet ) )
|
||||
connexions.append( ( self.nets[2].chipIntNet, padInfo.enableNet ) )
|
||||
for controlInfo in padInfo.controlNets:
|
||||
controlNet = self.coreToChip.newControlForPad( self.ioPadConf, controlInfo )
|
||||
self.nets.append( self.coreToChip.getIoNet( controlNet ) )
|
||||
self.nets[-1].buildNets()
|
||||
connexions.append( ( self.nets[-1].chipIntNet, controlInfo.name ) )
|
||||
if not self.coreToChip.useHarness():
|
||||
self.pads.append( Instance.create( self.coreToChip.chip
|
||||
, self.padInstanceName
|
||||
|
@ -448,13 +455,21 @@ class CoreToChip ( object ):
|
|||
to the core actually bearing information.
|
||||
"""
|
||||
|
||||
class IoControlInfo ( object ):
|
||||
|
||||
def __init__ ( self, name, defaultState ):
|
||||
self.name = name
|
||||
self.defaultState = defaultState
|
||||
pass
|
||||
|
||||
class IoPadInfo ( object ):
|
||||
|
||||
def __init__ ( self, flags, padName, padNet, coreNets ):
|
||||
self.flags = flags
|
||||
self.name = padName
|
||||
self.padNet = padNet
|
||||
self.coreNets = coreNets
|
||||
def __init__ ( self, flags, padName, padNet, coreNets, controlNets=[] ):
|
||||
self.flags = flags
|
||||
self.name = padName
|
||||
self.padNet = padNet
|
||||
self.coreNets = coreNets
|
||||
self.controlNets = [ CoreToChip.IoControlInfo( net[0], net[1] ) for net in controlNets ]
|
||||
return
|
||||
|
||||
@property
|
||||
|
@ -508,6 +523,10 @@ class CoreToChip ( object ):
|
|||
if not masterNetO: masterNet = instance.getMasterCell().getNet( chipNet.getName() )
|
||||
elif isinstance(masterNetO,Net): masterNet = masterNetO
|
||||
else: masterNet = instance.getMasterCell().getNet( masterNetO )
|
||||
if not masterNet:
|
||||
raise ErrorMessage( 1, [ 'CoreToChip._connect(): No net "{}" in cell "{}".' \
|
||||
.format( masterNetO, instance.getMasterCell().getName() )
|
||||
] )
|
||||
instance.getPlug( masterNet ).setNet( chipNet )
|
||||
return
|
||||
|
||||
|
@ -571,6 +590,22 @@ class CoreToChip ( object ):
|
|||
self.dummyNetCount += 1
|
||||
return dummy
|
||||
|
||||
def newControlNet ( self, controlName, constantType ):
|
||||
"""
|
||||
Create a new control signal, in *core* cell, to control the associated I/O pad.
|
||||
The control signal is tied to a constant value, either zero or one.
|
||||
|
||||
:param controlName: The name of the control net *in the core cell*.
|
||||
:param constantType: Whether the control signal is set to zero or one.
|
||||
"""
|
||||
instance = self.conf.constantsConf.createInstance( self.core, constantType )
|
||||
control = Net.create( self.core, controlName )
|
||||
control.setExternal ( True )
|
||||
control.setDirection( Net.Direction.OUT )
|
||||
getPlugByName( instance, self.conf.constantsConf.output(constantType) ).setNet( control )
|
||||
self.conf.addClonedCell( self.conf.core )
|
||||
return control
|
||||
|
||||
def newEnableForNet ( self, ioNet ):
|
||||
"""
|
||||
Create a new enable signal, in *core* cell, to control the associated I/O pad.
|
||||
|
@ -582,13 +617,16 @@ class CoreToChip ( object ):
|
|||
else:
|
||||
raise ErrorMessage( 2, 'CoreToChip.newEnableForNet(): Net "{}" is neither IN nor OUT.' \
|
||||
.format(ioNet.coreNet.getName()) )
|
||||
instance = self.conf.constantsConf.createInstance( self.core, constantType )
|
||||
enable = Net.create( self.core, ioNet.enableNetName )
|
||||
enable.setExternal ( True )
|
||||
enable.setDirection( Net.Direction.OUT )
|
||||
getPlugByName( instance, self.conf.constantsConf.output(constantType) ).setNet( enable )
|
||||
self.conf.addClonedCell( self.conf.core )
|
||||
return enable
|
||||
return self.newControlNet( ioNet.enableNetName, constantType )
|
||||
|
||||
def newControlForPad ( self, ioPadInfo, ioControlInfo ):
|
||||
"""
|
||||
Create a new control signal, in *core* cell, to control the associated I/O pad.
|
||||
This is to be used for all I/O pads controls nets, save the "enable" signal.
|
||||
"""
|
||||
constantType = ConstantsConf.ONE if ioControlInfo.defaultState else ConstantsConf.ZERO
|
||||
controlNetName = '{}_{}'.format( ioPadInfo.instanceName, ioControlInfo.name )
|
||||
return self.newControlNet( controlNetName, constantType )
|
||||
|
||||
def getIoNet ( self, coreNet ):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2020-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | C u m u l u s - P y t h o n T o o l s |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./plugins/core2chip/libresocio.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
"""
|
||||
Core2Chip configuration for the Global Foudries 180nm I/O pad library (GF180MCU).
|
||||
"""
|
||||
|
||||
import sys
|
||||
import re
|
||||
from ...Hurricane import DbU, DataBase, UpdateSession, Breakpoint, \
|
||||
Transformation , Instance , Net
|
||||
from ...CRL import Catalog, AllianceFramework
|
||||
from ...helpers import trace
|
||||
from ...helpers.io import ErrorMessage, WarningMessage
|
||||
from ...helpers.overlay import CfgCache
|
||||
from .core2chip import CoreToChip as BaseCoreToChip, IoNet, IoPad
|
||||
|
||||
|
||||
class CoreToChip ( BaseCoreToChip ):
|
||||
"""
|
||||
Provide pad-specific part for GF180MCU I/O pads (works in real mode).
|
||||
"""
|
||||
rePadType = re.compile(r'(?P<type>.+)_(?P<index>[\d]+)$')
|
||||
|
||||
def __init__ ( self, core ):
|
||||
with CfgCache() as cfg:
|
||||
cfg.chip.useAbstractPads = False
|
||||
self.ioPadNames = { 'in' :'gf180mcu_fd_io__in_s'
|
||||
, 'bidir' :'gf180mcu_fd_io__bi_t'
|
||||
, 'analog' :'gf180mcu_fd_io__asig_5p0'
|
||||
, 'vdd' :'gf180mcu_fd_io__dvdd'
|
||||
, 'vss' :'gf180mcu_fd_io__dvss'
|
||||
, 'corner' :'gf180mcu_fd_io__cor'
|
||||
, 'spacer1' :'gf180mcu_fd_io__fill1'
|
||||
, 'spacer5' :'gf180mcu_fd_io__fill5'
|
||||
, 'spacer10' :'gf180mcu_fd_io__fill10'
|
||||
}
|
||||
BaseCoreToChip.__init__ ( self, core )
|
||||
self.ringNetNames = { 'DVDD' : None
|
||||
, 'DVSS' : None
|
||||
#, 'VDD' : None
|
||||
#, 'VSS' : None
|
||||
}
|
||||
self.ioPadInfos = [ BaseCoreToChip.IoPadInfo( IoPad.IN
|
||||
, self.ioPadNames['in']
|
||||
, 'PAD', ['Y'], [ ( 'PU' , False )
|
||||
, ( 'PD' , False )
|
||||
] )
|
||||
, BaseCoreToChip.IoPadInfo( IoPad.BIDIR
|
||||
, self.ioPadNames['bidir']
|
||||
, 'PAD', ['A', 'Y', 'OE'], [ ( 'SL' , True )
|
||||
, ( 'CS' , True )
|
||||
, ( 'PU' , False )
|
||||
, ( 'PD' , False )
|
||||
, ( 'PDRV0', False )
|
||||
, ( 'PDRV1', False )
|
||||
, ( 'IE' , True )
|
||||
] )
|
||||
, BaseCoreToChip.IoPadInfo( IoPad.ANALOG
|
||||
, self.ioPadNames['analog']
|
||||
, 'ASIG5V', ['asig5v'] )
|
||||
, BaseCoreToChip.IoPadInfo( IoPad.CORNER
|
||||
, self.ioPadNames['corner']
|
||||
, None, [] )
|
||||
, BaseCoreToChip.IoPadInfo( IoPad.FILLER
|
||||
, self.ioPadNames['spacer1']
|
||||
, None, [] )
|
||||
, BaseCoreToChip.IoPadInfo( IoPad.FILLER
|
||||
, self.ioPadNames['spacer5']
|
||||
, None, [] )
|
||||
, BaseCoreToChip.IoPadInfo( IoPad.FILLER
|
||||
, self.ioPadNames['spacer10']
|
||||
, None, [] )
|
||||
]
|
||||
self.cornerCount = 0
|
||||
self.spacerCount = 0
|
||||
self.padSpacers = []
|
||||
self._getPadLib()
|
||||
return
|
||||
|
||||
def _getPadLib ( self ):
|
||||
"""
|
||||
Check that the I/O pad library is present and pre-load the spacer cells.
|
||||
"""
|
||||
def _cmpPad ( pad ):
|
||||
"""Used to sort I/O pads by decreasing width."""
|
||||
return pad.getAbutmentBox().getWidth()
|
||||
|
||||
self.padLib = AllianceFramework.get().getLibrary( "iolib" )
|
||||
if not self.padLib:
|
||||
message = [ 'CoreToChip.libresocio._getPadLib(): Unable to find Alliance "iolib" library' ]
|
||||
raise ErrorMessage( 1, message )
|
||||
for ioPadInfo in self.ioPadInfos:
|
||||
if ioPadInfo.flags & IoPad.FILLER:
|
||||
spacerCell = self.padLib.getCell( ioPadInfo.name )
|
||||
if spacerCell: self.padSpacers.append( spacerCell )
|
||||
else:
|
||||
raise ErrorMessage( 1, 'CoreToChip.gf180mcu._getPadLib(): Missing spacer cell "{}"'.format(spacerName) )
|
||||
self.padSpacers = sorted( self.padSpacers, key=_cmpPad, reverse=True )
|
||||
|
||||
def getNetType ( self, netName ):
|
||||
if netName.lower().startswith('vss') or netName.lower().startswith('dvss'): return Net.Type.GROUND
|
||||
if netName.lower().startswith('vdd') or netName.lower().startswith('dvdd'): return Net.Type.POWER
|
||||
return Net.Type.LOGICAL
|
||||
|
||||
def isGlobal ( self, netName ):
|
||||
if netName in self.ringNetNames: return True
|
||||
return False
|
||||
|
||||
def getCell ( self, masterCellName ):
|
||||
#cell = self.padLib.getCell( masterCellName )
|
||||
cell = AllianceFramework.get().getCell( masterCellName, Catalog.State.Views )
|
||||
if not cell:
|
||||
raise ErrorMessage( 1, 'libresocio.getCell(): I/O pad library "%s" does not contain cell named "%s"' \
|
||||
% (self.padLib.getName(),masterCellName) )
|
||||
return cell
|
||||
|
||||
def _buildAllGroundPads ( self, ioPadConf ):
|
||||
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
|
||||
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
|
||||
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName )
|
||||
padNet = self.chip .getNet( ioPadConf.padSupplyNetName )
|
||||
if not coronaNet:
|
||||
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
|
||||
coronaNet.setExternal( True )
|
||||
coronaNet.setGlobal ( True )
|
||||
coronaNet.setType ( Net.Type.GROUND )
|
||||
self.icore.getPlug( coreNet ).setNet( coronaNet )
|
||||
if not chipNet:
|
||||
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
|
||||
chipNet.setExternal( True )
|
||||
chipNet.setType ( Net.Type.GROUND )
|
||||
if not padNet:
|
||||
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
|
||||
padNet.setExternal( True )
|
||||
padNet.setType ( Net.Type.GROUND )
|
||||
coronaPlug = self.icorona.getPlug( coronaNet )
|
||||
if not coronaPlug.getNet():
|
||||
coronaPlug.setNet( chipNet )
|
||||
self.ringNetNames['DVSS' ] = chipNet
|
||||
#self.ringNetNames['VSS' ] = padNet
|
||||
ioPadConf.pads.append( Instance.create( self.chip
|
||||
, 'p_iovss_{}'.format(ioPadConf.index)
|
||||
, self.getCell(self.ioPadNames['vss']) ) )
|
||||
#self._connect( ioPadConf.pads[0], chipNet, 'VSS' )
|
||||
self._connect( ioPadConf.pads[0], padNet , 'DVSS' )
|
||||
self.groundPadCount += 1
|
||||
self.chipPads += ioPadConf.pads
|
||||
|
||||
def _buildAllPowerPads ( self, ioPadConf ):
|
||||
trace( 550, ',+', '\tgf180mcu.CoreToChip()\n' )
|
||||
trace( 550, '\tcoreSupplyNetName="{}"\n'.format( ioPadConf.coreSupplyNetName ))
|
||||
trace( 550, '\tpadSupplyNetName ="{}"\n'.format( ioPadConf.padSupplyNetName ))
|
||||
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
|
||||
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
|
||||
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName )
|
||||
padNet = self.chip .getNet( ioPadConf.padSupplyNetName )
|
||||
if not coronaNet:
|
||||
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
|
||||
coronaNet.setExternal( True )
|
||||
coronaNet.setGlobal ( True )
|
||||
coronaNet.setType ( Net.Type.POWER )
|
||||
self.icore.getPlug( coreNet ).setNet( coronaNet )
|
||||
if not chipNet:
|
||||
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
|
||||
chipNet.setExternal( True )
|
||||
chipNet.setType ( Net.Type.POWER )
|
||||
self.icorona.getPlug( coronaNet ).setNet( chipNet )
|
||||
trace( 550, '\tchipNet ="{}"\n'.format( chipNet ))
|
||||
if not padNet:
|
||||
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
|
||||
padNet.setExternal( True )
|
||||
padNet.setType ( Net.Type.POWER )
|
||||
self.ringNetNames['DVDD'] = chipNet
|
||||
#self.ringNetNames['VDD'] = padNet
|
||||
trace( 550, '\tpadNet ="{}"\n'.format( padNet ))
|
||||
ioPadConf.pads.append( Instance.create( self.chip
|
||||
, 'p_iovdd_{}'.format(ioPadConf.index)
|
||||
, self.getCell(self.ioPadNames['vdd']) ) )
|
||||
#self._connect( ioPadConf.pads[0], chipNet, 'VDD' )
|
||||
self._connect( ioPadConf.pads[0], padNet , 'DVDD' )
|
||||
self.powerPadCount += 1
|
||||
self.chipPads += ioPadConf.pads
|
||||
trace( 550, '-,' )
|
||||
|
||||
def _buildClockPads ( self, ioPadConf ):
|
||||
"""For "GF180MCU" there is no specialized clock I/O pad. So do nothing."""
|
||||
pass
|
||||
|
||||
def _connectClocks ( self ):
|
||||
"""For "GF180MCU" there is no pad internal clock ring. So do nothing."""
|
||||
pass
|
||||
|
||||
def hasCornerCell ( self ):
|
||||
"""Overload of CoreToChip, YES we have dedicated corner cells."""
|
||||
return True
|
||||
|
||||
def hasFillerCells ( self ):
|
||||
"""Overload of CoreToChip, YES we have dedicated filler cells."""
|
||||
return True
|
||||
|
||||
def getCornerCell ( self ):
|
||||
"""Return the model of corner cell."""
|
||||
return self.getCell( self.ioPadNames['corner'] )
|
||||
|
||||
def createSpacer ( self, gapWidth ):
|
||||
"""Return a new instance of spacer cell."""
|
||||
spacerCell = None
|
||||
for candidate in self.padSpacers:
|
||||
if gapWidth >= candidate.getAbutmentBox().getWidth():
|
||||
spacerCell = candidate
|
||||
break
|
||||
if not spacerCell:
|
||||
return None
|
||||
spacer = Instance.create( self.chip
|
||||
, 'pad_spacer_{}'.format( self.spacerCount )
|
||||
, spacerCell )
|
||||
self.spacerCount += 1
|
||||
#self._connect( spacer, self.ringNetNames['vddring'], 'vddring' )
|
||||
self._connect( spacer, self.ringNetNames['DVDD'], 'DVDD' )
|
||||
#self._connect( spacer, self.ringNetNames['gndring'], 'gndring' )
|
||||
self._connect( spacer, self.ringNetNames['DVSS'], 'DVSS' )
|
||||
return spacer
|
||||
|
||||
def createCorner ( self, instanceName=None ):
|
||||
"""Return a new instance of corner cell."""
|
||||
if instanceName is None:
|
||||
instanceName = 'pad_corner_{}'.format( self.cornerCount )
|
||||
corner = Instance.create( self.chip, instanceName, self.getCornerCell() )
|
||||
self.cornerCount += 1
|
||||
self._connect( corner, self.ringNetNames['DVDD'], 'DVDD' )
|
||||
#self._connect( corner, self.ringNetNames['vddcore'], 'vddcore' )
|
||||
self._connect( corner, self.ringNetNames['DVSS'], 'DVSS' )
|
||||
#self._connect( corner, self.ringNetNames['gndcore'], 'gndcore' )
|
||||
return corner
|
|
@ -120,7 +120,7 @@ Contact::Contact(Net* net, const Layer* layer, DbU::Unit x, DbU::Unit y, DbU::Un
|
|||
throw Error("Contact::Contact(): Can't create " + _TName("Contact") + ", NULL layer.");
|
||||
|
||||
const BasicLayer* basicLayer = dynamic_cast<const BasicLayer*>( layer );
|
||||
if (not basicLayer or basicLayer->getMaterial() != BasicLayer::Material::cut) return;
|
||||
if (not basicLayer or (basicLayer->getMaterial() != BasicLayer::Material::cut)) return;
|
||||
if ( _width < _layer->getMinimalSize() ) _width = _layer->getMinimalSize();
|
||||
if ( _height < _layer->getMinimalSize() ) _height = _layer->getMinimalSize();
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ Contact::Contact(Net* net, Component* anchor, const Layer* layer, DbU::Unit dx,
|
|||
_anchorHook.attach(anchor->getBodyHook());
|
||||
|
||||
const BasicLayer* basicLayer = dynamic_cast<const BasicLayer*>( layer );
|
||||
if (not basicLayer or basicLayer->getMaterial() != BasicLayer::Material::cut) return;
|
||||
if (not basicLayer or (basicLayer->getMaterial() != BasicLayer::Material::cut)) return;
|
||||
if ( _width < _layer->getMinimalSize() ) _width = _layer->getMinimalSize();
|
||||
if ( _height < _layer->getMinimalSize() ) _height = _layer->getMinimalSize();
|
||||
}
|
||||
|
@ -180,29 +180,33 @@ Contact* Contact::create(Component* anchor, const Layer* layer, DbU::Unit dx, Db
|
|||
// *************************
|
||||
{
|
||||
DbU::Unit twoGrid = DbU::fromGrid( 2 );
|
||||
DbU::Unit minSize = _layer->getMinimalSize();
|
||||
bool rvalue = true;
|
||||
if (_layer->isSymbolic()) {
|
||||
if (not _width ) _width = _layer->getMinimalSize();
|
||||
if (not _height) _height = _layer->getMinimalSize();
|
||||
if (not _width ) _width = minSize;
|
||||
if (not _height) _height = minSize;
|
||||
} else {
|
||||
if ((_width) and _checkMinSize and (_width < _layer->getMinimalSize())) {
|
||||
const BasicLayer* basicLayer = dynamic_cast<const BasicLayer*>( _layer );
|
||||
if (not basicLayer or basicLayer->getMaterial() != BasicLayer::Material::cut)
|
||||
minSize = 0;
|
||||
if ((_width) and _checkMinSize and (_width < minSize)) {
|
||||
cerr << Warning( "Contact::_postCheck(): Width %s is inferior to layer minimal size %s, bumping.\n"
|
||||
" (on %s)"
|
||||
, DbU::getValueString(_width).c_str()
|
||||
, DbU::getValueString(_layer->getMinimalSize()).c_str()
|
||||
, DbU::getValueString(minSize).c_str()
|
||||
, getString(this).c_str() )
|
||||
<< endl;
|
||||
_width = _layer->getMinimalSize();
|
||||
_width = minSize;
|
||||
rvalue = false;
|
||||
}
|
||||
if ((_height) and _checkMinSize and (_height < _layer->getMinimalSize())) {
|
||||
if ((_height) and _checkMinSize and (_height < minSize)) {
|
||||
cerr << Warning( "Contact::_postCheck(): Height %s is inferior to layer minimal size %s, bumping.\n"
|
||||
" (on %s)"
|
||||
, DbU::getValueString(_height).c_str()
|
||||
, DbU::getValueString(_layer->getMinimalSize()).c_str()
|
||||
, DbU::getValueString(minSize).c_str()
|
||||
, getString(this).c_str() )
|
||||
<< endl;
|
||||
_height = _layer->getMinimalSize();
|
||||
_height = minSize;
|
||||
rvalue = false;
|
||||
}
|
||||
if ((_width % twoGrid) and _checkMinSize) {
|
||||
|
|
|
@ -223,8 +223,8 @@ namespace Hurricane {
|
|||
// );
|
||||
|
||||
// Rotate the painter for the cartouche if in A4+Landscape mode.
|
||||
if ( (_printer->paperSize () == QPrinter::A4)
|
||||
and (_printer->orientation() == QPrinter::Landscape) ) {
|
||||
if ( (_printer->pageLayout().pageSize().id() == QPageSize::A4)
|
||||
and (_printer->pageLayout().orientation() == QPageLayout::Landscape) ) {
|
||||
painter.translate ( _paperWidth - frameMargin(), frameMargin() );
|
||||
painter.rotate ( -90 );
|
||||
} else
|
||||
|
@ -326,7 +326,7 @@ namespace Hurricane {
|
|||
|
||||
_printer = printer;
|
||||
_printer->setResolution ( _dpi );
|
||||
_printer->setPageMargins( 0.0, 0.0, 0.0, 0.0, QPrinter::DevicePixel );
|
||||
_printer->setPageMargins( QMarginsF(0.0, 0.0, 0.0, 0.0), QPageLayout::Millimeter );
|
||||
|
||||
_paperWidth = _printer->width ();
|
||||
_paperHeight = _printer->height ();
|
||||
|
@ -336,7 +336,7 @@ namespace Hurricane {
|
|||
_ypaper = (imageOnly) ? 0 : frameMargin();
|
||||
|
||||
// Substract the cartouche size only for A4 format.
|
||||
if ( _printer->orientation() == QPrinter::Landscape ) {
|
||||
if ( _printer->pageLayout().orientation() == QPageLayout::Landscape ) {
|
||||
_drawingWidth -= cartoucheHeight();
|
||||
} else {
|
||||
_drawingHeight -= cartoucheHeight();
|
||||
|
|
Loading…
Reference in New Issue