Merge pull request #41 from lip6/wip-gf180mcu

Wip gf180mcu
This commit is contained in:
Jean-Paul Chaput 2023-09-26 00:30:11 +02:00 committed by GitHub
commit db0adbcc02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 591 additions and 92 deletions

View File

@ -690,9 +690,9 @@ namespace Anabatic {
bool Vertex::isH () const bool Vertex::isH () const
{ {
GCell* gcell = getGCell(); GCell* gcell = getGCell();
if (gcell->isDevice()) return isiHorizontal(); if ( gcell->isDevice()) return isiHorizontal();
else if ((gcell->isHChannel())||(gcell->isHRail())) return true; else if ((gcell->isHChannel()) or (gcell->isHRail())) return true;
else if (gcell->isStrut()| gcell->isMatrix() ) return ((gcell->getWidth() > gcell->getHeight())||(gcell->getWidth() == gcell->getHeight())); else if ( gcell->isStrut() or gcell->isMatrix()) return ((gcell->getWidth() > gcell->getHeight())||(gcell->getWidth() == gcell->getHeight()));
else return false; else return false;
} }

View File

@ -181,7 +181,7 @@ def _routing ():
cfg.katana.globalRipupLimit = 5 cfg.katana.globalRipupLimit = 5
cfg.katana.globalRipupLimit = [1, None] cfg.katana.globalRipupLimit = [1, None]
cfg.katana.longGlobalRipupLimit = 5 cfg.katana.longGlobalRipupLimit = 5
cfg.chip.padCoreSide = 'South' cfg.chip.padCoreSide = 'North'
# Plugins setup # Plugins setup
cfg.clockTree.minimumSide = u(5.04) * 6 cfg.clockTree.minimumSide = u(5.04) * 6
cfg.clockTree.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2' cfg.clockTree.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2'

View File

@ -99,6 +99,10 @@ def _routing():
) )
af.addCellGauge(cg) af.addCellGauge(cg)
af.setCellGauge('StdCell3V3Lib') af.setCellGauge('StdCell3V3Lib')
lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 )
lg5.setType( CRL.RoutingLayerGauge.PowerSupply )
env = af.getEnvironment()
env.setRegister( '.*sff.*' )
# Place & Route setup # Place & Route setup
with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg: with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
@ -162,17 +166,8 @@ def _routing():
cfg.katana.globalRipupLimit = 5 cfg.katana.globalRipupLimit = 5
cfg.katana.globalRipupLimit = [1, None] cfg.katana.globalRipupLimit = [1, None]
cfg.katana.longGlobalRipupLimit = 5 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.minimumSize = 500
cfg.viewer.pixelThreshold = 10 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.minimumSide = l(600)
cfg.clockTree.buffer = 'buf_x1' cfg.clockTree.buffer = 'buf_x1'
cfg.clockTree.placerEngine = 'Etesian' cfg.clockTree.placerEngine = 'Etesian'

View File

