Compare commits

...

7 Commits

Author SHA1 Message Date
Staf Verhaegen f32188fe2d [gf180mcu]Update pin names
For gf180mcu there are only two rings named vdd and vss.
2022-12-05 17:13:40 +01:00
Staf Verhaegen 6eab01950c [gf180mcu]Reduce inner size when removing drawn polygons.
For gf180mcu the rings are drawn inside the inner area at top
and right of the cell.
2022-12-05 17:13:09 +01:00
Staf Verhaegen 7b04a76fae Add core2chip file for gf180mcu
This is a copy of the sky130 one.
2022-12-01 16:28:01 +01:00
Staf Verhaegen 1262f65eec Hack left/right pin drawing
This is assumed to only fix symptoms, not the real problem.
2022-12-01 16:27:34 +01:00
Staf Verhaegen 8ebd0954e5 Fix left/right pin connection.
Made code look like North/South pins.
I am not sure these are needed anyway.
2022-11-29 12:02:16 +01:00
Staf Verhaegen 047eb4cc78 Also mark gf180mcu process as Sky130 2022-11-29 12:02:16 +01:00
Staf Verhaegen 0ee4542d57 Allow StdCellLib* names for standard cells. 2022-11-29 12:02:16 +01:00
5 changed files with 325 additions and 12 deletions

View File

@ -182,7 +182,11 @@ namespace {
defrSetSNetCbk ( _snetCbk );
defrSetPathCbk ( _pathCbk );
if (DataBase::getDB()->getTechnology()->getName() == "Sky130") _flags |= Sky130;
if ( (DataBase::getDB()->getTechnology()->getName() == "Sky130")
|| (DataBase::getDB()->getTechnology()->getName() == "gf180mcu")
) {
_flags |= Sky130;
}
}

View File

@ -74,6 +74,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/niolib.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/libresocio.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/sky130.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/gf180mcu.py
)
set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py

View File

@ -281,13 +281,29 @@ class CoreWire ( object ):
, wwidthM5
)
else:
hChip = Horizontal.create( self.chipNet
, self.padSegment.getLayer()
, self.bbSegment.getCenter().getY()
, self.bbSegment.getHeight()
, xPadMin
, xPadMax
)
# hChip = Horizontal.create( self.chipNet
# , self.padSegment.getLayer()
# , self.bbSegment.getCenter().getY()
# , self.bbSegment.getHeight()
# , xPadMin
# , xPadMax
# )
if self.side == West:
hChip = Horizontal.create( self.chipNet
, self.padSegment.getLayer()
, self.bbSegment.getCenter().getY()
, self.bbSegment.getHeight()
, xPadMin
, xPadMax
)
else:
hChip = Horizontal.create( self.chipNet
, self.padSegment.getLayer()
, self.bbSegment.getCenter().getY()
, self.bbSegment.getHeight()
, xPadMin + 3*vPitch
, xPadMax
)
trace( 550, '\tself.arraySize: %s\n' % str(self.arraySize) )
if self.arraySize:
contacts = self.conf.coronaContactArray( self.chipNet
@ -314,7 +330,7 @@ class CoreWire ( object ):
vStrapBb = contact.getBoundingBox( padLayer )
coronaTransf.applyOn( vStrapBb )
if self.arraySize:
if self.side == West: xContact = min( xContact, vStrapBb.getXMin() )
if self.side == West: xContact = min( xContact, vStrapBb.getXMin() - vPitch )
else: xContact = max( xContact, vStrapBb.getXMax() )
hCorona = self.conf.coronaHorizontal( self.chipNet
, self.symSegmentLayer
@ -333,10 +349,10 @@ class CoreWire ( object ):
, DbU.fromLambda( 1.0 )
, self.bbSegment.getHeight()
)
hChipBb = hChip.getBoundingBox( padLayer )
hChipBb = hChip.getBoundingBox()
vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMin() )
vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMax() )
hCoronaBb = hCorona.getBoundingBox( padLayer )
hCoronaBb = hCorona.getBoundingBox()
self.conf.icorona.getTransformation().applyOn( hCoronaBb )
vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.getYMin() )
vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.getYMax() )

