use --recursive on git submodule not --remote - one does a "latest update"
[soclayout.git] / experiments9 / freepdk_c4m45 / doDesign.py
1
2 from __future__ import print_function
3
4 import os
5 import re
6 import json
7 import sys
8 import traceback
9 import collections
10 import CRL
11 import helpers
12 from helpers import trace, l, u, n
13 from helpers.io import ErrorMessage, WarningMessage
14 from helpers.overlay import UpdateSession
15 import plugins
16 from Hurricane import (Breakpoint, DataBase, DbU, Transformation,
17 Point, Box,
18 Cell, Instance)
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
27
28
29 af = CRL.AllianceFramework.get()
30 powerCount = 0
31
32
33 def isiterable ( pyobj ):
34 if isinstance(pyobj,collections.Iterable): return True
35 return False
36
37
38 def doIoPowerCap ( flags ):
39 global powerCount
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' )
46 ]
47 else:
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' )
52 ]
53 powerCount += 1
54 return ioPadPower
55
56
57 def doIoPinVector ( ioSpec, bits ):
58 v = []
59 if not isiterable(bits): bits = range(bits)
60 if not bits:
61 raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "bits" is neither a width nor an iterable.'
62 , '(bits={})'.format(bits)
63 ] )
64 if len(ioSpec) == 5:
65 for bit in bits:
66 v.append(( ioSpec[0]
67 , ioSpec[1]
68 , ioSpec[2].format(bit)
69 , ioSpec[3].format(bit)
70 , ioSpec[4].format(bit) ))
71 elif len(ioSpec) == 6:
72 for bit in bits:
73 v.append(( ioSpec[0]
74 , ioSpec[1]
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:
80 for bit in bits:
81 v.append(( ioSpec[0]
82 , ioSpec[1]
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) ))
88 else:
89 raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "ioSpec" ' \
90 'must have between 5 and 7 ' \
91 'fields ({})'.format(len(ioSpec))
92 , '(ioSpec={})'.format(ioSpec)
93 ] )
94 return v
95
96
97 def get_instance_like(cell, name_contains, lev=0):
98 """get_instance_like: returns first instance with the word being searched
99 """
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)
104 return inst
105
106 return None
107
108 def rgetInstanceLike ( cell, path, lev=0):
109 """
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
112 instances names.
113
114 it also "reconstructs" the actual full path name of the instances
115 found recursively.
116 """
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 ({})"' \
122 .format(path) )
123 # find instance at this level
124 instance = get_instance_like(cell, path[0], lev)
125 if instance is None:
126 raise ErrorMessage( 1, 'rgetInstanceLike(): no instance "{}" ' \
127 'in cell "{}"' \
128 .format(path[0], cell.getName()) )
129 iname = instance.getName()
130 # last instance (leaf search), return it
131 if len(path) == 1:
132 return instance, iname
133 # chew down another level, another brick in the wall
134 rinstance, rname = rgetInstanceLike(instance.getMasterCell(),
135 path[1:], lev+1)
136 # accumulate the names recursively found "level0.level1.level2..."
137 return rinstance, "%s.%s" % (iname, rname)
138
139
140 def rgetInstance ( cell, path ):
141 """
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
144 instances names.
145 """
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 ({})"' \
151 .format(path) )
152 instance = cell.getInstance( path[0] )
153 if instance is None:
154 raise ErrorMessage( 1, 'rgetInstance(): no instance "{}" ' \
155 'in cell "{}"' \
156 .format(path[0],cell.getName()) )
157 if len(path) == 1:
158 return instance
159 return rgetInstance( instance.getMasterCell(), path[1:] )
160
161
162 def rsetAbutmentBox ( cell, ab ):
163 for occurrence in cell.getNonTerminalNetlistInstanceOccurrences():
164 masterCell = occurrence.getEntity().getMasterCell()
165 masterCell.setAbutmentBox( ab )
166
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 )
172 return instance
173
174
175 def scriptMain (**kw):
176 """The mandatory function to be called by Coriolis CGT/Unicorn."""
177 global af
178 #helpers.setTraceLevel( 550 )
179 #Breakpoint.setStopLevel( 100 )
180 rvalue = True
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)
186 ioSpecs = IoSpecs()
187 pinmuxFile = './ls180/litex_pinpads.json'
188 ioSpecs.loadFromPinmux( pinmuxFile )
189 # I/O pads, East side.
190 ioPadsSpec = []
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' )
198 ]
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' )
212 ]
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' )
227 ]
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' )
238 ]
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' )
242 ]
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' )
246 ]
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 )
252 try:
253 cell, editor = plugins.kwParseMain( **kw )
254 cell = af.getCell( 'ls180', CRL.Catalog.State.Logical )
255 if cell is None:
256 print( ErrorMessage( 2, 'doDesign.scriptMain(): Unable to ' \
257 ' load cell "{}".' \
258 .format('ls180') ))
259 sys.exit(1)
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
282 ls180Conf.bRows = 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)
288
289 with UpdateSession():
290 sliceHeight = ls180Conf.sliceHeight
291 coreAb = Box( 0, 0, coreSize, coreSize )
292 rsetAbutmentBox( cell, coreAb )
293
294 ls180ToChip = CoreToChip( ls180Conf )
295 ls180ToChip.buildChip()
296 chipBuilder = Chip( ls180Conf )
297 chipBuilder.doChipFloorplan()
298
299 with UpdateSession():
300 #######
301 # placement of SRAM blackboxes, manually.
302
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'
306 for i in range(4):
307 sram = DataBase.getDB().getCell( 'spblock_512w64b8w' )
308 if sram:
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
317 , y
318 , Transformation.Orientation.ID )
319 chipBuilder.placeMacro ( path, t )
320 originX += sramAb.getWidth () + 3*sliceHeight
321 else:
322 print (ErrorMessage( 1, 'SRAM instance %d not found.' % i))
323
324 #########
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 )
330 if pll:
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 )
337
338 #ls180Conf.placeArea = Box( coreAb.getXMin()
339 # , coreAb.getYMin()
340 # , coreAb.getXMax() -
341 # chipBuilder.conf.sliceStep
342 # , coreAb.getYMax() -
343 # sramAb.getHeight() - 2*sliceHeight
344 # )
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+])$'
349 # ]
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.' )
357
358 rvalue = chipBuilder.doPnR()
359 chipBuilder.save()
360 CRL.Gds.save( ls180Conf.chip )
361 except Exception, e:
362 helpers.io.catch(e)
363 rvalue = False
364 sys.stdout.flush()
365 sys.stderr.flush()
366 return rvalue