@ -27,8 +27,9 @@ def _routing ():
cfg.chip.block.rails.vWidth = u(30.0) cfg.chip.block.rails.vWidth = u(30.0)
cfg.chip.block.rails.hSpacing = u( 6.0) cfg.chip.block.rails.hSpacing = u( 6.0)
cfg.chip.block.rails.vSpacing = u( 6.0) cfg.chip.block.rails.vSpacing = u( 6.0)
cfg.chip.padCorner = 'gf180mcu_fd_io__cor_5lm' #cfg.chip.padCorner = 'gf180mcu_fd_io__cor'
cfg.chip.padSpacers = 'gf180mcu_fd_io__fill10_5lm,gf180mcu_fd_io__fill5_5lm,gf180mcu_fd_io__fill1_5lm' #cfg.chip.padSpacers = 'gf180mcu_fd_io__fill10,gf180mcu_fd_io__fill5,gf180mcu_fd_io__fill1'
cfg.chip.padCoreSide = 'North'
af = AllianceFramework.get() af = AllianceFramework.get()
cg = CellGauge.create( 'LEF.GF_IO_Site' cg = CellGauge.create( 'LEF.GF_IO_Site'
, 'Metal2' # pin layer name. , 'Metal2' # pin layer name.
@ -57,7 +58,6 @@ def _loadIoLib ( pdkDir ):
print( ' o Setup GF180MCU I/O library in {}.'.format( ioLib.getName() )) print( ' o Setup GF180MCU I/O library in {}.'.format( ioLib.getName() ))
io.vprint( 1, ' 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' cellsDir = pdkDir / 'libraries' / 'gf180mcu_fd_io' / 'latest' / 'cells'
print( cellsDir )
for lefFile in cellsDir.glob( '*/*_5lm.lef' ): for lefFile in cellsDir.glob( '*/*_5lm.lef' ):
print( lefFile ) print( lefFile )
gdsFile = lefFile.with_suffix( '.gds' ) gdsFile = lefFile.with_suffix( '.gds' )
@ -65,6 +65,12 @@ def _loadIoLib ( pdkDir ):
Gds.setTopCellName( gdsFile.stem[:-4] ) Gds.setTopCellName( gdsFile.stem[:-4] )
Gds.load( ioLib, gdsFile.as_posix(), Gds.Layer_0_IsBoundary|Gds.NoBlockages ) Gds.load( ioLib, gdsFile.as_posix(), Gds.Layer_0_IsBoundary|Gds.NoBlockages )
LefImport.load( lefFile.as_posix() ) 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 ) af.wrapLibrary( ioLib, 1 )

View File

@ -17,8 +17,8 @@
${CMAKE_CURRENT_SOURCE_DIR}/designflow/dreal.py ${CMAKE_CURRENT_SOURCE_DIR}/designflow/dreal.py
${CMAKE_CURRENT_SOURCE_DIR}/designflow/sv2v.py ${CMAKE_CURRENT_SOURCE_DIR}/designflow/sv2v.py
${CMAKE_CURRENT_SOURCE_DIR}/designflow/svase.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/yosys.py
${CMAKE_CURRENT_SOURCE_DIR}/designflow/yosysnp.py
${CMAKE_CURRENT_SOURCE_DIR}/designflow/blif2vst.py ${CMAKE_CURRENT_SOURCE_DIR}/designflow/blif2vst.py
${CMAKE_CURRENT_SOURCE_DIR}/designflow/pnr.py ${CMAKE_CURRENT_SOURCE_DIR}/designflow/pnr.py
${CMAKE_CURRENT_SOURCE_DIR}/designflow/klayout.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/niolib.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/libresocio.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/libresocio.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/sky130.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 set ( pyPluginChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/constants.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/constants.py

View File

@ -1,4 +1,5 @@
import shutil
from pathlib import Path from pathlib import Path
from doit.exceptions import TaskFailed from doit.exceptions import TaskFailed
from .task import FlowTask from .task import FlowTask
@ -37,6 +38,9 @@ class Clean ( FlowTask ):
if filePath.is_file(): if filePath.is_file():
print( ' - {:<40} [removed]'.format( filePath.as_posix() )) print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
filePath.unlink() filePath.unlink()
elif filePath.is_dir():
print( ' - {:<40} [removed (directory)]'.format( filePath.as_posix() ))
shutil.rmtree( filePath )
else: else:
print( ' - {}'.format( filePath.as_posix() )) print( ' - {}'.format( filePath.as_posix() ))
if doExtrasClean and len(self.extrasGlobs): if doExtrasClean and len(self.extrasGlobs):

View File

@ -24,7 +24,7 @@ class PnR ( FlowTask ):
textMode = True textMode = True
@staticmethod @staticmethod
def mkRule ( rule, targets=[], depends=[], script=None ): def mkRule ( rule, targets=[], depends=[], script=None, topName=None ):
""" """
Creates a new rule instance (``doit`` task). Creates a new rule instance (``doit`` task).
@ -36,11 +36,12 @@ class PnR ( FlowTask ):
:param script: A callable, typically a ``scriptMain()`` function. The only :param script: A callable, typically a ``scriptMain()`` function. The only
requirement is that it should accept one keyworded argument (``**kw``). 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 ) super().__init__( rule, targets, depends )
self.script = script self.script = script
self.topName = topName
self.addClean( self.targets ) self.addClean( self.targets )
def __repr__ ( self ): def __repr__ ( self ):
@ -70,8 +71,11 @@ class PnR ( FlowTask ):
if self.script and not callable(self.script): if self.script and not callable(self.script):
e = ErrorMessage( 1, 'PnR.doTask(): "script" argument is *not* callable.' ) e = ErrorMessage( 1, 'PnR.doTask(): "script" argument is *not* callable.' )
return TaskFailed( e ) return TaskFailed( e )
kw = {}
if self.script: if self.script:
self.script( **{} ) if self.topName:
kw[ 'loadCell' ] = self.topName
self.script( **kw )
if not PnR.textMode: if not PnR.textMode:
# Run in graphic mode. # Run in graphic mode.
ha = Viewer.HApplication.create( [] ) ha = Viewer.HApplication.create( [] )

View File

@ -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
}

View File

@ -2,7 +2,6 @@
import os.path import os.path
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from pyosys import libyosys as yosys
from doit.exceptions import TaskFailed from doit.exceptions import TaskFailed
from .task import FlowTask from .task import FlowTask
@ -19,11 +18,12 @@ class Sv2v ( FlowTask ):
FlagLog = 0x00000001 FlagLog = 0x00000001
@staticmethod @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 ) return Sv2v( rule, targets, depends, top, incdirs, libdirs, defines, flags )
def __init__ ( self, rule, targets, depends, top, incdirs, libdirs, defines, flags ): def __init__ ( self, rule, targets, depends, top, incdirs, libdirs, defines, flags ):
self.flags = flags self.flags = flags
self.top = top
self.incdirs = incdirs self.incdirs = incdirs
self.libdirs = libdirs self.libdirs = libdirs
self.defines = defines self.defines = defines
@ -31,10 +31,6 @@ class Sv2v ( FlowTask ):
self.success = True self.success = True
targets = FlowTask._normFileList( targets ) targets = FlowTask._normFileList( targets )
depends = FlowTask._normFileList( depends ) depends = FlowTask._normFileList( depends )
if top is not None:
self.top = top
else:
self.top = depends[0].stem
if targets == []: if targets == []:
targets.append( self.top + '.v' ) targets.append( self.top + '.v' )
#if self.flags & Sv2v.FlagLog: #if self.flags & Sv2v.FlagLog:

