--- /dev/null
+
+from __future__ import print_function
+
+import os
+import re
+import json
+import sys
+import traceback
+import collections
+import CRL
+import helpers
+from helpers import trace, l, u, n
+from helpers.io import ErrorMessage, WarningMessage
+from helpers.overlay import UpdateSession
+import plugins
+from Hurricane import Breakpoint, DataBase, DbU, Transformation, Point, Box, \
+ Cell, Instance
+from plugins.alpha.block.matrix import RegisterMatrix
+from plugins.alpha.macro.macro import Macro
+from plugins.alpha.block.iospecs import IoSpecs
+from plugins.alpha.block.block import Block
+from plugins.alpha.block.configuration import IoPin, GaugeConf
+from plugins.alpha.core2chip.libresocio import CoreToChip
+from plugins.alpha.chip.configuration import ChipConf
+from plugins.alpha.chip.chip import Chip
+
+
+af = CRL.AllianceFramework.get()
+powerCount = 0
+
+
+def isiterable ( pyobj ):
+ if isinstance(pyobj,collections.Iterable): return True
+ return False
+
+
+def doIoPowerCap ( flags ):
+ global powerCount
+ side = flags & IoPin.SIDE_MASK
+ if flags & IoPin.A_BEGIN:
+ ioPadPower = [ (side , None, 'power_{}'.format(powerCount), 'vdd' )
+ , (side , None, 'ground_{}'.format(powerCount), 'vss' )
+ , (side , None, 'ioground_{}'.format(powerCount), 'iovss' )
+ , (side , None, 'iopower_{}'.format(powerCount), 'iovdd' )
+ ]
+ else:
+ ioPadPower = [ (side , None, 'iopower_{}'.format(powerCount), 'iovdd' )
+ , (side , None, 'ioground_{}'.format(powerCount), 'iovss' )
+ , (side , None, 'ground_{}'.format(powerCount), 'vss' )
+ , (side , None, 'power_{}'.format(powerCount), 'vdd' )
+ ]
+ powerCount += 1
+ return ioPadPower
+
+
+def doIoPinVector ( ioSpec, bits ):
+ v = []
+ if not isiterable(bits): bits = range(bits)
+ if not bits:
+ raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "bits" is neither a width nor an iterable.'
+ , '(bits={})'.format(bits)
+ ] )
+ if len(ioSpec) == 5:
+ for bit in bits:
+ v.append(( ioSpec[0]
+ , ioSpec[1]
+ , ioSpec[2].format(bit)
+ , ioSpec[3].format(bit)
+ , ioSpec[4].format(bit) ))
+ elif len(ioSpec) == 6:
+ for bit in bits:
+ v.append(( ioSpec[0]
+ , ioSpec[1]
+ , ioSpec[2].format(bit)
+ , ioSpec[3].format(bit)
+ , ioSpec[4].format(bit)
+ , ioSpec[5].format(bit) ))
+ elif len(ioSpec) == 7:
+ for bit in bits:
+ v.append(( ioSpec[0]
+ , ioSpec[1]
+ , ioSpec[2].format(bit)
+ , ioSpec[3].format(bit)
+ , ioSpec[4].format(bit)
+ , ioSpec[5].format(bit)
+ , ioSpec[6].format(bit) ))
+ else:
+ raise ErrorMessage( 1, [ 'doIoPinVector(): Argument "ioSpec" must have between 5 and 7 fields ({})'.format(len(ioSpec))
+ , '(ioSpec={})'.format(ioSpec)
+ ] )
+ return v
+
+
+def rgetInstance ( cell, path ):
+ """
+ Get the instance designated by path (recursively). The path argument can be
+ either a string of instance names separated by dots or directly a list of
+ instances names.
+ """
+ if isinstance(path,str):
+ path = path.split( '.' )
+ elif not isinstance(path,list):
+ raise ErrorMessage( 1, 'rgetInstance(): "path" argument is neither a string or a list ({})"' \
+ .format(path) )
+ instance = cell.getInstance( path[0] )
+ if instance is None:
+ raise ErrorMessage( 1, 'rgetInstance(): no instance "{}" in cell "{}"' \
+ .format(path[0],cell.getName()) )
+ if len(path) == 1:
+ return instance
+ return rgetInstance( instance.getMasterCell(), path[1:] )
+
+
+def rsetAbutmentBox ( cell, ab ):
+ for occurrence in cell.getNonTerminalNetlistInstanceOccurrences():
+ masterCell = occurrence.getEntity().getMasterCell()
+ masterCell.setAbutmentBox( ab )
+
+def addPllPlaceHolder ( cell ):
+ pllPlaceHolder = Cell.create( af.getLibrary(0), 'pllplaceholder' )
+ pllPlaceHolder.setAbutmentBox( Box( u(0.0), u(0.0), u(200.0), u(200.0) ))
+ pllPlaceHolder.setTerminalNetlist( True )
+ instance = Instance.create( cell, 'pllPlaceholder', pllPlaceHolder )
+ return instance
+
+
+def scriptMain (**kw):
+ """The mandatory function to be called by Coriolis CGT/Unicorn."""
+ global af
+ #helpers.setTraceLevel( 550 )
+ #Breakpoint.setStopLevel( 100 )
+ rvalue = True
+ #coreSize = u(37*90.0)
+ coreSize = u(59*90.0)
+ chipBorder = u(2*214.0 + 10*13.0)
+ ioSpecs = IoSpecs()
+ #pinmuxFile = './non_generated/litex_pinpads.json'
+ #pinmuxFile = './coriolis2/ls180/litex_pinpads.json'
+ #ioSpecs.loadFromPinmux( pinmuxFile )
+ # I/O pads, East side.
+ ioPadsSpec = []
+ ioPadsSpec += doIoPowerCap( IoPin.EAST|IoPin.A_BEGIN )
+ ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'sdram_a_{}', 'sdram_a({})', 'sdram_a({})'), 13 )
+ ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(8,16) )
+ ioPadsSpec += [ (IoPin.EAST , None, 'jtag_tms', 'jtag_tms', 'jtag_tms' )
+ , (IoPin.EAST , None, 'jtag_tdi', 'jtag_tdi', 'jtag_tdi' )
+ , (IoPin.EAST , None, 'jtag_tdo', 'jtag_tdo', 'jtag_tdo' )
+ , (IoPin.EAST , None, 'jtag_tck', 'jtag_tck', 'jtag_tck' )
+ ]
+ ioPadsSpec += doIoPinVector( (IoPin.EAST , None, 'nc_{}', 'nc({})', 'nc({})'), range(4) )
+ ioPadsSpec += doIoPowerCap( IoPin.EAST|IoPin.A_END )
+ # I/O pads, West side.
+ ioPadsSpec += doIoPowerCap( IoPin.WEST|IoPin.A_BEGIN )
+ ioPadsSpec += [ (IoPin.WEST, None, 'pwm_1', 'pwm(1)', 'pwm(1)' ) ]
+ ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'eint_{}', 'eint({})', 'eint({})'), 3 )
+ ioPadsSpec += [ (IoPin.WEST , None, 'spimaster_clk' , 'spimaster_clk' , 'spimaster_clk' )
+ , (IoPin.WEST , None, 'spimaster_cs_n', 'spimaster_cs_n', 'spimaster_cs_n' )
+ , (IoPin.WEST , None, 'spimaster_mosi', 'spimaster_mosi', 'spimaster_mosi' )
+ , (IoPin.WEST , None, 'spimaster_miso', 'spimaster_miso', 'spimaster_miso' )
+ , (IoPin.WEST , None, 'sdcard_cmd' , 'sdcard_cmd' , 'sdcard_cmd_i', 'sdcard_cmd_oe', 'sdcard_cmd_o' )
+ , (IoPin.WEST , None, 'sdcard_clk' , 'sdcard_clk' , 'sdcard_clk' )
+ ]
+ ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'sdcard_data_{}', 'sdcard_data({})', 'sdcard_data_i({})', 'sdcard_data_oe', 'sdcard_data_o({})'), 4 )
+ ioPadsSpec += doIoPinVector( (IoPin.WEST , None, 'nc_{}', 'nc({})', 'nc({})'), range(4,16) )
+ ioPadsSpec += doIoPowerCap( IoPin.WEST|IoPin.A_END )
+ # I/O pads, North side.
+ ioPadsSpec += doIoPowerCap( IoPin.NORTH|IoPin.A_BEGIN )
+ ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_dm_{}', 'sdram_dm({})', 'sdram_dm({})'), 2 )
+ ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_dq_{}', 'sdram_dq({})', 'sdram_dq_i({})', 'sdram_dq_oe', 'sdram_dq_o({})'), range(0,16) )
+ ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'sdram_ba_{}', 'sdram_ba({})', 'sdram_ba({})'), 2 )
+ ioPadsSpec += [ (IoPin.NORTH, None, 'sdram_clock' , 'sdram_clock' , 'sdram_clock' )
+ , (IoPin.NORTH, None, 'sdram_cke' , 'sdram_cke' , 'sdram_cke' )
+ , (IoPin.NORTH, None, 'sdram_ras_n' , 'sdram_ras_n' , 'sdram_ras_n' )
+ , (IoPin.NORTH, None, 'sdram_cas_n' , 'sdram_cas_n' , 'sdram_cas_n' )
+ , (IoPin.NORTH, None, 'sdram_we_n' , 'sdram_we_n' , 'sdram_we_n' )
+ , (IoPin.NORTH, None, 'sdram_cs_n' , 'sdram_cs_n' , 'sdram_cs_n' )
+ ]
+ ioPadsSpec += doIoPinVector( (IoPin.NORTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(16,18) )
+ ioPadsSpec += doIoPowerCap( IoPin.NORTH|IoPin.A_END )
+ # I/O pads, South side.
+ ioPadsSpec += doIoPowerCap( IoPin.SOUTH|IoPin.A_BEGIN )
+ ioPadsSpec += [ (IoPin.SOUTH, None, 'i2c_sda_i' , 'i2c_sda_i' , 'i2c_sda_i' ) ]
+ ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(18,22) )
+ ioPadsSpec += [ (IoPin.SOUTH, None, 'spisdcard_clk' , 'spisdcard_clk' , 'spisdcard_clk' )
+ , (IoPin.SOUTH, None, 'spisdcard_cs_n', 'spisdcard_cs_n', 'spisdcard_cs_n' )
+ , (IoPin.SOUTH, None, 'spisdcard_mosi', 'spisdcard_mosi', 'spisdcard_mosi' )
+ , (IoPin.SOUTH, None, 'spisdcard_miso', 'spisdcard_miso', 'spisdcard_miso' )
+ ]
+ ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(22,23) )
+ ioPadsSpec += [ (IoPin.SOUTH, None, 'uart_tx', 'uart_tx', 'uart_tx' )
+ , (IoPin.SOUTH, None, 'uart_rx', 'uart_rx', 'uart_rx' )
+ ]
+ ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'gpio_{}', 'gpio({})', 'gpio_i({})', 'gpio_oe({})', 'gpio_o({})'), range(0,8) )
+ ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_clk', 'sys_clk', 'sys_clk' )
+ , (IoPin.SOUTH, None, 'sys_rst', 'sys_rst', 'sys_rst' )
+ ]
+ ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'nc_{}', 'nc({})', 'nc({})'), range(23,24) )
+ ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_pll_18_o' , 'sys_pll_18_o' , 'sys_pll_18_o' ) ]
+ ioPadsSpec += doIoPinVector( (IoPin.SOUTH, None, 'sys_clksel_i{}', 'sys_clksel_i({})', 'sys_clksel_i({})'), 2 )
+ ioPadsSpec += [ (IoPin.SOUTH, None, 'sys_pll_lck_o' , 'sys_pll_lck_o' , 'sys_pll_lck_o' ) ]
+ ioPadsSpec += doIoPowerCap( IoPin.SOUTH|IoPin.A_END )
+ try:
+ cell, editor = plugins.kwParseMain( **kw )
+ cell = af.getCell( 'ls180', CRL.Catalog.State.Logical )
+ if cell is None:
+ print( ErrorMessage( 2, 'doDesign.scriptMain(): Unable to load cell "{}".' \
+ .format('ls180') ))
+ sys.exit(1)
+ if editor: editor.setCell( cell )
+ #ls180Conf = ChipConf( cell, ioPads=ioSpecs.ioPadsSpec )
+ ls180Conf = ChipConf( cell, ioPads=ioPadsSpec )
+ ls180Conf.cfg.etesian.bloat = 'nsxlib'
+ ls180Conf.cfg.etesian.uniformDensity = True
+ ls180Conf.cfg.etesian.aspectRatio = 1.0
+ ls180Conf.cfg.etesian.spaceMargin = 0.05
+ ls180Conf.cfg.anabatic.searchHalo = 2
+ ls180Conf.cfg.anabatic.globalIterations = 20
+ ls180Conf.cfg.anabatic.topRoutingLayer = 'METAL5'
+ ls180Conf.cfg.katana.hTracksReservedLocal = 6
+ ls180Conf.cfg.katana.vTracksReservedLocal = 3
+ ls180Conf.cfg.katana.hTracksReservedMin = 3
+ ls180Conf.cfg.katana.vTracksReservedMin = 1
+ ls180Conf.cfg.block.spareSide = u(7*13)
+ ls180Conf.cfg.chip.supplyRailWidth = u(35)
+ ls180Conf.cfg.chip.supplyRailPitch = u(90)
+ ls180Conf.editor = editor
+ ls180Conf.useSpares = True
+ ls180Conf.useClockTree = True
+ ls180Conf.useHFNS = True
+ ls180Conf.bColumns = 2
+ ls180Conf.bRows = 2
+ ls180Conf.chipConf.name = 'chip'
+ ls180Conf.chipConf.ioPadGauge = 'LibreSOCIO'
+ ls180Conf.coreSize = (coreSize, coreSize)
+ ls180Conf.chipSize = (coreSize + chipBorder, coreSize + chipBorder)
+
+ with UpdateSession():
+ sliceHeight = ls180Conf.sliceHeight
+ coreAb = Box( 0, 0, coreSize, coreSize )
+ rsetAbutmentBox( cell, coreAb )
+
+ ls180ToChip = CoreToChip( ls180Conf )
+ ls180ToChip.buildChip()
+ chipBuilder = Chip( ls180Conf )
+ chipBuilder.doChipFloorplan()
+
+ with UpdateSession():
+ # Thoses ids are dependent on Yosys. They need to be adjusted whenever
+ # the design changes.
+ #tiId = 38695
+ tiId = 38381
+ #sramId = 3695
+ sramId = 3300
+ tiPath = 'subckt_{}_test_issuer.subckt_1_ti.'.format(tiId)
+ sramPaths = [ tiPath+'subckt_{}_sram4k_0.subckt_144_SPBlock_512W64B8W'.format(sramId)
+ , tiPath+'subckt_{}_sram4k_1.subckt_144_SPBlock_512W64B8W'.format(sramId+1)
+ , tiPath+'subckt_{}_sram4k_2.subckt_144_SPBlock_512W64B8W'.format(sramId+2)
+ , tiPath+'subckt_{}_sram4k_3.subckt_144_SPBlock_512W64B8W'.format(sramId+3)
+ ]
+ sram = DataBase.getDB().getCell( 'SPBlock_512W64B8W' )
+ if not sram:
+ raise ErrorMessage( 1, 'SRAM instance "{}" not found.'.format(sramPaths[i]) )
+ sramAb = sram.getAbutmentBox()
+ coreAb = cell.getAbutmentBox()
+ sliceHeight = chipBuilder.conf.sliceHeight
+ originX = coreAb.getXMin() + 2*chipBuilder.conf.sliceStep
+ for i in range(4):
+ sram = rgetInstance( cell, sramPaths[i] )
+ chipBuilder.placeMacro \
+ ( sramPaths[i]
+ , Transformation( originX
+ , coreAb.getYMax() - sramAb.getHeight() - 2*sliceHeight
+ , Transformation.Orientation.ID )
+ )
+ originX += sramAb.getWidth () + 3*sliceHeight
+ pll = addPllPlaceHolder( cell )
+ pllAb = pll.getAbutmentBox()
+ pll.setTransformation( Transformation( coreAb.getXMax() - pllAb.getWidth()
+ , coreAb.getYMax() - pllAb.getHeight()
+ , Transformation.Orientation.ID ) )
+ pll.setPlacementStatus( Instance.PlacementStatus.FIXED )
+ #ls180Conf.placeArea = Box( coreAb.getXMin()
+ # , coreAb.getYMin()
+ # , coreAb.getXMax() - chipBuilder.conf.sliceStep
+ # , coreAb.getYMax() - sramAb.getHeight() - 2*sliceHeight
+ # )
+ #memPatterns = [ r'^mem_(?P<i>\d+)__(?P<j>[\d+])$'
+ # , r'^mem_1_(?P<i>\d+)__(?P<j>[\d+])$'
+ # , r'^mem_2_(?P<i>\d+)__(?P<j>[\d+])$'
+ # , r'^mem_3_(?P<i>\d+)__(?P<j>[\d+])$'
+ # ]
+ #originX += 2*sliceHeight
+ #originY = coreAb.getYMax()
+ #for i in range(len(memPatterns)):
+ # mem = RegisterMatrix( ls180Conf, cell, memPatterns[i] )
+ # originY -= mem.getHeight()
+ # mem.place( Point(originX,originY) )
+ Breakpoint.stop( 99, 'After core placement.' )
+
+ rvalue = chipBuilder.doPnR()
+ chipBuilder.save()
+ CRL.Gds.save( ls180Conf.chip )
+ except Exception, e:
+ helpers.io.catch(e)
+ rvalue = False
+ sys.stdout.flush()
+ sys.stderr.flush()
+ return rvalue