Improved SRAM output multiplexer, using NAND/NOR.
* New: In cumulus/plugins/sram_256x32.py, build the output mux using a NAND2/NOR2 binary tree instead of mux2/mux3. Use more, but much smaller cells. The reduction of wirelength (from Yosys) goes from 4% to 15% for the non-folded variant. Uses a specially placed tree to minimize wire length. * New: In cumulus/plugins/sram.py, extend StdCellConf to convert names accross library flavors (FlexLib_TSMC_C180, FlexLib_Sky130 and generic SxLib).
This commit is contained in:
parent
d294a770c4
commit
9594476ab6
|
@ -26,8 +26,8 @@ from helpers.io import ErrorMessage, WarningMessage
|
||||||
from helpers.overlay import UpdateSession
|
from helpers.overlay import UpdateSession
|
||||||
from helpers import trace, l, u, n
|
from helpers import trace, l, u, n
|
||||||
import plugins
|
import plugins
|
||||||
from Hurricane import Breakpoint, DbU, Box, Net, Cell, Instance, \
|
from Hurricane import DataBase, Breakpoint, DbU, Box, Net, Cell, \
|
||||||
Transformation, PythonAttributes
|
Instance, Transformation, PythonAttributes
|
||||||
import CRL
|
import CRL
|
||||||
from Foehn import FoehnEngine, DagExtension
|
from Foehn import FoehnEngine, DagExtension
|
||||||
from plugins.chip.configuration import GaugeConf
|
from plugins.chip.configuration import GaugeConf
|
||||||
|
@ -49,6 +49,12 @@ class StdCellConf ( object ):
|
||||||
reDataIn = re.compile( r'^i[0-9]?' )
|
reDataIn = re.compile( r'^i[0-9]?' )
|
||||||
reDataOut = re.compile( r'^n?q' )
|
reDataOut = re.compile( r'^n?q' )
|
||||||
|
|
||||||
|
def __init__ ( self ):
|
||||||
|
self.techName = DataBase.getDB().getTechnology().getName()
|
||||||
|
|
||||||
|
def __repr__ ( self ):
|
||||||
|
return '<StdCellConf "{}">'.format( self.techName )
|
||||||
|
|
||||||
def isRegister ( self, cell ):
|
def isRegister ( self, cell ):
|
||||||
"""Returns True if the cell is a register."""
|
"""Returns True if the cell is a register."""
|
||||||
m = StdCellConf.reDFF.match( cell.getName() )
|
m = StdCellConf.reDFF.match( cell.getName() )
|
||||||
|
@ -85,6 +91,16 @@ class StdCellConf ( object ):
|
||||||
"""Returns True if the net is a data flow (i.e. not a control)."""
|
"""Returns True if the net is a data flow (i.e. not a control)."""
|
||||||
return self.isDataIn(net) or self.isDataOut(net)
|
return self.isDataIn(net) or self.isDataOut(net)
|
||||||
|
|
||||||
|
def getStdCellName ( self, name ):
|
||||||
|
if self.techName == 'Sky130':
|
||||||
|
if name == 'na2_x1': name = 'nand2_x0'
|
||||||
|
if name == 'no2_x1': name = 'nor2_x0'
|
||||||
|
if name == 'no3_x1': name = 'nor3_x0'
|
||||||
|
return name
|
||||||
|
|
||||||
|
def getStdCell ( self, name ):
|
||||||
|
return af.getCell( self.getStdCellName(name), CRL.Catalog.State.Views )
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# Class : Bus.
|
# Class : Bus.
|
||||||
|
@ -186,6 +202,9 @@ class Column ( object ):
|
||||||
Connect a bus to the column. ``busName`` is the name of the master net
|
Connect a bus to the column. ``busName`` is the name of the master net
|
||||||
in the reference cell of the column.
|
in the reference cell of the column.
|
||||||
"""
|
"""
|
||||||
|
if not busName in self.busPlugs:
|
||||||
|
raise ErrorMessage( 1, 'Column.setBusNet(): {} has no bus named "{}".' \
|
||||||
|
.format( self.tag, busName ))
|
||||||
busPlug = self.busPlugs[ busName ]
|
busPlug = self.busPlugs[ busName ]
|
||||||
if busPlug[0].getNet() and busPlug[0].getNet() != busNet[0]:
|
if busPlug[0].getNet() and busPlug[0].getNet() != busNet[0]:
|
||||||
print( Warning( 'Column.setBusNet(): Overrode {} {} -> {} with {}' \
|
print( Warning( 'Column.setBusNet(): Overrode {} {} -> {} with {}' \
|
||||||
|
@ -318,11 +337,12 @@ class ColGroup ( object ):
|
||||||
Initialize an *empty* column group. Sub-group or columns must be
|
Initialize an *empty* column group. Sub-group or columns must be
|
||||||
added afterwards.
|
added afterwards.
|
||||||
"""
|
"""
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.parent = None
|
self.parent = None
|
||||||
self.order = None
|
self.order = None
|
||||||
self.depth = 0
|
self.depth = 0
|
||||||
self.childs = []
|
self.childs = []
|
||||||
|
self.isReversed = False
|
||||||
|
|
||||||
def __iter__ ( self ):
|
def __iter__ ( self ):
|
||||||
return ColGroupIterator( self )
|
return ColGroupIterator( self )
|
||||||
|
@ -358,11 +378,25 @@ class ColGroup ( object ):
|
||||||
busWidth = max( busWidth, child.busWidth )
|
busWidth = max( busWidth, child.busWidth )
|
||||||
return busWidth
|
return busWidth
|
||||||
|
|
||||||
def group ( self, child ):
|
def group ( self, newChild, after=None, before=None ):
|
||||||
""" Add a new child to the group. """
|
""" Add a new child to the group. """
|
||||||
self.childs.append( child )
|
inserted = False
|
||||||
child.parent = self
|
if after is not None:
|
||||||
self.depth = max( self.depth, child.depth+1 )
|
for i in range(len(self.childs)):
|
||||||
|
if self.childs[i] == after:
|
||||||
|
self.childs.insert( i+1, newChild )
|
||||||
|
inserted = True
|
||||||
|
break
|
||||||
|
if before is not None:
|
||||||
|
for i in range(len(self.childs)):
|
||||||
|
if self.childs[i] == before:
|
||||||
|
self.childs.insert( i, newChild )
|
||||||
|
inserted = True
|
||||||
|
break
|
||||||
|
if not inserted:
|
||||||
|
self.childs.append( newChild )
|
||||||
|
newChild.parent = self
|
||||||
|
self.depth = max( self.depth, newChild.depth+1 )
|
||||||
|
|
||||||
def unGroup ( self, child=None ):
|
def unGroup ( self, child=None ):
|
||||||
""" Remove a child from the group (the child is *not* deleted). """
|
""" Remove a child from the group (the child is *not* deleted). """
|
||||||
|
@ -403,6 +437,7 @@ class ColGroup ( object ):
|
||||||
for child in self.childs:
|
for child in self.childs:
|
||||||
child.reverse()
|
child.reverse()
|
||||||
self.childs.reverse()
|
self.childs.reverse()
|
||||||
|
self.isReversed = not self.isReversed
|
||||||
|
|
||||||
def place ( self ):
|
def place ( self ):
|
||||||
""" Place childs/colums from left to rigth. """
|
""" Place childs/colums from left to rigth. """
|
||||||
|
@ -572,7 +607,7 @@ class FoldState ( object ):
|
||||||
else:
|
else:
|
||||||
self.direction = BaseSRAM.TO_RIGHT
|
self.direction = BaseSRAM.TO_RIGHT
|
||||||
self.x = self.xmin
|
self.x = self.xmin
|
||||||
self.irow += self.sram.rootGroup.busWidth + 1
|
self.irow += self.sram.rootGroup.busWidth + 2
|
||||||
self.fold += 1
|
self.fold += 1
|
||||||
|
|
||||||
def addWidth ( self, width ):
|
def addWidth ( self, width ):
|
||||||
|
@ -622,12 +657,16 @@ class BaseSRAM ( object ):
|
||||||
The overall relative placement is organized as follow : ::
|
The overall relative placement is organized as follow : ::
|
||||||
|
|
||||||
+---------+-------------------------------------------+
|
+---------+-------------------------------------------+
|
||||||
| | headers[1] (1 row) |
|
| | headers[4] (1 row) |
|
||||||
|
| +-------------------------------------------+
|
||||||
|
| | headers[3] (1 row) |
|
||||||
| +-------------------------------------------+
|
| +-------------------------------------------+
|
||||||
| | |
|
| | |
|
||||||
| | Column area, fold 1 (N rows) |
|
| | Column area, fold 1 (N rows) |
|
||||||
| | |
|
| | |
|
||||||
| decoder +-------------------------------------------+
|
| decoder +-------------------------------------------+
|
||||||
|
| | headers[1] (1 row) |
|
||||||
|
| +-------------------------------------------+
|
||||||
| | headers[0] (1 row) |
|
| | headers[0] (1 row) |
|
||||||
| +-------------------------------------------+
|
| +-------------------------------------------+
|
||||||
| | |
|
| | |
|
||||||
|
@ -646,7 +685,7 @@ class BaseSRAM ( object ):
|
||||||
self.busses = {}
|
self.busses = {}
|
||||||
self.decoder = None
|
self.decoder = None
|
||||||
self.toHeaders = []
|
self.toHeaders = []
|
||||||
self.headers = [ HeaderRow( self ) for row in range(fold) ]
|
self.headers = [ HeaderRow( self ) for row in range(fold*2) ]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fold ( self ):
|
def fold ( self ):
|
||||||
|
@ -656,6 +695,12 @@ class BaseSRAM ( object ):
|
||||||
if column.tag in self.foldTags:
|
if column.tag in self.foldTags:
|
||||||
self.foldState.forceFold()
|
self.foldState.forceFold()
|
||||||
|
|
||||||
|
def getBus ( self, fmt ):
|
||||||
|
""" Find a bus by it's formatting string. """
|
||||||
|
if fmt in self.busses:
|
||||||
|
return self.busses[ fmt ]
|
||||||
|
return None
|
||||||
|
|
||||||
def getNet ( self, name, create=True ):
|
def getNet ( self, name, create=True ):
|
||||||
"""
|
"""
|
||||||
Find a Net by name. If it doesn't exists and ``create`` is set to ``True``,
|
Find a Net by name. If it doesn't exists and ``create`` is set to ``True``,
|
||||||
|
@ -694,7 +739,9 @@ class BaseSRAM ( object ):
|
||||||
, 'q' : 'net_output_X' } )
|
, 'q' : 'net_output_X' } )
|
||||||
"""
|
"""
|
||||||
masterCell = af.getCell( masterName, CRL.Catalog.State.Views )
|
masterCell = af.getCell( masterName, CRL.Catalog.State.Views )
|
||||||
inst = Instance.create( self.cell, instName, masterCell )
|
if not masterCell:
|
||||||
|
raise ErrorMessage( 1, 'BaseSRAM.addInstance(): Cannot find cell "{}".'.format( masterName ))
|
||||||
|
inst = Instance.create( self.cell, instName, masterCell )
|
||||||
for masterNetName, netName in netMapNames.items():
|
for masterNetName, netName in netMapNames.items():
|
||||||
masterNet = masterCell.getNet( masterNetName )
|
masterNet = masterCell.getNet( masterNetName )
|
||||||
net = self.getNet( netName )
|
net = self.getNet( netName )
|
||||||
|
@ -796,18 +843,18 @@ class BaseSRAM ( object ):
|
||||||
bb = Box()
|
bb = Box()
|
||||||
bb.merge( self.decoder.place( 0 ) )
|
bb.merge( self.decoder.place( 0 ) )
|
||||||
bb.merge( self.rootGroup.place() )
|
bb.merge( self.rootGroup.place() )
|
||||||
for inst, refInst in self.toHeaders:
|
for inst, refInst, headerRow in self.toHeaders:
|
||||||
self.headers[ refInst.fold ].addInstanceAt( inst, refInst )
|
self.headers[ refInst.fold*2 + headerRow ].addInstanceAt( inst, refInst )
|
||||||
for i in range(len(self.headers)):
|
for i in range(len(self.headers)):
|
||||||
trace( 610, ',+', 'Place row header {} {}\n'.format( i, self.headers[i].row ))
|
trace( 610, ',+', 'Place row header {} {}\n'.format( i, self.headers[i].row ))
|
||||||
if i % 2:
|
if i//2 % 2:
|
||||||
xstart = bb.getXMax()
|
xstart = bb.getXMax()
|
||||||
direction = BaseSRAM.TO_LEFT
|
direction = BaseSRAM.TO_LEFT
|
||||||
else:
|
else:
|
||||||
xstart = self.decoder.width
|
xstart = self.decoder.width
|
||||||
direction = BaseSRAM.TO_RIGHT
|
direction = BaseSRAM.TO_RIGHT
|
||||||
bb.merge( self.headers[i].place( xstart
|
bb.merge( self.headers[i].place( xstart
|
||||||
, self.rootGroup.busWidth*(i + 1) + i
|
, self.rootGroup.busWidth*(i//2 + 1) + i
|
||||||
, direction ))
|
, direction ))
|
||||||
trace( 610, '-,' )
|
trace( 610, '-,' )
|
||||||
self.cell.setAbutmentBox( bb )
|
self.cell.setAbutmentBox( bb )
|
||||||
|
|
|
@ -73,31 +73,50 @@ Provisional results
|
||||||
|
|
||||||
.. note:: All length are in micro-meters.
|
.. note:: All length are in micro-meters.
|
||||||
|
|
||||||
+--------------+-----------------------------+-----------------------------+
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
| Kind | Generator | Yosys |
|
| Arch | Kind | Generator | Yosys |
|
||||||
+==============+=============================+=============================+
|
+========+==============+=============================+=============================+
|
||||||
| # Gates | 23209 (-25.4%) | 32121 |
|
| Mux | # Gates | 23209 (-25.4%) | 32121 |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
+--------+--------------+-----------------------------+ |
|
||||||
| 1 Fold |
|
| Nao | # Gates | 34637 (+7.8%) | |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
| Area | 7182 x 330 (-5.5%) | 7380 x 340 |
|
| 1 Fold |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
| Wirelength | 1841036 (-4.3%) | 1924153 |
|
| | Area | 7182 x 330 (-5.5%) | 7380 x 340 |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
| Mux +--------------+-----------------------------+-----------------------------+
|
||||||
| 2 Fold |
|
| | Wirelength | 1841036 (-4.3%) | 1924153 |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
| Area | 3599 x 660 (-5.3%) | 3690 x 680 |
|
| | Area | 6680 x 340 (-14.9%) | |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
| Nao +--------------+-----------------------------+ |
|
||||||
| Wirelength | 1670455 (-6.3%) | 1782558 |
|
| | Wirelength | 1637781 (-14.9%) | |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
| 4 Fold |
|
| 2 Fold |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
| Area | 1812 x 1320 (-4.6%) | 1900 x 1320 |
|
| | Area | 3599 x 660 (-5.3%) | 3690 x 680 |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
| Mux +--------------+-----------------------------+-----------------------------+
|
||||||
| Wirelength | 1699810 (-1.5%) | 1726436 |
|
| | Wirelength | 1670455 (-6.3%) | 1782558 |
|
||||||
+--------------+-----------------------------+-----------------------------+
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
|
| | Area | 3350 x 680 (-9.2%) | |
|
||||||
|
| Nao +--------------+-----------------------------+ |
|
||||||
|
| | Wirelength | 1548358 (-13.1%) | |
|
||||||
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
|
| 4 Fold |
|
||||||
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
|
| | Area | 1812 x 1320 (-4.6%) | 1900 x 1320 |
|
||||||
|
| Mux +--------------+-----------------------------+-----------------------------+
|
||||||
|
| | Wirelength | 1699810 (-1.5%) | 1726436 |
|
||||||
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
|
| | Area | 1692 x 1360 (-8.2%) | |
|
||||||
|
| Nao +--------------+-----------------------------+ |
|
||||||
|
| | Wirelength | 1512107 (-12.4%) | |
|
||||||
|
+--------+--------------+-----------------------------+-----------------------------+
|
||||||
|
|
||||||
Conclusions that we can draw from those results are :
|
|
||||||
|
The difference between the two implementations resides only in the *output*
|
||||||
|
multiplexer. With a 4 inputs mux made of mux2+mux3 or 2 inputs multiplexer
|
||||||
|
made of alternate layers of nand2+nor2.
|
||||||
|
|
||||||
|
Conclusions for the mux2+mux3 implementation :
|
||||||
|
|
||||||
1. The generator version uses subtantially less gates than the Yosys one.
|
1. The generator version uses subtantially less gates than the Yosys one.
|
||||||
As the both SRAM uses the exact same number of SFFs, the difference is
|
As the both SRAM uses the exact same number of SFFs, the difference is
|
||||||
|
@ -111,26 +130,42 @@ Conclusions that we can draw from those results are :
|
||||||
|
|
||||||
In particular, to build the output multiplexer we only have mx2 and
|
In particular, to build the output multiplexer we only have mx2 and
|
||||||
mx3 cells, which are large. The density of the SRAM could be much
|
mx3 cells, which are large. The density of the SRAM could be much
|
||||||
increased if we did have nmx2 and nmx3. We could also try to synthesise
|
increased if we did have nmx2 and nmx3.
|
||||||
the tree using nandX and norX but we are short of time.
|
|
||||||
|
|
||||||
Furthermore for the output multiplexers, as it is a controlled case,
|
Furthermore for the output multiplexers, as it is a controlled case,
|
||||||
we may also uses three-state drivers cells (which have not been
|
we may also uses three-state drivers cells (which have not been
|
||||||
ported either).
|
ported either).
|
||||||
|
|
||||||
|
Conclusion for the nand2+nor2 implementation:
|
||||||
|
|
||||||
|
1. The multiplexer allows us for a much more compact area and noticeably
|
||||||
|
lesser wire length. With an increased number of cells (not an issue).
|
||||||
|
|
||||||
|
2. The total wire length is extremely sensitive to the placement, which
|
||||||
|
in our case is just a column ordering. To optimize, the binary tree
|
||||||
|
(for the netlist) is not placed fully symmetrically but slightly
|
||||||
|
"askew".
|
||||||
|
|
||||||
|
|
||||||
.. note:: Cell width in the SkyWater 130 port of FlexLib:
|
.. note:: Cell width in the SkyWater 130 port of FlexLib:
|
||||||
|
|
||||||
============== =====
|
============== =====
|
||||||
Cell Width
|
Cell Width
|
||||||
============== =====
|
============== =====
|
||||||
|
inv_x2 2
|
||||||
mx2_x2 7
|
mx2_x2 7
|
||||||
mx3_x2 11
|
mx3_x2 11
|
||||||
|
a3_x2 5
|
||||||
nand2_x0 2
|
nand2_x0 2
|
||||||
nand3_x0 3
|
nand3_x0 3
|
||||||
nand4_x0 4
|
nand4_x0 4
|
||||||
nor2_x0 2
|
nor2_x0 2
|
||||||
|
nor3_x0 3
|
||||||
|
sff1_x4 15
|
||||||
============== =====
|
============== =====
|
||||||
|
|
||||||
|
Differrent ways of implementing the output multiplexer :
|
||||||
|
|
||||||
1. mx2_x2 + mx3_x2 = 18
|
1. mx2_x2 + mx3_x2 = 18
|
||||||
2. 9 * nand2_x0 = 18
|
2. 9 * nand2_x0 = 18
|
||||||
3. 4 * nand3_x0 + nand4_x0 = 16
|
3. 4 * nand3_x0 + nand4_x0 = 16
|
||||||
|
@ -178,15 +213,18 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
if fold == 1:
|
if fold == 1:
|
||||||
pass
|
pass
|
||||||
elif fold == 2:
|
elif fold == 2:
|
||||||
self.foldTags = [ 'imux_addr0128' ]
|
#self.foldTags = [ 'imux_addr0128' ]
|
||||||
|
self.foldTags = [ 'imux_addr0192' ]
|
||||||
elif fold == 4:
|
elif fold == 4:
|
||||||
self.foldTags = [ 'omux_0_to_127', 'imux_addr0128', 'imux_addr0240' ]
|
#self.foldTags = [ 'omux_0_to_127', 'imux_addr0128', 'imux_addr0240' ]
|
||||||
#self.foldTags = [ 'imux_addr0064', 'imux_addr0128', 'imux_addr0192' ]
|
self.foldTags = [ 'imux_addr0096', 'imux_addr0192', 'imux_addr0160' ]
|
||||||
else:
|
else:
|
||||||
raise ErrorMessage( 1, 'SRAM_256x32.__init__(): Unsupported fold {}, valid values are 1, 2, 4.'.format( fold ))
|
raise ErrorMessage( 1, 'SRAM_256x32.__init__(): Unsupported fold {}, valid values are 1, 2, 4.'.format( fold ))
|
||||||
self.cell = af.createCell( 'spram_256x32' )
|
self.cell = af.createCell( 'spram_256x32' )
|
||||||
self.mx2Cell = af.getCell( 'mx2_x2', CRL.Catalog.State.Views )
|
self.mx2Cell = self.confLib.getStdCell( 'mx2_x2' )
|
||||||
self.mx3Cell = af.getCell( 'mx3_x2', CRL.Catalog.State.Views )
|
self.mx3Cell = self.confLib.getStdCell( 'mx3_x2' )
|
||||||
|
self.na2Cell = self.confLib.getStdCell( 'na2_x1' )
|
||||||
|
self.no2Cell = self.confLib.getStdCell( 'no2_x1' )
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
self.buildInterface()
|
self.buildInterface()
|
||||||
self.decoder = ColBlock( self, 'decod', 33 )
|
self.decoder = ColBlock( self, 'decod', 33 )
|
||||||
|
@ -203,61 +241,149 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
, 'bit_addr{:04d}'.format( addr )
|
, 'bit_addr{:04d}'.format( addr )
|
||||||
, '_byte{byte}_{bbit}'
|
, '_byte{byte}_{bbit}'
|
||||||
, 32 ))
|
, 32 ))
|
||||||
bus = Bus( self, 'imux_addr{:04d}_b_q({{}})'.format(addr), 32 )
|
bus = Bus( self, 'imux_addr{:04d}_q({{}})'.format(addr), 32 )
|
||||||
bitGroup.childs[0].setBusNet( 'q', bus )
|
bitGroup.childs[0].setBusNet( 'q', bus )
|
||||||
bitGroup.childs[1].setBusNet( 'i', bus )
|
bitGroup.childs[1].setBusNet( 'i', bus )
|
||||||
bus = Bus( self, 'bit_addr{:04d}_b_q({{}})'.format(addr), 32 )
|
bus = Bus( self, 'bit_addr{:04d}_q({{}})'.format(addr), 32 )
|
||||||
bitGroup.childs[0].setBusNet( 'i0', bus )
|
bitGroup.childs[0].setBusNet( 'i0', bus )
|
||||||
bitGroup.childs[1].setBusNet( 'q', bus )
|
bitGroup.childs[1].setBusNet( 'q', bus )
|
||||||
bus = Bus( self, 'di({})', 32 )
|
bus = Bus( self, 'di({})', 32 )
|
||||||
bitGroup.childs[0].setBusNet( 'i1', bus )
|
bitGroup.childs[0].setBusNet( 'i1', bus )
|
||||||
bitGroup.childs[1].setCmdNet( 'ck', self.getNet( 'clk' ))
|
bitGroup.childs[1].setCmdNet( 'ck', self.getNet( 'clk' ))
|
||||||
omuxGroupsCurr = []
|
self.buildDecoder()
|
||||||
omuxGroupsNext = []
|
#self._buildOutputMux_mx23()
|
||||||
muxDepth = 0
|
self._buildOutputMux_nao23()
|
||||||
for i in range(256//4):
|
#inst = self.addInstance( 'inv_x2'
|
||||||
childs = []
|
# , 'nrst_inv'
|
||||||
for addr in range(i*4, (i+1)*4):
|
# , { 'i' : 'rst'
|
||||||
tag = SRAM_256x32.BIT_GROUP_FMT.format( addr )
|
# , 'nq' : 'n_rst'
|
||||||
childs.append( self.rootGroup.findChild( tag ))
|
# }
|
||||||
childs[-1].unGroup()
|
# )
|
||||||
omuxGroupsCurr.append( self._doMux4( childs, muxDepth ))
|
#self.decoder.addInstance( 0, inst )
|
||||||
while len(omuxGroupsCurr) >= 4:
|
|
||||||
trace( 610, '\tGrouping {} elements.\n'.format( len(omuxGroupsCurr )))
|
|
||||||
muxDepth += 1
|
|
||||||
for i in range(len(omuxGroupsCurr)//4):
|
|
||||||
omuxGroupsNext.append( self._doMux4( omuxGroupsCurr[i*4:(i+1)*4], muxDepth ))
|
|
||||||
omuxGroupsCurr = omuxGroupsNext
|
|
||||||
omuxGroupsNext = []
|
|
||||||
for group in omuxGroupsCurr:
|
|
||||||
self.rootGroup.group( group )
|
|
||||||
inst = self.addInstance( 'inv_x2'
|
inst = self.addInstance( 'inv_x2'
|
||||||
, 'nrst_inv'
|
, 'nce_inv'
|
||||||
, { 'i' : 'rst'
|
, { 'i' : 'ce'
|
||||||
, 'nq' : 'nrst'
|
, 'nq' : 'n_ce'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.decoder.addInstance( 0, inst )
|
self.decoder.addInstance( 0, inst )
|
||||||
for child in self.rootGroup.childs[0].childs:
|
for child in self.rootGroup.childs[0].childs:
|
||||||
if child.kind == Column.KIND_COLUMN:
|
if child.kind == Column.KIND_COLUMN:
|
||||||
if child.insts[0].getMasterCell() != self.mx3Cell:
|
if child.insts[0].getMasterCell() == self.mx3Cell:
|
||||||
continue
|
rstCol = Column( self
|
||||||
rstCol = Column( self
|
, af.getCell( 'a2_x2', CRL.Catalog.State.Views )
|
||||||
, af.getCell( 'a2_x2', CRL.Catalog.State.Views )
|
, 'omux_n_rst'
|
||||||
, 'omux_nrst'
|
, '_byte{byte}_{bbit}'
|
||||||
, '_byte{byte}_{bbit}'
|
, 32 )
|
||||||
, 32 )
|
busOMux = Bus( self, child.tag+'_q({})', 32 )
|
||||||
busOMux = Bus( self, child.tag+'_b_q({})', 32 )
|
busDato = Bus( self, 'dato({})', 32 )
|
||||||
busDato = Bus( self, 'dato({})', 32 )
|
child .setBusNet( 'q' , busOMux )
|
||||||
child .setBusNet( 'q' , busOMux )
|
rstCol.setBusNet( 'i0', busOMux )
|
||||||
rstCol.setBusNet( 'i0', busOMux )
|
rstCol.setCmdNet( 'i1', self.getNet('n_rst') )
|
||||||
rstCol.setCmdNet( 'i1', self.getNet('nrst') )
|
rstCol.setBusNet( 'q' , busDato )
|
||||||
rstCol.setBusNet( 'q' , busDato )
|
self.rootGroup.group( rstCol )
|
||||||
self.rootGroup.group( rstCol )
|
break
|
||||||
self.buildDecoder()
|
omuxRoot = self.rootGroup.findChild( 'omux_0_to_255' )
|
||||||
|
rstCol = Column( self
|
||||||
|
, self.no2Cell
|
||||||
|
, 'omux_rst'
|
||||||
|
, '_byte{byte}_{bbit}'
|
||||||
|
, 32 )
|
||||||
|
busOMux = Bus( self, 'omux_0_to_255_nq({})', 32 )
|
||||||
|
busDato = Bus( self, 'dato({})', 32 )
|
||||||
|
omuxRoot.setBusNet( 'nq', busOMux )
|
||||||
|
rstCol.setBusNet( 'i0', busOMux )
|
||||||
|
rstCol.setCmdNet( 'i1', self.getNet('rst') )
|
||||||
|
rstCol.setBusNet( 'nq', busDato )
|
||||||
|
omuxRoot.parent.group( rstCol, after=omuxRoot )
|
||||||
af.saveCell( self.cell, CRL.Catalog.State.Logical )
|
af.saveCell( self.cell, CRL.Catalog.State.Logical )
|
||||||
|
|
||||||
def _doMux4 ( self, childs, muxDepth ):
|
def _buildOutputMux_nao23 ( self ):
|
||||||
|
"""
|
||||||
|
Build the complete output mux based on successive layers of NAND2
|
||||||
|
then NOR2. More compact than the mux based version.
|
||||||
|
|
||||||
|
Use an "askew" tree to minimize wiring.
|
||||||
|
"""
|
||||||
|
muxDepth = 0
|
||||||
|
levels = [ [], ]
|
||||||
|
for addr in range(256):
|
||||||
|
oneHotName = 'rdecod_' + self._getDecodNetName( addr, 8 ).replace('_n_','_')
|
||||||
|
tag = SRAM_256x32.BIT_GROUP_FMT.format( addr )
|
||||||
|
bitGroup = self.rootGroup.findChild(tag)
|
||||||
|
bitGroup.unGroup()
|
||||||
|
tag = 'sel_' + tag[:-2]
|
||||||
|
nand2Col = Column( self
|
||||||
|
, self.na2Cell
|
||||||
|
, tag
|
||||||
|
, '_byte{byte}_{bbit}'
|
||||||
|
, 32 )
|
||||||
|
nand2Col.setCmdNet( 'i0', self.getNet( oneHotName ))
|
||||||
|
busDff = self.getBus( 'bit_addr{:04d}_q({{}})'.format(addr) )
|
||||||
|
nand2Col.setBusNet( 'i1', busDff )
|
||||||
|
bitGroup.group( nand2Col )
|
||||||
|
levels[0].append( (bitGroup, nand2Col ) )
|
||||||
|
while len(levels[muxDepth]) > 1:
|
||||||
|
levels.append( [] )
|
||||||
|
childIndex = 1 if muxDepth else 2
|
||||||
|
for i in range(len( levels[muxDepth]) // 2 ):
|
||||||
|
naoCell = self.no2Cell if muxDepth%2 else self.na2Cell
|
||||||
|
childs = [ levels[muxDepth][i*2][0], levels[muxDepth][i*2+1][0] ]
|
||||||
|
leftRoot = levels[muxDepth][i*2 ][1]
|
||||||
|
rightRoot = levels[muxDepth][i*2 + 1][1]
|
||||||
|
tags = [ childs[0].tag, childs[1].tag ]
|
||||||
|
naoTag = SRAM_256x32._mergeOMuxTags( tags )
|
||||||
|
naoGroup = ColGroup( naoTag+'_g' )
|
||||||
|
trace( 610, ',+', '\tSRAM_256x32._buildOutputmux() {} + {} -> {}\n' \
|
||||||
|
.format( tags[0], tags[1], naoTag ))
|
||||||
|
nao2Col = Column( self
|
||||||
|
, naoCell
|
||||||
|
, naoTag
|
||||||
|
, '_byte{byte}_{bbit}'
|
||||||
|
, 32 )
|
||||||
|
naoGroup.group( childs[0] )
|
||||||
|
naoGroup.group( childs[1] )
|
||||||
|
bus0 = Bus( self, tags[0][:-2]+'_nq({})', 32 )
|
||||||
|
bus1 = Bus( self, tags[1][:-2]+'_nq({})', 32 )
|
||||||
|
busNao = Bus( self, naoTag+'_nq({})', 32 )
|
||||||
|
leftRoot .setBusNet( 'nq', bus0 )
|
||||||
|
rightRoot.setBusNet( 'nq', bus1 )
|
||||||
|
nao2Col.setBusNet( 'i0', bus0 )
|
||||||
|
nao2Col.setBusNet( 'i1', bus1 )
|
||||||
|
childs[1].reverse()
|
||||||
|
rightRoot.parent.group( nao2Col, before=rightRoot )
|
||||||
|
trace( 610, '\tInsert mux {} before {}\n'.format( nao2Col, rightRoot.parent ))
|
||||||
|
levels[muxDepth+1].append( (naoGroup, nao2Col) )
|
||||||
|
trace( 610, '-,' )
|
||||||
|
muxDepth += 1
|
||||||
|
self.rootGroup.group( levels[muxDepth][0][0] )
|
||||||
|
|
||||||
|
def _buildOutputMux_mx23 ( self ):
|
||||||
|
"""
|
||||||
|
Build the complete output mux based on successive layers of mux4,
|
||||||
|
each mux4 beeing built upon a mux2 + mux3 (_doMux4_mux23).
|
||||||
|
"""
|
||||||
|
omuxGroupsCurr = []
|
||||||
|
omuxGroupsNext = []
|
||||||
|
muxDepth = 0
|
||||||
|
for i in range(256//4):
|
||||||
|
childs = []
|
||||||
|
for addr in range(i*4, (i+1)*4):
|
||||||
|
tag = SRAM_256x32.BIT_GROUP_FMT.format( addr )
|
||||||
|
childs.append( self.rootGroup.findChild( tag ))
|
||||||
|
childs[-1].unGroup()
|
||||||
|
omuxGroupsCurr.append( self._doMux4_mx23( childs, muxDepth ))
|
||||||
|
while len(omuxGroupsCurr) >= 4:
|
||||||
|
trace( 610, '\tGrouping {} elements.\n'.format( len(omuxGroupsCurr )))
|
||||||
|
muxDepth += 1
|
||||||
|
for i in range(len(omuxGroupsCurr)//4):
|
||||||
|
omuxGroupsNext.append( self._doMux4_mx23( omuxGroupsCurr[i*4:(i+1)*4], muxDepth ))
|
||||||
|
omuxGroupsCurr = omuxGroupsNext
|
||||||
|
omuxGroupsNext = []
|
||||||
|
for group in omuxGroupsCurr:
|
||||||
|
self.rootGroup.group( group )
|
||||||
|
|
||||||
|
def _doMux4_mx23 ( self, childs, muxDepth ):
|
||||||
"""
|
"""
|
||||||
Build a 4 entry mux. It uses a mux2 / mux3 combination.
|
Build a 4 entry mux. It uses a mux2 / mux3 combination.
|
||||||
Returns a newly build group.
|
Returns a newly build group.
|
||||||
|
@ -276,7 +402,7 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
mux2Tag = SRAM_256x32._mergeOMuxTags( tags[0:2] )
|
mux2Tag = SRAM_256x32._mergeOMuxTags( tags[0:2] )
|
||||||
mux3Tag = SRAM_256x32._mergeOMuxTags( tags )
|
mux3Tag = SRAM_256x32._mergeOMuxTags( tags )
|
||||||
muxGroup = ColGroup( muxTag+'_g' )
|
muxGroup = ColGroup( muxTag+'_g' )
|
||||||
trace( 610, ',+', '\tSRAM_256x32._doMux4() {} + {} -> {}\n' \
|
trace( 610, ',+', '\tSRAM_256x32._doMux4_mx23() {} + {} -> {}\n' \
|
||||||
.format( mux2Tag, mux3Tag, muxTag ))
|
.format( mux2Tag, mux3Tag, muxTag ))
|
||||||
mux2Col = Column( self
|
mux2Col = Column( self
|
||||||
, self.mx2Cell
|
, self.mx2Cell
|
||||||
|
@ -297,11 +423,11 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
muxGroup.group( childs[2] )
|
muxGroup.group( childs[2] )
|
||||||
muxGroup.group( mux3Col )
|
muxGroup.group( mux3Col )
|
||||||
muxGroup.group( childs[3] )
|
muxGroup.group( childs[3] )
|
||||||
bus0 = Bus( self, tags[0][:-2]+'_b_q({})', 32 )
|
bus0 = Bus( self, tags[0][:-2]+'_q({})', 32 )
|
||||||
bus1 = Bus( self, tags[1][:-2]+'_b_q({})', 32 )
|
bus1 = Bus( self, tags[1][:-2]+'_q({})', 32 )
|
||||||
bus2 = Bus( self, tags[2][:-2]+'_b_q({})', 32 )
|
bus2 = Bus( self, tags[2][:-2]+'_q({})', 32 )
|
||||||
bus3 = Bus( self, tags[3][:-2]+'_b_q({})', 32 )
|
bus3 = Bus( self, tags[3][:-2]+'_q({})', 32 )
|
||||||
busMx2 = Bus( self, mux2Tag+'_b_q({})', 32 )
|
busMx2 = Bus( self, mux2Tag+'_q({})', 32 )
|
||||||
childs[0].childs[ childIndex ].setBusNet( 'q', bus0 )
|
childs[0].childs[ childIndex ].setBusNet( 'q', bus0 )
|
||||||
childs[1].childs[ childIndex ].setBusNet( 'q', bus1 )
|
childs[1].childs[ childIndex ].setBusNet( 'q', bus1 )
|
||||||
childs[2].childs[ childIndex ].setBusNet( 'q', bus2 )
|
childs[2].childs[ childIndex ].setBusNet( 'q', bus2 )
|
||||||
|
@ -331,8 +457,10 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
addrs = []
|
addrs = []
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
end = -2 if tag.endswith('_g') else 0
|
end = -2 if tag.endswith('_g') else 0
|
||||||
if tag.startswith('bit'):
|
if tag.startswith('bit_addr'):
|
||||||
addrs.append( int( tag[8:end] ))
|
addrs.append( int( tag[8:end] ))
|
||||||
|
if tag.startswith('sel_bit_addr'):
|
||||||
|
addrs.append( int( tag[12:end] ))
|
||||||
elif tag.startswith('omux'):
|
elif tag.startswith('omux'):
|
||||||
m = vectorRe.match( tag )
|
m = vectorRe.match( tag )
|
||||||
addrs += [ int(m.group('lsb')), int(m.group('msb')) ]
|
addrs += [ int(m.group('lsb')), int(m.group('msb')) ]
|
||||||
|
@ -397,14 +525,14 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
if addrWidth == 2:
|
if addrWidth == 2:
|
||||||
indexFirstBit = (oneHot >> addrWidth) * addrWidth
|
indexFirstBit = (oneHot >> addrWidth) * addrWidth
|
||||||
valueAddr = oneHot % (1 << addrWidth)
|
valueAddr = oneHot % (1 << addrWidth)
|
||||||
trunkName = self._getDecodNetName( oneHot, addrWidth )
|
trunkName = 'n_'+self._getDecodNetName( oneHot, addrWidth )
|
||||||
instConf.append( 'a2_x2' )
|
instConf.append( self.confLib.getStdCellName('na2_x1') )
|
||||||
instConf.append( 'decod_a2_{}'.format( trunkName ))
|
instConf.append( 'decod_nand2_{}'.format( trunkName ))
|
||||||
instConf.append( {} )
|
instConf.append( {} )
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
inv = '' if (valueAddr & (1 << i)) else 'n_'
|
inv = '' if (valueAddr & (1 << i)) else 'n_'
|
||||||
instConf[2][ 'i{}'.format(i) ] = '{}addr({})'.format( inv, indexFirstBit+i )
|
instConf[2][ 'i{}'.format(i) ] = '{}addr({})'.format( inv, indexFirstBit+i )
|
||||||
instConf[2][ 'q' ] = 'decod_'+trunkName
|
instConf[2][ 'nq' ] = 'decod_'+trunkName
|
||||||
elif addrWidth == 4 or addrWidth == 8:
|
elif addrWidth == 4 or addrWidth == 8:
|
||||||
halfWidth = addrWidth>>1
|
halfWidth = addrWidth>>1
|
||||||
halfMask = 0
|
halfMask = 0
|
||||||
|
@ -413,15 +541,16 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
indexFirstBit = (oneHot >> addrWidth) * addrWidth
|
indexFirstBit = (oneHot >> addrWidth) * addrWidth
|
||||||
valueAddr = oneHot % (1 << addrWidth)
|
valueAddr = oneHot % (1 << addrWidth)
|
||||||
trunkName = self._getDecodNetName( oneHot, addrWidth )
|
trunkName = self._getDecodNetName( oneHot, addrWidth )
|
||||||
instConf.append( 'a2_x2' )
|
gate = 'no2_x1' if addrWidth == 4 else 'na2_x1'
|
||||||
instConf.append( 'decod_a2_{}'.format( trunkName ))
|
instConf.append( self.confLib.getStdCellName(gate) )
|
||||||
|
instConf.append( 'decod_{}_{}'.format( gate[:-3], trunkName ))
|
||||||
instConf.append( {} )
|
instConf.append( {} )
|
||||||
offset = (oneHot >> addrWidth) << (halfWidth+1)
|
offset = (oneHot >> addrWidth) << (halfWidth+1)
|
||||||
oneHot0 = (oneHot & halfMask) + offset
|
oneHot0 = (oneHot & halfMask) + offset
|
||||||
instConf[2][ 'i0' ] = 'decod_'+self._getDecodNetName( oneHot0, halfWidth )
|
instConf[2][ 'i0' ] = 'decod_n_'+self._getDecodNetName( oneHot0, halfWidth )
|
||||||
oneHot1 = ((oneHot >> halfWidth) & halfMask) + (1<<(halfWidth)) + offset
|
oneHot1 = ((oneHot >> halfWidth) & halfMask) + (1<<(halfWidth)) + offset
|
||||||
instConf[2][ 'i1' ] = 'decod_'+self._getDecodNetName( oneHot1, halfWidth )
|
instConf[2][ 'i1' ] = 'decod_n_'+self._getDecodNetName( oneHot1, halfWidth )
|
||||||
instConf[2][ 'q' ] = 'decod_'+trunkName
|
instConf[2][ 'nq' ] = 'decod_n_'+trunkName
|
||||||
trace( 610, '\t{:08b} {:3d}:{} + {:3d}:{} => {:3d}::{:08b}:{}\n' \
|
trace( 610, '\t{:08b} {:3d}:{} + {:3d}:{} => {:3d}::{:08b}:{}\n' \
|
||||||
.format( halfMask
|
.format( halfMask
|
||||||
, oneHot0, self._getDecodNetName( oneHot0, halfWidth )
|
, oneHot0, self._getDecodNetName( oneHot0, halfWidth )
|
||||||
|
@ -449,6 +578,14 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
)
|
)
|
||||||
self.decoder.addInstance( bit * 4, inst )
|
self.decoder.addInstance( bit * 4, inst )
|
||||||
self.connect( 'raddr_sff_{}'.format(bit), 'ck', 'clk' )
|
self.connect( 'raddr_sff_{}'.format(bit), 'ck', 'clk' )
|
||||||
|
for we in range(4):
|
||||||
|
inst = self.addInstance( 'inv_x1'
|
||||||
|
, 'decod_n_we_{}'.format(we)
|
||||||
|
, { 'i' : 'we({})'.format(we)
|
||||||
|
, 'nq' : 'n_we({})'.format(we)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.decoder.addInstance( we*4 + 1, inst )
|
||||||
for bit in range(8):
|
for bit in range(8):
|
||||||
inst = self.addInstance( 'inv_x1'
|
inst = self.addInstance( 'inv_x1'
|
||||||
, 'decod_inv_{}'.format(bit)
|
, 'decod_inv_{}'.format(bit)
|
||||||
|
@ -460,6 +597,7 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
for oneHot in range(16):
|
for oneHot in range(16):
|
||||||
trace( 610, '\t{}\n'.format( self._getDecodNetName(oneHot,2) ))
|
trace( 610, '\t{}\n'.format( self._getDecodNetName(oneHot,2) ))
|
||||||
instDatas = self._getDecodInstConf( oneHot, 2 )
|
instDatas = self._getDecodInstConf( oneHot, 2 )
|
||||||
|
print( instDatas )
|
||||||
inst = self.addInstance( instDatas[0], instDatas[1], instDatas[2] )
|
inst = self.addInstance( instDatas[0], instDatas[1], instDatas[2] )
|
||||||
self.decoder.addInstance( oneHot*2 + 1, inst )
|
self.decoder.addInstance( oneHot*2 + 1, inst )
|
||||||
for oneHot in range(32):
|
for oneHot in range(32):
|
||||||
|
@ -473,21 +611,38 @@ class SRAM_256x32 ( BaseSRAM ):
|
||||||
inst = self.addInstance( instDatas[0], instDatas[1], instDatas[2] )
|
inst = self.addInstance( instDatas[0], instDatas[1], instDatas[2] )
|
||||||
dffCol = self.rootGroup.findChild( bitTag )
|
dffCol = self.rootGroup.findChild( bitTag )
|
||||||
imuxCol = self.rootGroup.findChild( imuxTag )
|
imuxCol = self.rootGroup.findChild( imuxTag )
|
||||||
self.toHeaders.append(( inst, imuxCol.insts[0] ))
|
self.toHeaders.append(( inst, imuxCol.insts[0], 0 ))
|
||||||
for we in range(4):
|
for we in range(4):
|
||||||
cmdNetName = 'decod_addr{:04d}_we({})'.format( oneHot, we )
|
cmdNetName = 'decod_addr{:04d}_we({})'.format( oneHot, we )
|
||||||
inst = self.addInstance( 'a3_x2'
|
inst = self.addInstance( self.confLib.getStdCellName('no3_x1')
|
||||||
, 'decod_a3_we_{}_{}'.format(we,oneHot)
|
, 'decod_no3_we_{}_{}'.format(we,oneHot)
|
||||||
, { 'i0' : instDatas[2]['q']
|
, { 'i0' : instDatas[2]['nq']
|
||||||
, 'i1' : 'ce'
|
, 'i1' : 'n_ce'
|
||||||
, 'i2' : 'we({})'.format(we)
|
, 'i2' : 'n_we({})'.format(we)
|
||||||
, 'q' : cmdNetName
|
, 'nq' : cmdNetName
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.toHeaders.append(( inst, dffCol.insts[0] ))
|
self.toHeaders.append(( inst, imuxCol.insts[0], 0 ))
|
||||||
for bit in range(8):
|
for bit in range(8):
|
||||||
self.connect( 'imux_addr{:04d}_byte{byte}_{bbit}'.format( oneHot, byte=we, bbit=bit )
|
self.connect( 'imux_addr{:04d}_byte{byte}_{bbit}'.format( oneHot, byte=we, bbit=bit )
|
||||||
, 'cmd'
|
, 'cmd'
|
||||||
, cmdNetName
|
, cmdNetName
|
||||||
)
|
)
|
||||||
|
oneHotName = instDatas[2]['nq'].replace('_n_','_')
|
||||||
|
inst = self.addInstance( 'inv_x1'
|
||||||
|
, 'omux_onehot_inv_{:04d}'.format(oneHot)
|
||||||
|
, { 'i' : instDatas[2]['nq']
|
||||||
|
, 'nq' : oneHotName
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.toHeaders.append(( inst, imuxCol.insts[0], 0))
|
||||||
|
sffName = 'omux_onehot_dff_{:04d}'.format(oneHot)
|
||||||
|
inst = self.addInstance( 'sff1_x4'
|
||||||
|
, sffName
|
||||||
|
, { 'i' : oneHotName
|
||||||
|
, 'q' : 'r'+oneHotName
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.connect( sffName, 'ck', 'clk' )
|
||||||
|
self.toHeaders.append(( inst, imuxCol.insts[0], 1 ))
|
||||||
trace( 610, '-,' )
|
trace( 610, '-,' )
|
||||||
|
|
Loading…
Reference in New Issue