View File

@ -2,7 +2,6 @@
import os.path import os.path
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from pyosys import libyosys as yosys
from doit.exceptions import TaskFailed from doit.exceptions import TaskFailed
from .task import FlowTask from .task import FlowTask
@ -19,11 +18,12 @@ class Svase ( FlowTask ):
FlagLog = 0x00000001 FlagLog = 0x00000001
@staticmethod @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 ) return Svase( rule, targets, depends, top, incdirs, libdirs, defines, svargs, flags )
def __init__ ( self, 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.flags = flags
self.top = top
self.svargs = svargs self.svargs = svargs
self.incdirs = incdirs self.incdirs = incdirs
self.libdirs = libdirs self.libdirs = libdirs
@ -32,15 +32,12 @@ class Svase ( FlowTask ):
self.success = True self.success = True
targets = FlowTask._normFileList( targets ) targets = FlowTask._normFileList( targets )
depends = FlowTask._normFileList( depends ) depends = FlowTask._normFileList( depends )
if top is not None:
self.top = top
else:
self.top = depends[0].stem
if targets == []: if targets == []:
targets.append( self.top + '.v' ) targets.append( self.top + '.v' )
#if self.flags & Svase.FlagLog: #if self.flags & Svase.FlagLog:
# self.log = Path( self.top + '.log' ) # self.log = Path( self.top + '.log' )
# targets.append( self.log ) # targets.append( self.log )
targets.append( './slang-args.txt' )
super().__init__( rule, targets, depends ) super().__init__( rule, targets, depends )
self.addClean( targets ) self.addClean( targets )

View File

@ -284,7 +284,6 @@ def setupGf180mcu_c4m ( checkToolkit=None
cfg.misc.verboseLevel2 = True cfg.misc.verboseLevel2 = True
cfg.etesian.graphics = 3 cfg.etesian.graphics = 3
cfg.etesian.spaceMargin = 0.10 cfg.etesian.spaceMargin = 0.10
cfg.anabatic.topRoutingLayer = 'metal6'
cfg.katana.eventsLimit = 4000000 cfg.katana.eventsLimit = 4000000
af = CRL.AllianceFramework.get() af = CRL.AllianceFramework.get()
lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 ) lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 )

