also add blackboxes spblock512* etc.
[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 rgetInstance ( cell, path ):
98 """
99 Get the instance designated by path (recursively). The path argument can be
100 either a string of instance names separated by dots or directly a list of
101 instances names.
102 """
103 if isinstance(path,str):
104 path = path.split( '.' )
105 elif not isinstance(path,list):
106 raise ErrorMessage( 1, 'rgetInstance(): "path" argument is neither ' \
107 'a string or a list ({})"' \
108 .format(path) )
109 instance = cell.getInstance( path[0] )
110 if instance is None:
111 raise ErrorMessage( 1, 'rgetInstance(): no instance "{}" ' \
112 'in cell "{}"' \
113 .format(path[0],cell.getName()) )
114 if len(path) == 1:
115 return instance
116 return rgetInstance( instance.getMasterCell(), path[1:] )
117
118
119 def rsetAbutmentBox ( cell, ab ):
120 for occurrence in cell.getNonTerminalNetlistInstanceOccurrences():
121 masterCell = occurrence.getEntity().getMasterCell()
122 masterCell.setAbutmentBox( ab )
123
124 def addPllPlaceHolder ( cell ):
125 pllPlaceHolder = Cell.create( af.getLibrary(0), 'pllplaceholder' )
126 pllPlaceHolder.setAbutmentBox( Box( u(0.0), u(0.0), u(200.0), u(200.0) ))
127 pllPlaceHolder.setTerminalNetlist( True )
128 instance = Instance.create( cell, 'pllPlaceholder', pllPlaceHolder )
129 return instance
130
131
132 def scriptMain (**kw):
133 """The mandatory function to be called by Coriolis CGT/Unicorn."""
134 global af
135 #helpers.setTraceLevel( 550 )
136 #Breakpoint.setStopLevel( 100 )
137 rvalue = True
138 coreSize = u(375*4.0)
139 chipSize = u(32*90.0 + 2*214.0)
140 #coreSize = u(17*90.0)
141 #coreSize = u(59*90.0)
142 #chipBorder = u(2*214.0 + 10*13.0) + u(20*90.0)
143 ioSpecs = IoSpecs()
144 pinmuxFile = './ls180/litex_pinpads.json'
145 ioSpecs.loadFromPinmux( pinmuxFile )
146 # I/O pads, East side.
147 ioPadsSpec = []
148 ioPadsSpec += doIoPowerCap( IoPin.EAST|IoPin.A_BEGIN )
149 ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'sdram_a_{}', 'sdram_a({})', 'sdram_a({})'), 13 )
150 ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(8,16) )
151 ioPadsSpec += [ (IoPin.EAST , None, 'jtag_tms', 'jtag_tms', 'jtag_tms' )
152 , (IoPin.EAST , None, 'jtag_tdi', 'jtag_tdi', 'jtag_tdi' )
153 , (IoPin.EAST , None, 'jtag_tdo', 'jtag_tdo', 'jtag_tdo' )
154 , (IoPin.EAST , None, 'jtag_tck', 'jtag_tck', 'jtag_tck' )
155 ]
156 ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'nc_{}', 'nc({})', 'nc({})'), range(4) )
157 ioPadsSpec += doIoPowerCap( IoPin.EAST|IoPin.A_END )
158 # I/O pads, West side.
159 ioPadsSpec += doIoPowerCap( IoPin.WEST|IoPin.A_BEGIN )
160 # PWM, SDCARD taken out
161 #ioPadsSpec += [ (IoPin.WEST, None, 'pwm_1', 'pwm(1)', 'pwm(1)' ) ]
162 ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'eint_{}', 'eint({})', 'eint({})'), 3 )
163 ioPadsSpec += [ (IoPin.WEST , None, 'spimaster_clk' , 'spimaster_clk' , 'spimaster_clk' )
164 , (IoPin.WEST , None, 'spimaster_cs_n', 'spimaster_cs_n', 'spimaster_cs_n' )
165 , (IoPin.WEST , None, 'spimaster_mosi', 'spimaster_mosi', 'spimaster_mosi' )
166 , (IoPin.WEST , None, 'spimaster_miso', 'spimaster_miso', 'spimaster_miso' )
167 #, (IoPin.WEST , None, 'sdcard_cmd' , 'sdcard_cmd' , 'sdcard_cmd_i', 'sdcard_cmd_oe', 'sdcard_cmd_o' )
168 #, (IoPin.WEST , None, 'sdcard_clk' , 'sdcard_clk' , 'sdcard_clk' )
169 ]
170 #ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'sdcard_data_{}', 'sdcard_data({})', 'sdcard_data_i({})', 'sdcard_data_oe', 'sdcard_data_o({})'), 4 )
171 ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'nc_{}', 'nc({})', 'nc({})'), range(4, 25) )
172 ioPadsSpec += doIoPowerCap( IoPin.WEST|IoPin.A_END )
173 # I/O pads, North side.
174 ioPadsSpec += doIoPowerCap( IoPin.NORTH|IoPin.A_BEGIN )
175 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_dm_{}', 'sdram_dm({})', 'sdram_dm({})'), 2 )
176 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_dq_{}', 'sdram_dq({})', 'sdram_dq_i({})', 'sdram_dq_oe', 'sdram_dq_o({})'), range(0,16) )
177 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_ba_{}', 'sdram_ba({})', 'sdram_ba({})'), 2 )
178 ioPadsSpec += [ (IoPin.NORTH, None, 'sdram_clock' , 'sdram_clock' , 'sdram_clock' )
179 , (IoPin.NORTH, None, 'sdram_cke' , 'sdram_cke' , 'sdram_cke' )
180 , (IoPin.NORTH, None, 'sdram_ras_n' , 'sdram_ras_n' , 'sdram_ras_n' )
181 , (IoPin.NORTH, None, 'sdram_cas_n' , 'sdram_cas_n' , 'sdram_cas_n' )
182 , (IoPin.NORTH, None, 'sdram_we_n' , 'sdram_we_n' , 'sdram_we_n' )
183 , (IoPin.NORTH, None, 'sdram_cs_n' , 'sdram_cs_n' , 'sdram_cs_n' )
184 ]
185 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(25,27) )
186 ioPadsSpec += doIoPowerCap( IoPin.NORTH|IoPin.A_END )
187 # I/O pads, South side.
188 ioPadsSpec += doIoPowerCap( IoPin.SOUTH|IoPin.A_BEGIN )
189 ioPadsSpec += [ (IoPin.SOUTH, None, 'i2c_sda_i' , 'i2c_sda_i' , 'i2c_sda_i' ) ]
190 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(27,31) )
191 ioPadsSpec += [ (IoPin.SOUTH, None, 'spisdcard_clk' , 'spisdcard_clk' , 'spisdcard_clk' )
192 , (IoPin.SOUTH, None, 'spisdcard_cs_n', 'spisdcard_cs_n', 'spisdcard_cs_n' )
193 , (IoPin.SOUTH, None, 'spisdcard_mosi', 'spisdcard_mosi', 'spisdcard_mosi' )
194 , (IoPin.SOUTH, None, 'spisdcard_miso', 'spisdcard_miso', 'spisdcard_miso' )
195 ]
196 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(31,32) )
197 ioPadsSpec += [ (IoPin.SOUTH, None, 'uart_tx', 'uart_tx', 'uart_tx' )
198 , (IoPin.SOUTH, None, 'uart_rx', 'uart_rx', 'uart_rx' )
199 ]
200 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(0,8) )
201 ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_clk', 'sys_clk', 'sys_clk' )
202 , (IoPin.SOUTH, None, 'sys_rst', 'sys_rst', 'sys_rst' )
203 ]
204 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(32,33) )
205 ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_pll_18_o' , 'sys_pll_18_o' , 'sys_pll_18_o' ) ]
206 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'sys_clksel_i{}', 'sys_clksel_i({})', 'sys_clksel_i({})'), 2 )
207 ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_pll_lck_o' , 'sys_pll_lck_o' , 'sys_pll_lck_o' ) ]
208 ioPadsSpec += doIoPowerCap( IoPin.SOUTH|IoPin.A_END )
209 try:
210 cell, editor = plugins.kwParseMain( **kw )
211 cell = af.getCell( 'ls180', CRL.Catalog.State.Logical )
212 if cell is None:
213 print( ErrorMessage( 2, 'doDesign.scriptMain(): Unable to ' \
214 ' load cell "{}".' \
215 .format('ls180') ))
216 sys.exit(1)
217 if editor: editor.setCell( cell )
218 ls180Conf = ChipConf( cell, ioPads=ioSpecs.ioPadsSpec )
219 #ls180Conf = ChipConf( cell, ioPads=ioPadsSpec )
220 ls180Conf.cfg.etesian.bloat = 'nsxlib'
221 ls180Conf.cfg.etesian.uniformDensity = True
222 ls180Conf.cfg.etesian.aspectRatio = 1.0
223 ls180Conf.cfg.etesian.spaceMargin = 0.05
224 ls180Conf.cfg.anabatic.searchHalo = 2
225 ls180Conf.cfg.anabatic.globalIterations = 20
226 #ls180Conf.cfg.anabatic.topRoutingLayer = 'metal6'
227 ls180Conf.cfg.katana.hTracksReservedLocal = 6
228 ls180Conf.cfg.katana.vTracksReservedLocal = 3
229 ls180Conf.cfg.katana.hTracksReservedMin = 3
230 ls180Conf.cfg.katana.vTracksReservedMin = 1
231 ls180Conf.cfg.block.spareSide = u(7*4.0)
232 ls180Conf.cfg.chip.supplyRailWidth = u(15)
233 ls180Conf.cfg.chip.supplyRailPitch = u(45)
234 ls180Conf.editor = editor
235 ls180Conf.useSpares = True
236 ls180Conf.useClockTree = True
237 ls180Conf.useHFNS = True
238 ls180Conf.bColumns = 2
239 ls180Conf.bRows = 2
240 ls180Conf.chipConf.name = 'chip'
241 ls180Conf.chipConf.ioPadGauge = 'LibreSOCIO'
242 ls180Conf.coreSize = (coreSize, coreSize)
243 # ls180Conf.chipSize = (coreSize + chipBorder, coreSize + chipBorder)
244 ls180Conf.chipSize = (chipSize, chipSize)
245
246 with UpdateSession():
247 sliceHeight = ls180Conf.sliceHeight
248 coreAb = Box( 0, 0, coreSize, coreSize )
249 rsetAbutmentBox( cell, coreAb )
250
251 ls180ToChip = CoreToChip( ls180Conf )
252 ls180ToChip.buildChip()
253 chipBuilder = Chip( ls180Conf )
254 chipBuilder.doChipFloorplan()
255
256 with UpdateSession():
257 #######
258 # placement of SRAM blackboxes, manually
259
260 # Thoses ids are dependent on Yosys. They need to be adjusted
261 # whenever the design changes.
262 tiId = 38695
263 tiId = 38381
264 sramId = 3695
265 sramId = 3300
266 tiPath = 'subckt_{}_test_issuer.subckt_1_ti.'.format(tiId)
267 sramPaths = [ tiPath+'subckt_{}_sram4k_0.subckt_144_SPBlock_512W64B8W'.format(sramId)
268 , tiPath+'subckt_{}_sram4k_1.subckt_144_SPBlock_512W64B8W'.format(sramId+1)
269 , tiPath+'subckt_{}_sram4k_2.subckt_144_SPBlock_512W64B8W'.format(sramId+2)
270 , tiPath+'subckt_{}_sram4k_3.subckt_144_SPBlock_512W64B8W'.format(sramId+3)
271 ]
272 # each sram is named differently (yosys blackbox issue)
273 for i in range(4):
274 sram = DataBase.getDB().getCell( 'spblock512w64b8w_%i' )
275 if sram:
276 sramAb = sram.getAbutmentBox()
277 coreAb = cell.getAbutmentBox()
278 sliceHeight = chipBuilder.conf.sliceHeight
279 originX = coreAb.getXMin() + 2*chipBuilder.conf.sliceStep
280 sram = rgetInstance( cell, sramPaths[i] )
281 y = coreAb.getYMax() - sramAb.getHeight() - 2*sliceHeight
282 t = Transformation( originX
283 , y
284 , Transformation.Orientation.ID )
285 chipBuilder.placeMacro ( sramPaths[i], t )
286 originX += sramAb.getWidth () + 3*sliceHeight
287 else:
288 print (ErrorMessage( 1, 'SRAM instance %d not found.' % i))
289
290 #########
291 # manual placement of PLL
292 pll = DataBase.getDB().getCell( 'pll' )
293 # skip PLL cell for now: Alliance cannot cope with no ports
294 if pll is None and False:
295 pll = addPllPlaceHolder( cell )
296 if pll:
297 pllAb = pll.getAbutmentBox()
298 t = Transformation( coreAb.getXMax() - pllAb.getWidth()
299 , coreAb.getYMax() - pllAb.getHeight()
300 , Transformation.Orientation.ID )
301 pll.setTransformation( t )
302 pll.setPlacementStatus( Instance.PlacementStatus.FIXED )
303
304 #ls180Conf.placeArea = Box( coreAb.getXMin()
305 # , coreAb.getYMin()
306 # , coreAb.getXMax() -
307 # chipBuilder.conf.sliceStep
308 # , coreAb.getYMax() -
309 # sramAb.getHeight() - 2*sliceHeight
310 # )
311 #memPatterns = [ r'^mem_(?P<i>\d+)__(?P<j>[\d+])$'
312 # , r'^mem_1_(?P<i>\d+)__(?P<j>[\d+])$'
313 # , r'^mem_2_(?P<i>\d+)__(?P<j>[\d+])$'
314 # , r'^mem_3_(?P<i>\d+)__(?P<j>[\d+])$'
315 # ]
316 #originX += 2*sliceHeight
317 #originY = coreAb.getYMax()
318 #for i in range(len(memPatterns)):
319 # mem = RegisterMatrix( ls180Conf, cell, memPatterns[i] )
320 # originY -= mem.getHeight()
321 # mem.place( Point(originX,originY) )
322 Breakpoint.stop( 99, 'After core placement.' )
323
324 rvalue = chipBuilder.doPnR()
325 chipBuilder.save()
326 CRL.Gds.save( ls180Conf.chip )
327 except Exception, e:
328 helpers.io.catch(e)
329 rvalue = False
330 sys.stdout.flush()
331 sys.stderr.flush()
332 return rvalue