2 from __future__
import print_function
12 from helpers
import trace
, l
, u
, n
13 from helpers
.io
import ErrorMessage
, WarningMessage
14 from helpers
.overlay
import UpdateSession
16 from Hurricane
import (Breakpoint
, DataBase
, DbU
, Transformation
,
19 from plugins
.alpha
.block
.matrix
import RegisterMatrix
20 from plugins
.alpha
.macro
.macro
import Macro
21 from plugins
.alpha
.block
.iospecs
import IoSpecs
22 from plugins
.alpha
.block
.block
import Block
23 from plugins
.alpha
.block
.configuration
import IoPin
, GaugeConf
24 from plugins
.alpha
.core2chip
.libresocio
import CoreToChip
25 from plugins
.alpha
.chip
.configuration
import ChipConf
26 from plugins
.alpha
.chip
.chip
import Chip
29 af
= CRL
.AllianceFramework
.get()
33 def isiterable ( pyobj
):
34 if isinstance(pyobj
,collections
.Iterable
): return True
38 def doIoPowerCap ( flags
):
40 side
= flags
& IoPin
.SIDE_MASK
41 if flags
& IoPin
.A_BEGIN
:
42 ioPadPower
= [ (side
, None, 'power_{}'.format(powerCount
), 'vdd' )
43 , (side
, None, 'ground_{}'.format(powerCount
), 'vss' )
44 , (side
, None, 'ioground_{}'.format(powerCount
), 'iovss' )
45 , (side
, None, 'iopower_{}'.format(powerCount
), 'iovdd' )
48 ioPadPower
= [ (side
, None, 'iopower_{}'.format(powerCount
), 'iovdd' )
49 , (side
, None, 'ioground_{}'.format(powerCount
), 'iovss' )
50 , (side
, None, 'ground_{}'.format(powerCount
), 'vss' )
51 , (side
, None, 'power_{}'.format(powerCount
), 'vdd' )
57 def doIoPinVector ( ioSpec
, bits
):
59 if not isiterable(bits
): bits
= range(bits
)
61 raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "bits" is neither a width nor an iterable.'
62 , '(bits={})'.format(bits
)
68 , ioSpec
[2].format(bit
)
69 , ioSpec
[3].format(bit
)
70 , ioSpec
[4].format(bit
) ))
71 elif len(ioSpec
) == 6:
75 , ioSpec
[2].format(bit
)
76 , ioSpec
[3].format(bit
)
77 , ioSpec
[4].format(bit
)
78 , ioSpec
[5].format(bit
) ))
79 elif len(ioSpec
) == 7:
83 , ioSpec
[2].format(bit
)
84 , ioSpec
[3].format(bit
)
85 , ioSpec
[4].format(bit
)
86 , ioSpec
[5].format(bit
)
87 , ioSpec
[6].format(bit
) ))
89 raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "ioSpec" ' \
90 'must have between 5 and 7 ' \
91 'fields ({})'.format(len(ioSpec
))
92 , '(ioSpec={})'.format(ioSpec
)
97 def get_instance_like(cell
, name_contains
, lev
=0):
98 """get_instance_like: returns first instance with the word being searched
100 for inst
in cell
.getInstances():
101 name
= inst
.getName()
102 if name_contains
in name
:
103 print ("\t"*lev
+ "found instance like", name_contains
, inst
, name
)
108 def rgetInstanceLike ( cell
, path
, lev
=0):
110 Get the instance designated by path (recursively). The path argument can be
111 either a string of instance names separated by dots or directly a list of
114 it also "reconstructs" the actual full path name of the instances
117 if isinstance(path
,str):
118 path
= path
.split( '.' )
119 elif not isinstance(path
, list):
120 raise ErrorMessage( 1, 'rgetInstanceLike(): "path" argument is ' \
121 'neither a string or a list ({})"' \
123 # find instance at this level
124 instance
= get_instance_like(cell
, path
[0], lev
)
126 raise ErrorMessage( 1, 'rgetInstanceLike(): no instance "{}" ' \
128 .format(path
[0], cell
.getName()) )
129 iname
= instance
.getName()
130 # last instance (leaf search), return it
132 return instance
, iname
133 # chew down another level, another brick in the wall
134 rinstance
, rname
= rgetInstanceLike(instance
.getMasterCell(),
136 # accumulate the names recursively found "level0.level1.level2..."
137 return rinstance
, "%s.%s" % (iname
, rname
)
140 def rgetInstance ( cell
, path
):
142 Get the instance designated by path (recursively). The path argument can be
143 either a string of instance names separated by dots or directly a list of
146 if isinstance(path
,str):
147 path
= path
.split( '.' )
148 elif not isinstance(path
,list):
149 raise ErrorMessage( 1, 'rgetInstance(): "path" argument is neither ' \
150 'a string or a list ({})"' \
152 instance
= cell
.getInstance( path
[0] )
154 raise ErrorMessage( 1, 'rgetInstance(): no instance "{}" ' \
156 .format(path
[0],cell
.getName()) )
159 return rgetInstance( instance
.getMasterCell(), path
[1:] )
162 def rsetAbutmentBox ( cell
, ab
):
163 for occurrence
in cell
.getNonTerminalNetlistInstanceOccurrences():
164 masterCell
= occurrence
.getEntity().getMasterCell()
165 masterCell
.setAbutmentBox( ab
)
167 def addPllPlaceHolder ( cell
):
168 pllPlaceHolder
= Cell
.create( af
.getLibrary(0), 'pllplaceholder' )
169 pllPlaceHolder
.setAbutmentBox( Box( u(0.0), u(0.0), u(200.0), u(200.0) ))
170 pllPlaceHolder
.setTerminalNetlist( True )
171 instance
= Instance
.create( cell
, 'pllPlaceholder', pllPlaceHolder
)
175 def scriptMain (**kw
):
176 """The mandatory function to be called by Coriolis CGT/Unicorn."""
178 #helpers.setTraceLevel( 550 )
179 #Breakpoint.setStopLevel( 100 )
181 coreSize
= u(375*4.0)
182 chipSize
= u(32*90.0 + 2*214.0)
183 #coreSize = u(17*90.0)
184 #coreSize = u(59*90.0)
185 #chipBorder = u(2*214.0 + 10*13.0) + u(20*90.0)
187 pinmuxFile
= './ls180/litex_pinpads.json'
188 ioSpecs
.loadFromPinmux( pinmuxFile
)
189 # I/O pads, East side.
191 ioPadsSpec
+= doIoPowerCap( IoPin
.EAST|IoPin
.A_BEGIN
)
192 ioPadsSpec
+= doIoPinVector( (IoPin
.EAST
, None, 'sdram_a_{}', 'sdram_a({})', 'sdram_a({})'), 13 )
193 ioPadsSpec
+= doIoPinVector( (IoPin
.EAST
, None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(8,16) )
194 ioPadsSpec
+= [ (IoPin
.EAST
, None, 'jtag_tms', 'jtag_tms', 'jtag_tms' )
195 , (IoPin
.EAST
, None, 'jtag_tdi', 'jtag_tdi', 'jtag_tdi' )
196 , (IoPin
.EAST
, None, 'jtag_tdo', 'jtag_tdo', 'jtag_tdo' )
197 , (IoPin
.EAST
, None, 'jtag_tck', 'jtag_tck', 'jtag_tck' )
199 ioPadsSpec
+= doIoPinVector( (IoPin
.EAST
, None, 'nc_{}', 'nc({})', 'nc({})'), range(4) )
200 ioPadsSpec
+= doIoPowerCap( IoPin
.EAST|IoPin
.A_END
)
201 # I/O pads, West side.
202 ioPadsSpec
+= doIoPowerCap( IoPin
.WEST|IoPin
.A_BEGIN
)
203 # PWM, SDCARD taken out
204 #ioPadsSpec += [ (IoPin.WEST, None, 'pwm_1', 'pwm(1)', 'pwm(1)' ) ]
205 ioPadsSpec
+= doIoPinVector( (IoPin
.WEST
, None, 'eint_{}', 'eint({})', 'eint({})'), 3 )
206 ioPadsSpec
+= [ (IoPin
.WEST
, None, 'spimaster_clk' , 'spimaster_clk' , 'spimaster_clk' )
207 , (IoPin
.WEST
, None, 'spimaster_cs_n', 'spimaster_cs_n', 'spimaster_cs_n' )
208 , (IoPin
.WEST
, None, 'spimaster_mosi', 'spimaster_mosi', 'spimaster_mosi' )
209 , (IoPin
.WEST
, None, 'spimaster_miso', 'spimaster_miso', 'spimaster_miso' )
210 #, (IoPin.WEST , None, 'sdcard_cmd' , 'sdcard_cmd' , 'sdcard_cmd_i', 'sdcard_cmd_oe', 'sdcard_cmd_o' )
211 #, (IoPin.WEST , None, 'sdcard_clk' , 'sdcard_clk' , 'sdcard_clk' )
213 #ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'sdcard_data_{}', 'sdcard_data({})', 'sdcard_data_i({})', 'sdcard_data_oe', 'sdcard_data_o({})'), 4 )
214 ioPadsSpec
+= doIoPinVector( (IoPin
.WEST
, None, 'nc_{}', 'nc({})', 'nc({})'), range(4, 25) )
215 ioPadsSpec
+= doIoPowerCap( IoPin
.WEST|IoPin
.A_END
)
216 # I/O pads, North side.
217 ioPadsSpec
+= doIoPowerCap( IoPin
.NORTH|IoPin
.A_BEGIN
)
218 ioPadsSpec
+= doIoPinVector( (IoPin
.NORTH
, None, 'sdram_dm_{}', 'sdram_dm({})', 'sdram_dm({})'), 2 )
219 ioPadsSpec
+= doIoPinVector( (IoPin
.NORTH
, None, 'sdram_dq_{}', 'sdram_dq({})', 'sdram_dq_i({})', 'sdram_dq_oe', 'sdram_dq_o({})'), range(0,16) )
220 ioPadsSpec
+= doIoPinVector( (IoPin
.NORTH
, None, 'sdram_ba_{}', 'sdram_ba({})', 'sdram_ba({})'), 2 )
221 ioPadsSpec
+= [ (IoPin
.NORTH
, None, 'sdram_clock' , 'sdram_clock' , 'sdram_clock' )
222 , (IoPin
.NORTH
, None, 'sdram_cke' , 'sdram_cke' , 'sdram_cke' )
223 , (IoPin
.NORTH
, None, 'sdram_ras_n' , 'sdram_ras_n' , 'sdram_ras_n' )
224 , (IoPin
.NORTH
, None, 'sdram_cas_n' , 'sdram_cas_n' , 'sdram_cas_n' )
225 , (IoPin
.NORTH
, None, 'sdram_we_n' , 'sdram_we_n' , 'sdram_we_n' )
226 , (IoPin
.NORTH
, None, 'sdram_cs_n' , 'sdram_cs_n' , 'sdram_cs_n' )
228 ioPadsSpec
+= doIoPinVector( (IoPin
.NORTH
, None, 'nc_{}', 'nc({})', 'nc({})'), range(25,27) )
229 ioPadsSpec
+= doIoPowerCap( IoPin
.NORTH|IoPin
.A_END
)
230 # I/O pads, South side.
231 ioPadsSpec
+= doIoPowerCap( IoPin
.SOUTH|IoPin
.A_BEGIN
)
232 ioPadsSpec
+= [ (IoPin
.SOUTH
, None, 'i2c_sda_i' , 'i2c_sda_i' , 'i2c_sda_i' ) ]
233 ioPadsSpec
+= doIoPinVector( (IoPin
.SOUTH
, None, 'nc_{}', 'nc({})', 'nc({})'), range(27,31) )
234 ioPadsSpec
+= [ (IoPin
.SOUTH
, None, 'spisdcard_clk' , 'spisdcard_clk' , 'spisdcard_clk' )
235 , (IoPin
.SOUTH
, None, 'spisdcard_cs_n', 'spisdcard_cs_n', 'spisdcard_cs_n' )
236 , (IoPin
.SOUTH
, None, 'spisdcard_mosi', 'spisdcard_mosi', 'spisdcard_mosi' )
237 , (IoPin
.SOUTH
, None, 'spisdcard_miso', 'spisdcard_miso', 'spisdcard_miso' )
239 ioPadsSpec
+= doIoPinVector( (IoPin
.SOUTH
, None, 'nc_{}', 'nc({})', 'nc({})'), range(31,32) )
240 ioPadsSpec
+= [ (IoPin
.SOUTH
, None, 'uart_tx', 'uart_tx', 'uart_tx' )
241 , (IoPin
.SOUTH
, None, 'uart_rx', 'uart_rx', 'uart_rx' )
243 ioPadsSpec
+= doIoPinVector( (IoPin
.SOUTH
, None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(0,8) )
244 ioPadsSpec
+= [ (IoPin
.SOUTH
, None, 'sys_clk', 'sys_clk', 'sys_clk' )
245 , (IoPin
.SOUTH
, None, 'sys_rst', 'sys_rst', 'sys_rst' )
247 ioPadsSpec
+= doIoPinVector( (IoPin
.SOUTH
, None, 'nc_{}', 'nc({})', 'nc({})'), range(32,33) )
248 ioPadsSpec
+= [ (IoPin
.SOUTH
, None, 'sys_pll_testout_o' , 'sys_pll_testout_o' , 'sys_pll_testout_o' ) ]
249 ioPadsSpec
+= doIoPinVector( (IoPin
.SOUTH
, None, 'sys_clksel_i{}', 'sys_clksel_i({})', 'sys_clksel_i({})'), 2 )
250 ioPadsSpec
+= [ (IoPin
.SOUTH
, None, 'sys_pll_vco_o' , 'sys_pll_vco_o' , 'sys_pll_vco_o' ) ]
251 ioPadsSpec
+= doIoPowerCap( IoPin
.SOUTH|IoPin
.A_END
)
253 cell
, editor
= plugins
.kwParseMain( **kw
)
254 cell
= af
.getCell( 'ls180', CRL
.Catalog
.State
.Logical
)
256 print( ErrorMessage( 2, 'doDesign.scriptMain(): Unable to ' \
260 if editor
: editor
.setCell( cell
)
261 ls180Conf
= ChipConf( cell
, ioPads
=ioSpecs
.ioPadsSpec
)
262 #ls180Conf = ChipConf( cell, ioPads=ioPadsSpec )
263 ls180Conf
.cfg
.etesian
.bloat
= 'nsxlib'
264 ls180Conf
.cfg
.etesian
.uniformDensity
= True
265 ls180Conf
.cfg
.etesian
.aspectRatio
= 1.0
266 ls180Conf
.cfg
.etesian
.spaceMargin
= 0.05
267 ls180Conf
.cfg
.anabatic
.searchHalo
= 2
268 ls180Conf
.cfg
.anabatic
.globalIterations
= 20
269 #ls180Conf.cfg.anabatic.topRoutingLayer = 'metal6'
270 ls180Conf
.cfg
.katana
.hTracksReservedLocal
= 6
271 ls180Conf
.cfg
.katana
.vTracksReservedLocal
= 3
272 ls180Conf
.cfg
.katana
.hTracksReservedMin
= 3
273 ls180Conf
.cfg
.katana
.vTracksReservedMin
= 1
274 ls180Conf
.cfg
.block
.spareSide
= u(7*4.0)
275 ls180Conf
.cfg
.chip
.supplyRailWidth
= u(15)
276 ls180Conf
.cfg
.chip
.supplyRailPitch
= u(45)
277 ls180Conf
.editor
= editor
278 ls180Conf
.useSpares
= True
279 ls180Conf
.useClockTree
= True
280 ls180Conf
.useHFNS
= True
281 ls180Conf
.bColumns
= 2
283 ls180Conf
.chipConf
.name
= 'chip'
284 ls180Conf
.chipConf
.ioPadGauge
= 'LibreSOCIO'
285 ls180Conf
.coreSize
= (coreSize
, coreSize
)
286 # ls180Conf.chipSize = (coreSize + chipBorder, coreSize + chipBorder)
287 ls180Conf
.chipSize
= (chipSize
, chipSize
)
289 with
UpdateSession():
290 sliceHeight
= ls180Conf
.sliceHeight
291 coreAb
= Box( 0, 0, coreSize
, coreSize
)
292 rsetAbutmentBox( cell
, coreAb
)
294 ls180ToChip
= CoreToChip( ls180Conf
)
295 ls180ToChip
.buildChip()
296 chipBuilder
= Chip( ls180Conf
)
297 chipBuilder
.doChipFloorplan()
299 with
UpdateSession():
301 # placement of SRAM blackboxes, manually.
303 # a "search by like" function is used which matches against
304 # the dotted component. brute force and ignorance...
305 tiPath
= 'test_issuer.subckt_1_ti.sram4k_%d.spblock_512w64b8w'
307 sram
= DataBase
.getDB().getCell( 'spblock_512w64b8w' )
309 sramAb
= sram
.getAbutmentBox()
310 coreAb
= cell
.getAbutmentBox()
311 sliceHeight
= chipBuilder
.conf
.sliceHeight
312 originX
= coreAb
.getXMin() + 2*chipBuilder
.conf
.sliceStep
313 sram
, path
= rgetInstanceLike( cell
, tiPath
% i
)
314 print ("found SRAM", sram
, path
)
315 y
= coreAb
.getYMax() - sramAb
.getHeight() - 2*sliceHeight
316 t
= Transformation( originX
318 , Transformation
.Orientation
.ID
)
319 chipBuilder
.placeMacro ( path
, t
)
320 originX
+= sramAb
.getWidth () + 3*sliceHeight
322 print (ErrorMessage( 1, 'SRAM instance %d not found.' % i
))
325 # manual placement of PLL
326 pll
= DataBase
.getDB().getCell( 'pll' )
327 # skip PLL cell for now: Alliance cannot cope with no ports
328 if pll
is None and False:
329 pll
= addPllPlaceHolder( cell
)
331 pllAb
= pll
.getAbutmentBox()
332 t
= Transformation( coreAb
.getXMax() - pllAb
.getWidth()
333 , coreAb
.getYMax() - pllAb
.getHeight()
334 , Transformation
.Orientation
.ID
)
335 pll
.setTransformation( t
)
336 pll
.setPlacementStatus( Instance
.PlacementStatus
.FIXED
)
338 #ls180Conf.placeArea = Box( coreAb.getXMin()
340 # , coreAb.getXMax() -
341 # chipBuilder.conf.sliceStep
342 # , coreAb.getYMax() -
343 # sramAb.getHeight() - 2*sliceHeight
345 #memPatterns = [ r'^mem_(?P<i>\d+)__(?P<j>[\d+])$'
346 # , r'^mem_1_(?P<i>\d+)__(?P<j>[\d+])$'
347 # , r'^mem_2_(?P<i>\d+)__(?P<j>[\d+])$'
348 # , r'^mem_3_(?P<i>\d+)__(?P<j>[\d+])$'
350 #originX += 2*sliceHeight
351 #originY = coreAb.getYMax()
352 #for i in range(len(memPatterns)):
353 # mem = RegisterMatrix( ls180Conf, cell, memPatterns[i] )
354 # originY -= mem.getHeight()
355 # mem.place( Point(originX,originY) )
356 Breakpoint
.stop( 99, 'After core placement.' )
358 rvalue
= chipBuilder
.doPnR()
360 CRL
.Gds
.save( ls180Conf
.chip
)