View File

@ -1,15 +1,26 @@
import os.path import os.path
import shutil
import subprocess
from pathlib import Path from pathlib import Path
from doit.exceptions import TaskFailed from doit.exceptions import TaskFailed
from .task import FlowTask from .task import FlowTask
usePyYosys = True
try:
from pyosys import libyosys as yosys
except:
usePyYosys = False
class BadLiberty ( Exception ): pass class BadLiberty ( Exception ): pass
class Yosys ( FlowTask ): class Yosys ( FlowTask ):
FlagLog = 0x00000001
FlagQuiet = 0x00000002
FlagSystemVerilog = 0x00000004
_liberty = None _liberty = None
@staticmethod @staticmethod
@ -25,20 +36,58 @@ class Yosys ( FlowTask ):
Yosys._liberty = liberty Yosys._liberty = liberty
@staticmethod @staticmethod
def mkRule ( rule, depends, top=None, blackboxes=[], flattens=[] ): def mkRule ( rule
return Yosys( rule, depends, top, blackboxes, flattens ) , 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 ) super().__init__( rule, [], depends )
self.success = True
self.blackboxes = blackboxes self.blackboxes = blackboxes
self.flattens = flattens self.flattens = flattens
self.depends += blackboxes 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: if top is not None:
self.top = top self.top = top
else: else:
self.top = self.main.stem self.top = self.main.stem
self.targets = [ Path( self.top + '.blif') ] self.targets = [ Path( self.top + '.blif') ]
if not usePyYosys:
self.targets.append( Path( self.top + '.ys' ))
self.addClean( self.targets ) self.addClean( self.targets )
def __repr__ ( self ): def __repr__ ( self ):
@ -53,11 +102,6 @@ class Yosys ( FlowTask ):
def main ( self ): def main ( self ):
return self.file_depend( 0 ) 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 ): def _loadDesign ( self, design ):
from ..helpers.io import ErrorMessage from ..helpers.io import ErrorMessage
if self.success is not True: return if self.success is not True: return
@ -66,13 +110,49 @@ class Yosys ( FlowTask ):
self.success = TaskFailed( e ) self.success = TaskFailed( e )
return return
design = Path( design ) design = Path( design )
if design.suffix == '.v' : self._run_pass( 'read_verilog -sv {}'.format( design.as_posix() )) if design.suffix == '.v' :
elif design.suffix == '.il': self._run_pass( 'read_ilang {}'.format( design.as_posix() )) 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: else:
e = ErrorMessage( 1, 'Yosys._loadDesign(): Unsupported input format for "{}".'.format( design )) e = ErrorMessage( 1, 'Yosys._loadDesign(): Unsupported input format for "{}".'.format( design ))
self.success = TaskFailed( e ) self.success = TaskFailed( e )
return 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 ): def _loadBlackboxes ( self ):
if self.success is not True: return if self.success is not True: return
for blackbox in self.blackboxes: for blackbox in self.blackboxes:
@ -81,11 +161,34 @@ class Yosys ( FlowTask ):
def _doFlattens ( self ): def _doFlattens ( self ):
if self.success is not True: return if self.success is not True: return
flattens = ' '.join( self.flattens ) flattens = ' '.join( self.flattens )
self._run_pass( 'flatten {}\n'.format( flattens )) self.script.append( 'flatten {}'.format( flattens ))
self._run_pass( 'hierarchy -top {}\n'.format( self.top )) 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 ): def doTask ( self ):
from pyosys import libyosys as yosys
from ..helpers.io import ErrorMessage from ..helpers.io import ErrorMessage
if self.liberty is None: if self.liberty is None:
e = ErrorMessage( 1, [ 'Yosys.doTask(): "liberty" has not been set' ] ) 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 "{}"' e = ErrorMessage( 1, [ 'Yosys.doTask(): File not found "{}"'
, '"{}"'.format( self.liberty.as_posix() ) ] ) , '"{}"'.format( self.liberty.as_posix() ) ] )
return TaskFailed( e ) return TaskFailed( e )
#print( 'Yosys.doTask() on "{}"'.format( self.design )) #print( 'Yosys.doTask() on "{}"'.format( self.main ))
self.tool = yosys.Design()
self._loadBlackboxes() self._loadBlackboxes()
if self.flags & Yosys.FlagSystemVerilog:
self._loadSVDesign()
else:
self._loadDesign( self.main ) self._loadDesign( self.main )
self._run_pass( 'hierarchy -check -top {}'.format( self.top )) self.script.append( 'hierarchy -check -top {}'.format( self.top ))
self._run_pass( 'synth -top {}'.format( self.top )) self.script.append( 'synth -top {}'.format( self.top ))
self._doFlattens() self._doFlattens()
self._run_pass( 'memory' ) self.script.append( 'memory' )
self._run_pass( 'dfflibmap -liberty {}'.format( self.liberty.as_posix() )) self.script.append( 'dfflibmap -liberty {}'.format( self.liberty.as_posix() ))
self._run_pass( 'abc -liberty {}'.format( self.liberty.as_posix() )) self.script.append( 'abc -liberty {}'.format( self.liberty.as_posix() ))
self._run_pass( 'clean' ) self.script.append( 'clean')
self._run_pass( 'write_blif {}'.format( self.targets[0] )) self.script.append( 'write_blif {}'.format( self.targets[0] ))
self._runScript()
return self.success return self.success
def create_doit_tasks ( self ): def create_doit_tasks ( self ):