View File

@ -0,0 +1,292 @@
# This file is part of the Coriolis Software.
# Copyright (c) Sorbonne Université 2020-2021, 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/sky130.py" |
# +-----------------------------------------------------------------+
"""
Core2Chip configuration for the Sky130 harness.
"""
import sys
import re
from Hurricane import DbU, DataBase, UpdateSession, Breakpoint, \
Transformation , Box, Instance , Net, \
Contact
import Viewer
from CRL import Catalog
from CRL import AllianceFramework, DefImport
from helpers import trace, l, u, n
from helpers.io import ErrorMessage, WarningMessage
from helpers.overlay import CfgCache, UpdateSession
import plugins.alpha.chip
from plugins.alpha.block.configuration import IoPin, GaugeConf
from plugins.alpha.core2chip.core2chip import CoreToChip as BaseCoreToChip, \
IoNet, IoPad
# -------------------------------------------------------------------
# Class : "MatchHarnessIos".
class MatchHarnessIos ( object ):
"""
In case the connections of the core to the I/O pins are not specified
(empty ioPadsSpecs list), try to guess the connection by names.
.. note:: Currently, only matching with the (io_in,io_out,io_oeb),
power and clock are supported.
"""
def __init__ ( self, coreToChip ):
self.coreToChip = coreToChip
self.digitalIos = []
for i in range(38):
self.digitalIos.append( [None, None, None] )
self.clock = None
self.digitalVdd = None
self.digitalVss = None
@property
def conf ( self ): return self.coreToChip.conf
def matchCore ( self ):
print( ' o Using implicit Caravel harness connections.' )
reIoIn = re.compile( r'^(?P<name>\w+)\((?P<index>\d+)\)$' )
for net in self.conf.core.getNets():
if not net.isExternal(): continue
if net.isClock():
self.clock = net
continue
if net.isPower():
self.digitalVdd = net
continue
if net.isGround():
self.digitalVss = net
continue
m = reIoIn.match( net.getName() )
if m:
index = int( m.group('index') )
if index >= 38:
continue
if m.group('name') == 'io_in':
self.digitalIos[ index ][0] = net
elif m.group('name') == 'io_out':
self.digitalIos[ index ][1] = net
elif m.group('name') == 'io_oeb':
self.digitalIos[ index ][2] = net
else:
print( WarningMessage('Unable to match "{}" into harness net.'.format( net.getName() )))
else:
print( WarningMessage('Unable to match "{}" into harness net.'.format( net.getName() )))
if self.digitalVdd:
self.conf.chipConf.addIoPad( (None, None, 'power_0', 'vdd', self.digitalVdd.getName()), 0 )
else:
print( WarningMessage('Missing digital power net in "{}".'.format(self.conf.core.getName())) )
if self.digitalVss:
self.conf.chipConf.addIoPad( (None, None, 'ground_0', 'vss', self.digitalVss.getName()), 0 )
else:
print( WarningMessage('Missing digital ground net in "{}".'.format(self.conf.core.getName())) )
if self.clock:
self.conf.chipConf.addIoPad( (None, None, None, 'user_clock2', self.clock.getName()), 0 )
else:
print( WarningMessage('Missing digital clock net in "{}".'.format(self.conf.core.getName())) )
for i in range(38):
ioNets = self.digitalIos[ i ]
if ioNets[0] and ioNets[1] and ioNets[2]:
self.conf.chipConf.addIoPad( ( None, None, None, ioNets[0].getName()
, ioNets[0].getName()
, ioNets[1].getName()
, ioNets[2].getName() ), 0 )
elif ioNets[0] and not ioNets[1] and not ioNets[2]:
self.conf.chipConf.addIoPad( ( None, None, None, ioNets[0].getName()
, ioNets[0].getName() ), 0 )
elif not ioNets[0] and not ioNets[1] and ioNets[2]:
self.conf.chipConf.addIoPad( ( None, None, None, ioNets[2].getName()
, ioNets[2].getName() ), 0 )
elif not ioNets[0] and not ioNets[1] and not ioNets[2]:
continue
else:
print( WarningMessage( [ 'Incomplete digital connexion to I/O pad "{}".'.format(index)
, '* In :{}'.format( ioNets[0] )
, '* Out:{}'.format( ioNets[1] )
, '* OEb:{}'.format( ioNets[2] ) ]))
# --------------------------------------------------------------------
# Class : "sky130.CoreToChip"
class CoreToChip ( BaseCoreToChip ):
"""
Provide harness-specific part for SkyWater 130 (works in real mode).
Emulate the behavior of I/O pads.
"""
rePadType = re.compile(r'(?P<type>.+)_(?P<index>[\d]+)$')
def __init__ ( self, core ):
self.ioPadNames = { 'bidir' :'IOHarnessInOut'
, 'analog':'IOHarnessAnalog'
, 'vdd' :'IOHarnessVdd'
, 'vss' :'IOHarnessVss'
, 'iovdd' :'IOHarnessIOVdd'
, 'iovss' :'IOHarnessIOVss'
}
BaseCoreToChip.__init__ ( self, core )
self.conf.useHarness = True
self.ringNetNames = { 'vss' : None
, 'vdd' : None
}
self.ioPadInfos = [ BaseCoreToChip.IoPadInfo( IoPad.BIDIR
, self.ioPadNames['bidir']
, 'pad', ['io_in', 'io_out', 'io_oeb'] )
, BaseCoreToChip.IoPadInfo( IoPad.ANALOG
, self.ioPadNames['analog']
, 'pad', ['pad', 'padres'] )
]
self._getPadLib()
if self.conf.chipConf.ioPadsCount() == 0:
MatchHarnessIos( self ).matchCore()
return
def _getPadLib ( self ):
return None
def getNetType ( self, netName ):
if netName.startswith('vss') or netName.startswith('vee'): return Net.Type.GROUND
if netName.startswith('vdd') or netName.startswith('vcc'): 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 ):
raise NotImplementedError( 'coreToChip.getCell(): Harness does not provides I/O pad cells.' )
def _buildCoreGroundPads ( self, ioPadConf ):
trace( 550, '\tsky130.CoreToChip._buildGroundPowerPads()\n' )
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.padSupplyNetName )
if not coronaNet:
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
coronaNet.setExternal ( True )
coronaNet.setGlobal ( True )
coronaNet.setDirection( Net.Direction.IN )
coronaNet.setType ( Net.Type.GROUND )
self.icore.getPlug( coreNet ).setNet( coronaNet )
trace( 550, '\tCreated corona ground net: {}\n'.format(coronaNet) )
if not chipNet:
raise ErrorMessage( 1, 'Harness do not provide ground net ""{}' \
.format( ioPadConf.padSupplyNetName ))
coronaPlug = self.icorona.getPlug( coronaNet )
if not coronaPlug.getNet():
coronaPlug.setNet( chipNet )
self.groundPadCount += 1
def _buildCorePowerPads ( self, ioPadConf ):
trace( 550, '\tsky130.CoreToChip._buildCorePowerPads()\n' )
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.padSupplyNetName )
if not coronaNet:
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
coronaNet.setExternal ( True )
coronaNet.setGlobal ( True )
coronaNet.setDirection( Net.Direction.IN )
coronaNet.setType ( Net.Type.POWER )
self.icore.getPlug( coreNet ).setNet( coronaNet )
trace( 550, '\tCreated corona power net: {}\n'.format(coronaNet) )
if not chipNet:
raise ErrorMessage( 1, 'Harness do not provide power net ""{}' \
.format( ioPadConf.padSupplyNetName ))
self.icorona.getPlug( coronaNet ).setNet( chipNet )
coronaPlug = self.icorona.getPlug( coronaNet )
if not coronaPlug.getNet():
coronaPlug.setNet( chipNet )
self.powerPadCount += 1
def _buildClockPads ( self, ioPadConf ):
"""For "Sky130" there is no specialized clock I/O pad. So do nothing."""
pass
def _connectClocks ( self ):
"""For "Sky130" there is no pad internal clock ring. So do nothing."""
pass
def _loadHarness ( self ):
"""
Load the DEF file containing the reference harness layout.
Remove the supplied internal power grid and slightly shrink
the central P&R area so that I/O pins are fully outside of it.
"""
self.harness = DefImport.load( self.conf.cfg.harness.path )
# For gf180mcu the rings are drawn inside the AbutmentBox
Ab = self.harness.getAbutmentBox()
innerAb = Box( Ab.getXMin(), Ab.getYMin()
, Ab.getXMax() - u(20.0), Ab.getYMax() - u(20.0)
)
wholeBb = self.harness.getBoundingBox()
filterBb = Box( wholeBb.getXMin(), innerAb.getYMin()
, wholeBb.getXMax(), innerAb.getYMax() )
components = []
for component in self.harness.getComponentsUnder( filterBb ):
if component.getNet().isSupply() and filterBb.contains( component.getBoundingBox() ):
components.append( component )
for instance in self.harness.getInstancesUnder( filterBb ):
components.append( instance )
with UpdateSession():
for component in components:
component.destroy()
components = []
filterBb = Box( innerAb.getXMin(), wholeBb.getYMin()
, innerAb.getXMax(), wholeBb.getYMax() )
for component in self.harness.getComponentsUnder( filterBb ):
if component.getNet().isSupply() and filterBb.contains( component.getBoundingBox() ):
components.append( component )
for instance in self.harness.getInstancesUnder( filterBb ):
components.append( instance )
with UpdateSession():
for component in components:
component.destroy()
areaXMin = innerAb.getXMin()
areaYMin = innerAb.getYMin()
areaXMax = innerAb.getXMax()
areaYMax = innerAb.getYMax()
for net in self.harness.getNets():
if net.isSupply(): continue
for component in net.getComponents():
trace( 550, '\t| {}\n'.format(component) )
bb = component.getBoundingBox()
side = None
if bb.getXMin() < innerAb.getXMin():
areaXMin = max( areaXMin, bb.getXMax() )
side = IoPin.WEST
if bb.getXMax() > innerAb.getXMax():
areaXMax = min( areaXMax, bb.getXMin() )
side = IoPin.EAST
if bb.getYMin() < innerAb.getYMin():
areaYMin = max( areaYMin, bb.getYMax() )
side = IoPin.SOUTH
if bb.getYMax() > innerAb.getYMax():
areaYMax = min( areaYMax, bb.getYMin() )
side = IoPin.NORTH
trace( 550, '\tside: {} {}\n'.format(side,type(component)) )
if side and isinstance(component,Contact):
trace( 550, '\tAdded on {} side: {}\n'.format(side,component) )
self.conf.chipConf.addHarnessPin( component, side )
area = Box( areaXMin, areaYMin, areaXMax, areaYMax )
area.inflate( - self.conf.hRoutingGauge.getPitch()*2
, - self.conf.vRoutingGauge.getPitch()*2 )
xmodulo = area.getWidth () % self.conf.sliceStep
ymodulo = area.getHeight() % self.conf.sliceHeight
area.inflate( 0, 0, -xmodulo, -ymodulo )
self.harness.setAbutmentBox( area )
return self.harness

View File

@ -498,7 +498,7 @@ namespace {
delta = plane->getLayerGauge()->getPitch();
}
}
if (AllianceFramework::get()->getCellGauge()->getName() == Name("StdCellLib")) {
if (AllianceFramework::get()->getCellGauge()->getName()._getString().substr(0, 10) == "StdCellLib") {
delta = plane->getLayerGauge()->getPitch();
}
}