Wip of P&R of ls180 with C4M FreePDK45.
[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, 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
27
28 af = CRL.AllianceFramework.get()
29 powerCount = 0
30
31
32 def isiterable ( pyobj ):
33 if isinstance(pyobj,collections.Iterable): return True
34 return False
35
36
37 def doIoPowerCap ( flags ):
38 global powerCount
39 side = flags & IoPin.SIDE_MASK
40 if flags & IoPin.A_BEGIN:
41 ioPadPower = [ (side , None, 'power_{}'.format(powerCount), 'vdd' )
42 , (side , None, 'ground_{}'.format(powerCount), 'vss' )
43 , (side , None, 'ioground_{}'.format(powerCount), 'iovss' )
44 , (side , None, 'iopower_{}'.format(powerCount), 'iovdd' )
45 ]
46 else:
47 ioPadPower = [ (side , None, 'iopower_{}'.format(powerCount), 'iovdd' )
48 , (side , None, 'ioground_{}'.format(powerCount), 'iovss' )
49 , (side , None, 'ground_{}'.format(powerCount), 'vss' )
50 , (side , None, 'power_{}'.format(powerCount), 'vdd' )
51 ]
52 powerCount += 1
53 return ioPadPower
54
55
56 def doIoPinVector ( ioSpec, bits ):
57 v = []
58 if not isiterable(bits): bits = range(bits)
59 if not bits:
60 raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "bits" is neither a width nor an iterable.'
61 , '(bits={})'.format(bits)
62 ] )
63 if len(ioSpec) == 5:
64 for bit in bits:
65 v.append(( ioSpec[0]
66 , ioSpec[1]
67 , ioSpec[2].format(bit)
68 , ioSpec[3].format(bit)
69 , ioSpec[4].format(bit) ))
70 elif len(ioSpec) == 6:
71 for bit in bits:
72 v.append(( ioSpec[0]
73 , ioSpec[1]
74 , ioSpec[2].format(bit)
75 , ioSpec[3].format(bit)
76 , ioSpec[4].format(bit)
77 , ioSpec[5].format(bit) ))
78 elif len(ioSpec) == 7:
79 for bit in bits:
80 v.append(( ioSpec[0]
81 , ioSpec[1]
82 , ioSpec[2].format(bit)
83 , ioSpec[3].format(bit)
84 , ioSpec[4].format(bit)
85 , ioSpec[5].format(bit)
86 , ioSpec[6].format(bit) ))
87 else:
88 raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "ioSpec" must have between 5 and 7 fields ({})'.format(len(ioSpec))
89 , '(ioSpec={})'.format(ioSpec)
90 ] )
91 return v
92
93
94 def rgetInstance ( cell, path ):
95 """
96 Get the instance designated by path (recursively). The path argument can be
97 either a string of instance names separated by dots or directly a list of
98 instances names.
99 """
100 if isinstance(path,str):
101 path = path.split( '.' )
102 elif not isinstance(path,list):
103 raise ErrorMessage( 1, 'rgetInstance(): "path" argument is neither a string or a list ({})"' \
104 .format(path) )
105 instance = cell.getInstance( path[0] )
106 if instance is None:
107 raise ErrorMessage( 1, 'rgetInstance(): no instance "{}" in cell "{}"' \
108 .format(path[0],cell.getName()) )
109 if len(path) == 1:
110 return instance
111 return rgetInstance( instance.getMasterCell(), path[1:] )
112
113
114 def rsetAbutmentBox ( cell, ab ):
115 for occurrence in cell.getNonTerminalNetlistInstanceOccurrences():
116 masterCell = occurrence.getEntity().getMasterCell()
117 masterCell.setAbutmentBox( ab )
118
119 def addPllPlaceHolder ( cell ):
120 pllPlaceHolder = Cell.create( af.getLibrary(0), 'pllplaceholder' )
121 pllPlaceHolder.setAbutmentBox( Box( u(0.0), u(0.0), u(200.0), u(200.0) ))
122 pllPlaceHolder.setTerminalNetlist( True )
123 instance = Instance.create( cell, 'pllPlaceholder', pllPlaceHolder )
124 return instance
125
126
127 def scriptMain (**kw):
128 """The mandatory function to be called by Coriolis CGT/Unicorn."""
129 global af
130 #helpers.setTraceLevel( 550 )
131 #Breakpoint.setStopLevel( 100 )
132 rvalue = True
133 #coreSize = u(37*90.0)
134 coreSize = u(59*90.0)
135 chipBorder = u(2*214.0 + 10*13.0)
136 ioSpecs = IoSpecs()
137 #pinmuxFile = './non_generated/litex_pinpads.json'
138 #pinmuxFile = './coriolis2/ls180/litex_pinpads.json'
139 #ioSpecs.loadFromPinmux( pinmuxFile )
140 # I/O pads, East side.
141 ioPadsSpec = []
142 ioPadsSpec += doIoPowerCap( IoPin.EAST|IoPin.A_BEGIN )
143 ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'sdram_a_{}', 'sdram_a({})', 'sdram_a({})'), 13 )
144 ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(8,16) )
145 ioPadsSpec += [ (IoPin.EAST , None, 'jtag_tms', 'jtag_tms', 'jtag_tms' )
146 , (IoPin.EAST , None, 'jtag_tdi', 'jtag_tdi', 'jtag_tdi' )
147 , (IoPin.EAST , None, 'jtag_tdo', 'jtag_tdo', 'jtag_tdo' )
148 , (IoPin.EAST , None, 'jtag_tck', 'jtag_tck', 'jtag_tck' )
149 ]
150 ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'nc_{}', 'nc({})', 'nc({})'), range(4) )
151 ioPadsSpec += doIoPowerCap( IoPin.EAST|IoPin.A_END )
152 # I/O pads, West side.
153 ioPadsSpec += doIoPowerCap( IoPin.WEST|IoPin.A_BEGIN )
154 ioPadsSpec += [ (IoPin.WEST, None, 'pwm_1', 'pwm(1)', 'pwm(1)' ) ]
155 ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'eint_{}', 'eint({})', 'eint({})'), 3 )
156 ioPadsSpec += [ (IoPin.WEST , None, 'spimaster_clk' , 'spimaster_clk' , 'spimaster_clk' )
157 , (IoPin.WEST , None, 'spimaster_cs_n', 'spimaster_cs_n', 'spimaster_cs_n' )
158 , (IoPin.WEST , None, 'spimaster_mosi', 'spimaster_mosi', 'spimaster_mosi' )
159 , (IoPin.WEST , None, 'spimaster_miso', 'spimaster_miso', 'spimaster_miso' )
160 , (IoPin.WEST , None, 'sdcard_cmd' , 'sdcard_cmd' , 'sdcard_cmd_i', 'sdcard_cmd_oe', 'sdcard_cmd_o' )
161 , (IoPin.WEST , None, 'sdcard_clk' , 'sdcard_clk' , 'sdcard_clk' )
162 ]
163 ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'sdcard_data_{}', 'sdcard_data({})', 'sdcard_data_i({})', 'sdcard_data_oe', 'sdcard_data_o({})'), 4 )
164 ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'nc_{}', 'nc({})', 'nc({})'), range(4,16) )
165 ioPadsSpec += doIoPowerCap( IoPin.WEST|IoPin.A_END )
166 # I/O pads, North side.
167 ioPadsSpec += doIoPowerCap( IoPin.NORTH|IoPin.A_BEGIN )
168 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_dm_{}', 'sdram_dm({})', 'sdram_dm({})'), 2 )
169 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_dq_{}', 'sdram_dq({})', 'sdram_dq_i({})', 'sdram_dq_oe', 'sdram_dq_o({})'), range(0,16) )
170 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_ba_{}', 'sdram_ba({})', 'sdram_ba({})'), 2 )
171 ioPadsSpec += [ (IoPin.NORTH, None, 'sdram_clock' , 'sdram_clock' , 'sdram_clock' )
172 , (IoPin.NORTH, None, 'sdram_cke' , 'sdram_cke' , 'sdram_cke' )
173 , (IoPin.NORTH, None, 'sdram_ras_n' , 'sdram_ras_n' , 'sdram_ras_n' )
174 , (IoPin.NORTH, None, 'sdram_cas_n' , 'sdram_cas_n' , 'sdram_cas_n' )
175 , (IoPin.NORTH, None, 'sdram_we_n' , 'sdram_we_n' , 'sdram_we_n' )
176 , (IoPin.NORTH, None, 'sdram_cs_n' , 'sdram_cs_n' , 'sdram_cs_n' )
177 ]
178 ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(16,18) )
179 ioPadsSpec += doIoPowerCap( IoPin.NORTH|IoPin.A_END )
180 # I/O pads, South side.
181 ioPadsSpec += doIoPowerCap( IoPin.SOUTH|IoPin.A_BEGIN )
182 ioPadsSpec += [ (IoPin.SOUTH, None, 'i2c_sda_i' , 'i2c_sda_i' , 'i2c_sda_i' ) ]
183 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(18,22) )
184 ioPadsSpec += [ (IoPin.SOUTH, None, 'spisdcard_clk' , 'spisdcard_clk' , 'spisdcard_clk' )
185 , (IoPin.SOUTH, None, 'spisdcard_cs_n', 'spisdcard_cs_n', 'spisdcard_cs_n' )
186 , (IoPin.SOUTH, None, 'spisdcard_mosi', 'spisdcard_mosi', 'spisdcard_mosi' )
187 , (IoPin.SOUTH, None, 'spisdcard_miso', 'spisdcard_miso', 'spisdcard_miso' )
188 ]
189 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(22,23) )
190 ioPadsSpec += [ (IoPin.SOUTH, None, 'uart_tx', 'uart_tx', 'uart_tx' )
191 , (IoPin.SOUTH, None, 'uart_rx', 'uart_rx', 'uart_rx' )
192 ]
193 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(0,8) )
194 ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_clk', 'sys_clk', 'sys_clk' )
195 , (IoPin.SOUTH, None, 'sys_rst', 'sys_rst', 'sys_rst' )
196 ]
197 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(23,24) )
198 ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_pll_18_o' , 'sys_pll_18_o' , 'sys_pll_18_o' ) ]
199 ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'sys_clksel_i{}', 'sys_clksel_i({})', 'sys_clksel_i({})'), 2 )
200 ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_pll_lck_o' , 'sys_pll_lck_o' , 'sys_pll_lck_o' ) ]
201 ioPadsSpec += doIoPowerCap( IoPin.SOUTH|IoPin.A_END )
202 try:
203 cell, editor = plugins.kwParseMain( **kw )
204 cell = af.getCell( 'ls180', CRL.Catalog.State.Logical )
205 if cell is None:
206 print( ErrorMessage( 2, 'doDesign.scriptMain(): Unable to load cell "{}".' \
207 .format('ls180') ))
208 sys.exit(1)
209 if editor: editor.setCell( cell )
210 #ls180Conf = ChipConf( cell, ioPads=ioSpecs.ioPadsSpec )
211 ls180Conf = ChipConf( cell, ioPads=ioPadsSpec )
212 ls180Conf.cfg.etesian.bloat = 'nsxlib'
213 ls180Conf.cfg.etesian.uniformDensity = True
214 ls180Conf.cfg.etesian.aspectRatio = 1.0
215 ls180Conf.cfg.etesian.spaceMargin = 0.05
216 ls180Conf.cfg.anabatic.searchHalo = 2
217 ls180Conf.cfg.anabatic.globalIterations = 20
218 ls180Conf.cfg.anabatic.topRoutingLayer = 'METAL5'
219 ls180Conf.cfg.katana.hTracksReservedLocal = 6
220 ls180Conf.cfg.katana.vTracksReservedLocal = 3
221 ls180Conf.cfg.katana.hTracksReservedMin = 3
222 ls180Conf.cfg.katana.vTracksReservedMin = 1
223 ls180Conf.cfg.block.spareSide = u(7*13)
224 ls180Conf.cfg.chip.supplyRailWidth = u(35)
225 ls180Conf.cfg.chip.supplyRailPitch = u(90)
226 ls180Conf.editor = editor
227 ls180Conf.useSpares = True
228 ls180Conf.useClockTree = True
229 ls180Conf.useHFNS = True
230 ls180Conf.bColumns = 2
231 ls180Conf.bRows = 2
232 ls180Conf.chipConf.name = 'chip'
233 ls180Conf.chipConf.ioPadGauge = 'LibreSOCIO'
234 ls180Conf.coreSize = (coreSize, coreSize)
235 ls180Conf.chipSize = (coreSize + chipBorder, coreSize + chipBorder)
236
237 with UpdateSession():
238 sliceHeight = ls180Conf.sliceHeight
239 coreAb = Box( 0, 0, coreSize, coreSize )
240 rsetAbutmentBox( cell, coreAb )
241
242 ls180ToChip = CoreToChip( ls180Conf )
243 ls180ToChip.buildChip()
244 chipBuilder = Chip( ls180Conf )
245 chipBuilder.doChipFloorplan()
246
247 with UpdateSession():
248 # Thoses ids are dependent on Yosys. They need to be adjusted whenever
249 # the design changes.
250 #tiId = 38695
251 tiId = 38381
252 #sramId = 3695
253 sramId = 3300
254 tiPath = 'subckt_{}_test_issuer.subckt_1_ti.'.format(tiId)
255 sramPaths = [ tiPath+'subckt_{}_sram4k_0.subckt_144_SPBlock_512W64B8W'.format(sramId)
256 , tiPath+'subckt_{}_sram4k_1.subckt_144_SPBlock_512W64B8W'.format(sramId+1)
257 , tiPath+'subckt_{}_sram4k_2.subckt_144_SPBlock_512W64B8W'.format(sramId+2)
258 , tiPath+'subckt_{}_sram4k_3.subckt_144_SPBlock_512W64B8W'.format(sramId+3)
259 ]
260 sram = DataBase.getDB().getCell( 'SPBlock_512W64B8W' )
261 if not sram:
262 raise ErrorMessage( 1, 'SRAM instance "{}" not found.'.format(sramPaths[i]) )
263 sramAb = sram.getAbutmentBox()
264 coreAb = cell.getAbutmentBox()
265 sliceHeight = chipBuilder.conf.sliceHeight
266 originX = coreAb.getXMin() + 2*chipBuilder.conf.sliceStep
267 for i in range(4):
268 sram = rgetInstance( cell, sramPaths[i] )
269 chipBuilder.placeMacro \
270 ( sramPaths[i]
271 , Transformation( originX
272 , coreAb.getYMax() - sramAb.getHeight() - 2*sliceHeight
273 , Transformation.Orientation.ID )
274 )
275 originX += sramAb.getWidth () + 3*sliceHeight
276 pll = addPllPlaceHolder( cell )
277 pllAb = pll.getAbutmentBox()
278 pll.setTransformation( Transformation( coreAb.getXMax() - pllAb.getWidth()
279 , coreAb.getYMax() - pllAb.getHeight()
280 , Transformation.Orientation.ID ) )
281 pll.setPlacementStatus( Instance.PlacementStatus.FIXED )
282 #ls180Conf.placeArea = Box( coreAb.getXMin()
283 # , coreAb.getYMin()
284 # , coreAb.getXMax() - chipBuilder.conf.sliceStep
285 # , coreAb.getYMax() - sramAb.getHeight() - 2*sliceHeight
286 # )
287 #memPatterns = [ r'^mem_(?P<i>\d+)__(?P<j>[\d+])$'
288 # , r'^mem_1_(?P<i>\d+)__(?P<j>[\d+])$'
289 # , r'^mem_2_(?P<i>\d+)__(?P<j>[\d+])$'
290 # , r'^mem_3_(?P<i>\d+)__(?P<j>[\d+])$'
291 # ]
292 #originX += 2*sliceHeight
293 #originY = coreAb.getYMax()
294 #for i in range(len(memPatterns)):
295 # mem = RegisterMatrix( ls180Conf, cell, memPatterns[i] )
296 # originY -= mem.getHeight()
297 # mem.place( Point(originX,originY) )
298 Breakpoint.stop( 99, 'After core placement.' )
299
300 rvalue = chipBuilder.doPnR()
301 chipBuilder.save()
302 CRL.Gds.save( ls180Conf.chip )
303 except Exception, e:
304 helpers.io.catch(e)
305 rvalue = False
306 sys.stdout.flush()
307 sys.stderr.flush()
308 return rvalue