View File

@ -2,7 +2,6 @@
import os.path import os.path
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from pyosys import libyosys as yosys
from doit.exceptions import TaskFailed from doit.exceptions import TaskFailed
from .task import FlowTask from .task import FlowTask

View File

@ -484,6 +484,19 @@ class Block ( object ):
trace( 550, '\tCORE AB is {}\n'.format(self.conf.cell.getAbutmentBox()) ) trace( 550, '\tCORE AB is {}\n'.format(self.conf.cell.getAbutmentBox()) )
if self.conf.isCoreBlock: if self.conf.isCoreBlock:
self.conf.setupICore() 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() ) self.conf.setRoutingBb( self.conf.cellPnR.getAbutmentBox() )
def flattenNets ( self ): def flattenNets ( self ):

View File

@ -15,6 +15,7 @@
import sys import sys
import re import re
import os.path import os.path
import collections
from operator import itemgetter from operator import itemgetter
from ... import Cfg from ... import Cfg
from ...Hurricane import DataBase, Breakpoint, DbU, Box, Transformation, \ from ...Hurricane import DataBase, Breakpoint, DbU, Box, Transformation, \
@ -1449,6 +1450,21 @@ class BlockConf ( GaugeConf ):
for ioPinSpec in self.ioPinsArg: for ioPinSpec in self.ioPinsArg:
self.ioPins.append( IoPin( *ioPinSpec ) ) self.ioPins.append( IoPin( *ioPinSpec ) )
for line in range(len(self.ioPadsArg)): for line in range(len(self.ioPadsArg)):
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 ) self.chipConf.addIoPad( self.ioPadsArg[line], line )
trace( 550, ',-' ) trace( 550, ',-' )

