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