Enable the heavy leaf load on the main clock.
[soclayout.git] / experiments9 / tsmc_c018 / 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, Point, Box, \
17 Cell, Instance
18 from plugins.alpha.block.matrix import RegisterMatrix
19 from plugins.alpha.macro.macro import Macro
20 from plugins.alpha.block.iospecs import IoSpecs
21 from plugins.alpha.block.block import Block
22 from plugins.alpha.block.configuration import IoPin, GaugeConf
23 from plugins.alpha.block.spares import Spares
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 #from plugins.alpha.utils import rgetInstanceMatching
28
29
30 af = CRL.AllianceFramework.get()
31 powerCount = 0
32 placeHolderCount = 0
33
34
35 def onGrid ( v ):
36 twoGrid = DbU.fromGrid( 2 )
37 modulo = v % twoGrid
38 if modulo:
39 v += twoGrid - modulo
40 return v
41
42
43 def isiterable ( pyobj ):
44 if isinstance(pyobj,collections.Iterable): return True
45 return False
46
47
48 def doIoPowerCap ( flags ):
49 global powerCount
50 side = flags & IoPin.SIDE_MASK
51 if flags & IoPin.A_BEGIN:
52 ioPadPower = [ (side , None, 'power_{}'.format(powerCount), 'vdd' )
53 , (side , None, 'ground_{}'.format(powerCount), 'vss' )
54 , (side , None, 'ioground_{}'.format(powerCount), 'vss' )
55 , (side , None, 'iopower_{}'.format(powerCount), 'iovdd' )
56 ]
57 else:
58 ioPadPower = [ (side , None, 'iopower_{}'.format(powerCount), 'iovdd' )
59 , (side , None, 'ioground_{}'.format(powerCount), 'vss' )
60 , (side , None, 'ground_{}'.format(powerCount), 'vss' )
61 , (side , None, 'power_{}'.format(powerCount), 'vdd' )
62 ]
63 powerCount += 1
64 return ioPadPower
65
66
67 def doIoPinVector ( ioSpec, bits ):
68 v = []
69 if not isiterable(bits): bits = range(bits)
70 if not bits:
71 raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "bits" is neither a width nor an iterable.'
72 , '(bits={})'.format(bits)
73 ] )
74 if len(ioSpec) == 5:
75 for bit in bits:
76 v.append(( ioSpec[0]
77 , ioSpec[1]
78 , ioSpec[2].format(bit)
79 , ioSpec[3].format(bit)
80 , ioSpec[4].format(bit) ))
81 elif len(ioSpec) == 6:
82 for bit in bits:
83 v.append(( ioSpec[0]
84 , ioSpec[1]
85 , ioSpec[2].format(bit)
86 , ioSpec[3].format(bit)
87 , ioSpec[4].format(bit)
88 , ioSpec[5].format(bit) ))
89 elif len(ioSpec) == 7:
90 for bit in bits:
91 v.append(( ioSpec[0]
92 , ioSpec[1]
93 , ioSpec[2].format(bit)
94 , ioSpec[3].format(bit)
95 , ioSpec[4].format(bit)
96 , ioSpec[5].format(bit)
97 , ioSpec[6].format(bit) ))
98 else:
99 raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "ioSpec" must have between 5 and 7 fields ({})'.format(len(ioSpec))
100 , '(ioSpec={})'.format(ioSpec)
101 ] )
102 return v
103
104
105 def rgetInstance ( cell, path ):
106 """
107 Get the instance designated by path (recursively). The path argument can be
108 either a string of instance names separated by dots or directly a list of
109 instances names.
110 """
111 if isinstance(path,str):
112 path = path.split( '.' )
113 elif not isinstance(path,list):
114 raise ErrorMessage( 1, 'rgetInstance(): "path" argument is neither a string or a list ({})"' \
115 .format(path) )
116 instance = cell.getInstance( path[0] )
117 if instance is None:
118 raise ErrorMessage( 1, 'rgetInstance(): no instance "{}" in cell "{}"' \
119 .format(path[0],cell.getName()) )
120 if len(path) == 1:
121 return instance
122 return rgetInstance( instance.getMasterCell(), path[1:] )
123
124
125 def rsetAbutmentBox ( cell, ab ):
126 for occurrence in cell.getNonTerminalNetlistInstanceOccurrences():
127 masterCell = occurrence.getEntity().getMasterCell()
128 masterCell.setAbutmentBox( ab )
129
130
131 def scriptMain (**kw):
132 """The mandatory function to be called by Coriolis CGT/Unicorn."""
133 global af
134 #helpers.setTraceLevel( 550 )
135 #Breakpoint.setStopLevel( 100 )
136 rvalue = True
137 coreSizeX = u(51*90.0)
138 coreSizeY = u(56*90.0)
139 chipBorder = u(2*214.0 + 8*13.0)
140 ioSpecs = IoSpecs()
141
142 # this should work fine, tested on nsxlib
143 cwd = os.path.split(os.path.abspath(__file__))[0]
144 pinmuxFile = '%s/non_generated/litex_pinpads.json' % cwd
145 # actual contents auto-generated and listed at:
146 # http://libre-soc.org/180nm_Oct2020/ls180/
147 ioSpecs.loadFromPinmux( pinmuxFile )
148
149 # XXX ioPadsSpec created but not used. saves time, saves errors. see
150 # wiki page for contents: http://libre-soc.org/180nm_Oct2020/ls180/
151 # if *not* using the auto-generated ioSpecs, ioPadsSpec should, really,
152 # be made exactly the same. which is more work.
153
154 # I/O pads, East side.
155 ioPadsSpec = []
156 ioPadsSpec += doIoPowerCap( IoPin.EAST|IoPin.A_BEGIN )
157 ioPadsSpec += [ (IoPin.EAST, None, 'sdram_cas_n' , 'sdram_cas_n' , 'sdram_cas_n' )
158 , (IoPin.EAST, None, 'sdram_we_n' , 'sdram_we_n' , 'sdram_we_n' )
159 , (IoPin.EAST, None, 'sdram_cs_n' , 'sdram_cs_n' , 'sdram_cs_n' )
160 ]
161 ioPadsSpec += doIoPinVector( (IoPin.EAST, None, 'sdram_a_{}' , 'sdram_a({})' , 'sdram_a({})'), 13 )
162 ioPadsSpec += doIoPinVector( (IoPin.EAST, None, 'sdram_ba_{}', 'sdram_ba({})', 'sdram_ba({})'), 2 )
163 ioPadsSpec += doIoPinVector( (IoPin.EAST, None, 'sdram_dm_{}', 'sdram_dm({})', 'sdram_dm({})'), 2 )
164 ioPadsSpec += doIoPinVector( (IoPin.EAST, None, 'nc_{}', 'nc({})', 'nc({})'), range(0,2) )
165 ioPadsSpec += doIoPowerCap( IoPin.EAST|IoPin.A_END )
166 ioPadsSpec += [ (IoPin.EAST , None, 'sys_pll_testout_o', 'sys_pll_testout_o', 'sys_pll_testout_o' )
167 , (IoPin.EAST|IoPin.ANALOG, None, 'sys_pll_vco_o' , 'sys_pll_vco_o' , 'sys_pll_vco_o' )
168 ]
169
170 # I/O pads, North side.
171 ioPadsSpec += doIoPowerCap( IoPin.NORTH|IoPin.A_BEGIN )
172 ioPadsSpec += [ (IoPin.NORTH, None, 'jtag_tms' , 'jtag_tms' , 'jtag_tms' )
173 , (IoPin.NORTH, None, 'jtag_tdi' , 'jtag_tdi' , 'jtag_tdi' )
174 , (IoPin.NORTH, None, 'jtag_tdo' , 'jtag_tdo' , 'jtag_tdo' )
175 , (IoPin.NORTH, None, 'jtag_tck' , 'jtag_tck' , 'jtag_tck' )
176 ]
177 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(2,19) )
178 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_dq_{}', 'sdram_dq({})', 'sdram_dq_i({})', 'sdram_dq_oe({})', 'sdram_dq_o({})'), range(0,16) )
179 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sys_clksel_i{}', 'sys_clksel_i({})', 'sys_clksel_i({})'), 2 )
180 ioPadsSpec += [ (IoPin.NORTH, None, 'sys_clk' , 'sys_clk' , 'sys_clk' ) ]
181 ioPadsSpec += doIoPowerCap( IoPin.NORTH|IoPin.A_END )
182
183 # I/O pads, West side.
184 ioPadsSpec += doIoPowerCap( IoPin.WEST|IoPin.A_BEGIN )
185 ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'nc_{}', ' nc({})', 'nc({})'), range(19,36) )
186 ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'eint_{}', 'eint_{}', 'eint_{}'), 3 )
187 ioPadsSpec += [ (IoPin.WEST , None, 'spimaster_clk' , 'spimaster_clk' , 'spimaster_clk' )
188 , (IoPin.WEST , None, 'spimaster_cs_n', 'spimaster_cs_n', 'spimaster_cs_n' )
189 , (IoPin.WEST , None, 'spimaster_mosi', 'spimaster_mosi', 'spimaster_mosi' )
190 , (IoPin.WEST , None, 'spimaster_miso', 'spimaster_miso', 'spimaster_miso' )
191 ]
192 ioPadsSpec += doIoPowerCap( IoPin.WEST|IoPin.A_END )
193
194 # I/O pads, South side.
195 ioPadsSpec += doIoPowerCap( IoPin.SOUTH|IoPin.A_BEGIN )
196 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(0,16) )
197 ioPadsSpec += [ (IoPin.SOUTH, None, 'i2c_sda_i' , 'i2c_sda_i' , 'i2c_sda_i', 'i2c_sda_oe', 'i2c_sda_o' ) ]
198 ioPadsSpec += [ (IoPin.SOUTH, None, 'i2c_scl' , 'i2c_scl' , 'i2c_scl' ) ]
199 ioPadsSpec += [ (IoPin.SOUTH, None, 'uart_tx', 'uart_tx', 'uart_tx' )
200 , (IoPin.SOUTH, None, 'uart_rx', 'uart_rx', 'uart_rx' )
201 , (IoPin.SOUTH, None, 'sys_rst', 'sys_rst', 'sys_rst' )
202 ]
203 ioPadsSpec += [ (IoPin.SOUTH, None, 'sdram_clock' , 'sdram_clock' , 'sdram_clock' )
204 , (IoPin.SOUTH, None, 'sdram_cke' , 'sdram_cke' , 'sdram_cke' )
205 , (IoPin.SOUTH, None, 'sdram_ras_n' , 'sdram_ras_n' , 'sdram_ras_n' )
206 ]
207 ioPadsSpec += doIoPowerCap( IoPin.SOUTH|IoPin.A_END )
208
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 load cell "{}".' \
214 .format('ls180') ))
215 sys.exit(1)
216 if editor: editor.setCell( cell )
217 # use auto-generated (but from non_generated) io pads specs
218 # works fine with soclayout nsxlib, should work perfectly fine
219 # here, too
220 ls180Conf = ChipConf( cell, ioPads=ioSpecs.ioPadsSpec )
221 #ls180Conf = ChipConf( cell, ioPads=ioPadsSpec )
222 ls180Conf.cfg.etesian.bloat = 'Flexlib'
223 ls180Conf.cfg.etesian.uniformDensity = True
224 ls180Conf.cfg.etesian.aspectRatio = 1.0
225 ls180Conf.cfg.etesian.spaceMargin = 0.05
226 ls180Conf.cfg.anabatic.searchHalo = 3
227 ls180Conf.cfg.anabatic.globalIterations = 20
228 ls180Conf.cfg.anabatic.topRoutingLayer = 'METAL5'
229 ls180Conf.cfg.katana.hTracksReservedLocal = 11
230 ls180Conf.cfg.katana.vTracksReservedLocal = 8
231 ls180Conf.cfg.katana.hTracksReservedMin = 9
232 ls180Conf.cfg.katana.vTracksReservedMin = 6
233 ls180Conf.cfg.katana.runRealignStage = True
234 ls180Conf.cfg.katana.trackFill = 2
235 ls180Conf.cfg.block.spareSide = u(7*13)
236 ls180Conf.cfg.chip.supplyRailWidth = u(35)
237 ls180Conf.cfg.chip.supplyRailPitch = u(90)
238 ls180Conf.editor = editor
239 ls180Conf.useSpares = True
240 ls180Conf.useClockTree = True
241 ls180Conf.useHFNS = True
242 ls180Conf.bColumns = 2
243 ls180Conf.bRows = 2
244 ls180Conf.chipConf.name = 'chip'
245 ls180Conf.chipConf.ioPadGauge = 'LibreSOCIO'
246 ls180Conf.coreSize = (coreSizeX, coreSizeY)
247 ls180Conf.chipSize = (coreSizeX + chipBorder + u(5.0), coreSizeY + chipBorder - u(0.04) )
248 ls180Conf.chipLogos = [ 'C4MLogo_norm'
249 , 'libresoc_logo_norm'
250 , 'sorbonne_logo_norm'
251 , 'lip6_norm'
252 ]
253 ls180Conf.useHTree( 'core.pll_clk', Spares.HEAVY_LEAF_LOAD )
254 ls180Conf.useHTree( 'jtag_tck_from_pad' )
255
256 tiPath = 'test_issuer.ti.'
257 sramDatas \
258 = [ ['test_issuer.ti.sram4k_0.spblock_512w64b8w', -2]
259 , ['test_issuer.ti.sram4k_1.spblock_512w64b8w', 2]
260 , ['test_issuer.ti.sram4k_2.spblock_512w64b8w', 2]
261 , ['test_issuer.ti.sram4k_3.spblock_512w64b8w', 2]
262 ]
263
264 ls180ToChip = CoreToChip( ls180Conf )
265 ls180ToChip.buildChip()
266 chipBuilder = Chip( ls180Conf )
267 chipBuilder.doChipFloorplan()
268
269 with UpdateSession():
270 sram = DataBase.getDB().getCell( 'spblock_512w64b8w' )
271 sramAb = sram.getAbutmentBox()
272 coreAb = cell.getAbutmentBox()
273 sliceHeight = chipBuilder.conf.sliceHeight
274 sliceStep = chipBuilder.conf.sliceStep
275 originX = coreAb.getXMin() + sramDatas[0][1]*chipBuilder.conf.sliceStep
276 for i in range(len(sramDatas)):
277 chipBuilder.placeMacro \
278 ( sramDatas[i][0]
279 , Transformation( originX
280 , coreAb.getYMax() - sramAb.getHeight() - 2*sliceHeight
281 , Transformation.Orientation.ID )
282 )
283 if i+1 < len(sramDatas):
284 originX += sramAb.getWidth() + 2*sliceHeight + sramDatas[i+1][1]*sliceStep
285 pllTransf = Transformation( coreAb.getXMax() # -u(234.0)
286 , coreAb.getYMax() - u(208.0)
287 , Transformation.Orientation.MX )
288 print( 'pllTransf={}'.format(pllTransf) )
289 chipBuilder.placeMacro( 'test_issuer.wrappll.pll' , pllTransf )
290 sys.stderr.flush()
291 sys.stdout.flush()
292 Breakpoint.stop( 99, 'After core placement.' )
293
294 rvalue = chipBuilder.doPnR()
295 chipBuilder.save()
296 CRL.Gds.save( ls180Conf.chip )
297 except Exception, e:
298 helpers.io.catch(e)
299 rvalue = False
300 sys.stdout.flush()
301 sys.stderr.flush()
302 return rvalue