View File

@ -99,11 +99,14 @@ class Chip ( Block ):
trace( 550, '\tminHCorona={}\n'.format(DbU.getValueString( minHCorona ))) trace( 550, '\tminHCorona={}\n'.format(DbU.getValueString( minHCorona )))
trace( 550, '\tminVCorona={}\n'.format(DbU.getValueString( minVCorona ))) trace( 550, '\tminVCorona={}\n'.format(DbU.getValueString( minVCorona )))
else: else:
print( ' - Using harness.' )
self.padsCorona = harnessPads.Corona( self ) self.padsCorona = harnessPads.Corona( self )
self.padsCorona.doLayout() self.padsCorona.doLayout()
innerBb = Box( self.conf.coreAb ) innerBb = Box( self.conf.coreAb )
innerBb.inflate( minHCorona, minVCorona ) innerBb.inflate( minHCorona, minVCorona )
coronaAb = self.conf.corona.getAbutmentBox() coronaAb = self.conf.corona.getAbutmentBox()
trace( 550, '\tinnerBb:{}\n'.format(innerBb) )
trace( 550, '\tcoronaAb:{}\n'.format(coronaAb) )
if innerBb.getWidth() > coronaAb.getWidth(): if innerBb.getWidth() > coronaAb.getWidth():
raise ErrorMessage( 1, 'Core is too wide to fit into the corona, needs {} but only has {}.' \ raise ErrorMessage( 1, 'Core is too wide to fit into the corona, needs {} but only has {}.' \
.format( DbU.getValueString(innerBb .getWidth()) .format( DbU.getValueString(innerBb .getWidth())

View File

@ -693,11 +693,11 @@ class Corona ( object ):
if plug.getMasterNet().isGlobal(): if plug.getMasterNet().isGlobal():
net = self.conf.cell.getNet( plug.getMasterNet().getName() ) net = self.conf.cell.getNet( plug.getMasterNet().getName() )
if not net: if not net:
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is not connected and there is no global net (in pad \"%s").' \ raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "{}" is not connected and there is no global net (in pad "{}").' \
% plug.getMasterNet().getName(), padCell.getName() ) .format( plug.getMasterNet().getName(), padCell.getName() ))
else: else:
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \ raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "{}" is neither connected nor global (in pad "{}").' \
% plug.getMasterNet().getName(), padCell.getName() ) .format( plug.getMasterNet().getName(), padCell.getName() ))
if net: if net:
self.padRails.append( ( net self.padRails.append( ( net
, component.getLayer() , component.getLayer()

View File

@ -375,6 +375,7 @@ class IoPad ( object ):
or self.nets[0].chipExtNetName.startswith('io_in') \ or self.nets[0].chipExtNetName.startswith('io_in') \
or self.nets[0].chipExtNetName.startswith('io_out') or self.nets[0].chipExtNetName.startswith('io_out')
if hasEnable: if hasEnable:
trace( 550, '\tself.nets = {}\n'.format( self.nets ))
if len(self.nets) < 2: if len(self.nets) < 2:
enableNet = self.coreToChip.newEnableForNet( self.nets[0] ) enableNet = self.coreToChip.newEnableForNet( self.nets[0] )
self.nets.append( self.coreToChip.getIoNet( enableNet ) ) 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.nets[0].chipIntNet , padInfo.inputNet ) )
connexions.append( ( self.coreToChip.newDummyNet(), padInfo.outputNet ) ) connexions.append( ( self.coreToChip.newDummyNet(), padInfo.outputNet ) )
if hasEnable: if hasEnable:
trace( 550, '\tenable Pad={} <-> {}\n'.format( padInfo.enableNet, self.nets[1].chipIntNet ))
connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) ) connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) )
elif (self.direction == IoPad.TRI_OUT) and (len(self.nets) < 2): elif (self.direction == IoPad.TRI_OUT) and (len(self.nets) < 2):
self.nets[0].setFlags( IoNet.DoExtNet ) 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[0].chipIntNet, padInfo.inputNet ) )
connexions.append( ( self.nets[1].chipIntNet, padInfo.outputNet ) ) connexions.append( ( self.nets[1].chipIntNet, padInfo.outputNet ) )
connexions.append( ( self.nets[2].chipIntNet, padInfo.enableNet ) ) 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(): if not self.coreToChip.useHarness():
self.pads.append( Instance.create( self.coreToChip.chip self.pads.append( Instance.create( self.coreToChip.chip
, self.padInstanceName , self.padInstanceName
@ -448,13 +455,21 @@ class CoreToChip ( object ):
to the core actually bearing information. to the core actually bearing information.
""" """
class IoControlInfo ( object ):
def __init__ ( self, name, defaultState ):
self.name = name
self.defaultState = defaultState
pass
class IoPadInfo ( object ): class IoPadInfo ( object ):
def __init__ ( self, flags, padName, padNet, coreNets ): def __init__ ( self, flags, padName, padNet, coreNets, controlNets=[] ):
self.flags = flags self.flags = flags
self.name = padName self.name = padName
self.padNet = padNet self.padNet = padNet
self.coreNets = coreNets self.coreNets = coreNets
self.controlNets = [ CoreToChip.IoControlInfo( net[0], net[1] ) for net in controlNets ]
return return
@property @property
@ -508,6 +523,10 @@ class CoreToChip ( object ):
if not masterNetO: masterNet = instance.getMasterCell().getNet( chipNet.getName() ) if not masterNetO: masterNet = instance.getMasterCell().getNet( chipNet.getName() )
elif isinstance(masterNetO,Net): masterNet = masterNetO elif isinstance(masterNetO,Net): masterNet = masterNetO
else: masterNet = instance.getMasterCell().getNet( 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 ) instance.getPlug( masterNet ).setNet( chipNet )
return return
@ -571,6 +590,22 @@ class CoreToChip ( object ):
self.dummyNetCount += 1 self.dummyNetCount += 1
return dummy 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 ): def newEnableForNet ( self, ioNet ):
""" """
Create a new enable signal, in *core* cell, to control the associated I/O pad. Create a new enable signal, in *core* cell, to control the associated I/O pad.
@ -582,13 +617,16 @@ class CoreToChip ( object ):
else: else:
raise ErrorMessage( 2, 'CoreToChip.newEnableForNet(): Net "{}" is neither IN nor OUT.' \ raise ErrorMessage( 2, 'CoreToChip.newEnableForNet(): Net "{}" is neither IN nor OUT.' \
.format(ioNet.coreNet.getName()) ) .format(ioNet.coreNet.getName()) )
instance = self.conf.constantsConf.createInstance( self.core, constantType ) return self.newControlNet( ioNet.enableNetName, constantType )
enable = Net.create( self.core, ioNet.enableNetName )
enable.setExternal ( True ) def newControlForPad ( self, ioPadInfo, ioControlInfo ):
enable.setDirection( Net.Direction.OUT ) """
getPlugByName( instance, self.conf.constantsConf.output(constantType) ).setNet( enable ) Create a new control signal, in *core* cell, to control the associated I/O pad.
self.conf.addClonedCell( self.conf.core ) This is to be used for all I/O pads controls nets, save the "enable" signal.
return enable """
constantType = ConstantsConf.ONE if ioControlInfo.defaultState else ConstantsConf.ZERO
controlNetName = '{}_{}'.format( ioPadInfo.instanceName, ioControlInfo.name )
return self.newControlNet( controlNetName, constantType )
def getIoNet ( self, coreNet ): def getIoNet ( self, coreNet ):
""" """

View File

@ -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

View File

@ -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."); throw Error("Contact::Contact(): Can't create " + _TName("Contact") + ", NULL layer.");
const BasicLayer* basicLayer = dynamic_cast<const BasicLayer*>( 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 ( _width < _layer->getMinimalSize() ) _width = _layer->getMinimalSize();
if ( _height < _layer->getMinimalSize() ) _height = _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()); _anchorHook.attach(anchor->getBodyHook());
const BasicLayer* basicLayer = dynamic_cast<const BasicLayer*>( 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 ( _width < _layer->getMinimalSize() ) _width = _layer->getMinimalSize();
if ( _height < _layer->getMinimalSize() ) _height = _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 twoGrid = DbU::fromGrid( 2 );
DbU::Unit minSize = _layer->getMinimalSize();
bool rvalue = true; bool rvalue = true;
if (_layer->isSymbolic()) { if (_layer->isSymbolic()) {
if (not _width ) _width = _layer->getMinimalSize(); if (not _width ) _width = minSize;
if (not _height) _height = _layer->getMinimalSize(); if (not _height) _height = minSize;
} else { } 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" cerr << Warning( "Contact::_postCheck(): Width %s is inferior to layer minimal size %s, bumping.\n"
" (on %s)" " (on %s)"
, DbU::getValueString(_width).c_str() , DbU::getValueString(_width).c_str()
, DbU::getValueString(_layer->getMinimalSize()).c_str() , DbU::getValueString(minSize).c_str()
, getString(this).c_str() ) , getString(this).c_str() )
<< endl; << endl;
_width = _layer->getMinimalSize(); _width = minSize;
rvalue = false; 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" cerr << Warning( "Contact::_postCheck(): Height %s is inferior to layer minimal size %s, bumping.\n"
" (on %s)" " (on %s)"
, DbU::getValueString(_height).c_str() , DbU::getValueString(_height).c_str()
, DbU::getValueString(_layer->getMinimalSize()).c_str() , DbU::getValueString(minSize).c_str()
, getString(this).c_str() ) , getString(this).c_str() )
<< endl; << endl;
_height = _layer->getMinimalSize(); _height = minSize;
rvalue = false; rvalue = false;
} }
if ((_width % twoGrid) and _checkMinSize) { if ((_width % twoGrid) and _checkMinSize) {

View File

@ -223,8 +223,8 @@ namespace Hurricane {
// ); // );
// Rotate the painter for the cartouche if in A4+Landscape mode. // Rotate the painter for the cartouche if in A4+Landscape mode.
if ( (_printer->paperSize () == QPrinter::A4) if ( (_printer->pageLayout().pageSize().id() == QPageSize::A4)
and (_printer->orientation() == QPrinter::Landscape) ) { and (_printer->pageLayout().orientation() == QPageLayout::Landscape) ) {
painter.translate ( _paperWidth - frameMargin(), frameMargin() ); painter.translate ( _paperWidth - frameMargin(), frameMargin() );
painter.rotate ( -90 ); painter.rotate ( -90 );
} else } else
@ -326,7 +326,7 @@ namespace Hurricane {
_printer = printer; _printer = printer;
_printer->setResolution ( _dpi ); _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 (); _paperWidth = _printer->width ();
_paperHeight = _printer->height (); _paperHeight = _printer->height ();
@ -336,7 +336,7 @@ namespace Hurricane {
_ypaper = (imageOnly) ? 0 : frameMargin(); _ypaper = (imageOnly) ? 0 : frameMargin();
// Substract the cartouche size only for A4 format. // Substract the cartouche size only for A4 format.
if ( _printer->orientation() == QPrinter::Landscape ) { if ( _printer->pageLayout().orientation() == QPageLayout::Landscape ) {
_drawingWidth -= cartoucheHeight(); _drawingWidth -= cartoucheHeight();
} else { } else {
_drawingHeight -= cartoucheHeight(); _drawingHeight -= cartoucheHeight();