From bbb0e100e3e37d2c51e0917699afe5bd051961d2 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 9 Mar 2021 11:01:04 +0100 Subject: [PATCH] First working version of the Flexlib + P&R flow for the ls180+SRAM. Note: It is working in the sense that the flow complete, but is stills contains various errors that needs fixing. We discoupled from pinmux as core2chip have problems associating the pad instances names with the relevant core signals. We guessed a pad placement from pinmux, but it seems a bit odd to me... --- experiments9/tsmc_c018/coriolis2/settings.py | 114 ++++------ experiments9/tsmc_c018/doDesign.py | 219 +++++++++++++++++-- 2 files changed, 244 insertions(+), 89 deletions(-) diff --git a/experiments9/tsmc_c018/coriolis2/settings.py b/experiments9/tsmc_c018/coriolis2/settings.py index 5c1ea66..1142e7a 100644 --- a/experiments9/tsmc_c018/coriolis2/settings.py +++ b/experiments9/tsmc_c018/coriolis2/settings.py @@ -1,79 +1,45 @@ # -*- Mode:Python -*- -import Cfg -import CRL -import Viewer -from helpers.overlay import CfgCache -import symbolic.cmos45 # do not remove import os +import socket +import helpers + +NdaDirectory = None +if os.environ.has_key('NDA_TOP'): + NdaDirectory = os.environ['NDA_TOP'] +if not NdaDirectory: + hostname = socket.gethostname() + if hostname.startswith('lepka'): + NdaDirectory = '/dsk/l1/jpc/crypted/soc/techno' + if not os.path.isdir(NdaDirectory): + print '[ERROR] You forgot to mount the NDA encrypted directory, stupid!' + else: + NdaDirectory = '/users/soft/techno/techno' +helpers.setNdaTopDir( NdaDirectory ) -if os.environ.has_key('CELLS_TOP'): - cellsTop = os.environ['CELLS_TOP'] -else: - cellsTop = '../../../alliance-check-toolkit/cells' - -with CfgCache('', priority=Cfg.Parameter.Priority.UserFile) as cfg: - cfg.misc.catchCore = False - cfg.misc.info = False - cfg.misc.paranoid = False - cfg.misc.bug = False - cfg.misc.logMode = True - cfg.misc.verboseLevel1 = True - cfg.misc.verboseLevel2 = True - cfg.anabatic.edgeLenght = 24 - cfg.anabatic.edgeWidth = 8 - cfg.anabatic.topRoutingLayer = 'METAL5' - cfg.etesian.graphics = 3 - - #cfg.katana.searchHalo = 30 - #cfg.katana.eventsLimit = 1000000 - #cfg.katana.hTracksReservedLocal = 7 - - # Run 2 (make-cgt-2.log) - #cfg.etesian.effort = 2 - #cfg.etesian.uniformDensity = True - #cfg.etesian.spaceMargin = 0.05 - #cfg.etesian.aspectRatio = 1.0 - #cfg.katana.vTracksReservedLocal = 4 - #cfg.katana.hTracksReservedLocal = 4 - - # Run 3 (make-cgt-3.log) - #cfg.etesian.effort = 2 - #cfg.etesian.uniformDensity = False - #cfg.etesian.spaceMargin = 0.05 - #cfg.etesian.aspectRatio = 1.0 - #cfg.katana.vTracksReservedLocal = 5 - #cfg.katana.hTracksReservedLocal = 5 - - # Run 4 (make-cgt-4.log) - #cfg.etesian.effort = 2 - #cfg.etesian.uniformDensity = True - #cfg.etesian.spaceMargin = 0.05 - #cfg.etesian.aspectRatio = 1.0 - - # Run 5 (make-cgt-5.log) - cfg.etesian.effort = 2 - cfg.etesian.uniformDensity = True - cfg.etesian.spaceMargin = 0.05 - cfg.etesian.aspectRatio = 1.0 - cfg.katana.useGlobalEstimate = False - cfg.katana.vTracksReservedLocal = 7 - cfg.katana.hTracksReservedLocal = 6 - cfg.katana.bloatOverloadAdd = 4 - cfg.conductor.stopLevel = 0 - cfg.conductor.maxPlaceIterations = 2 - cfg.conductor.useFixedAbHeight = False - - env = CRL.AllianceFramework.get().getEnvironment() +import Cfg +from CRL import AllianceFramework +from helpers import overlay, l, u, n +from NDA.node180.tsmc_c018 import techno, FlexLib, LibreSOCIO, LibreSOCMem + +techno.setup() +FlexLib.setup() +LibreSOCIO.setup() +LibreSOCMem.setup() + +with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg: + cfg.misc.catchCore = False + cfg.misc.minTraceLevel = 14700 + cfg.misc.maxTraceLevel = 14800 + cfg.misc.info = False + cfg.misc.paranoid = False + cfg.misc.bug = False + cfg.misc.logMode = True + cfg.misc.verboseLevel1 = True + cfg.misc.verboseLevel2 = True + cfg.etesian.graphics = 3 + cfg.etesian.spaceMargin = 0.10 + cfg.katana.eventsLimit = 4000000 + af = AllianceFramework.get() + env = af.getEnvironment() env.setCLOCK( '^sys_clk$|^ck|^jtag_tck$' ) - env.addSYSTEM_LIBRARY(library=cellsTop+'/niolib', - mode=CRL.Environment.Prepend ) - env.addSYSTEM_LIBRARY(library=cellsTop+'/nsxlib', - mode=CRL.Environment.Prepend ) - env.setPOWER ('vdd') - env.setGROUND('vss') - -Viewer.Graphics.setStyle('Alliance.Classic [black]') - -print( ' o Successfully run "<>/coriolis2/settings.py".' ) -print( ' - CELLS_TOP = "{}"'.format(cellsTop) ) diff --git a/experiments9/tsmc_c018/doDesign.py b/experiments9/tsmc_c018/doDesign.py index 76651a7..9321f33 100644 --- a/experiments9/tsmc_c018/doDesign.py +++ b/experiments9/tsmc_c018/doDesign.py @@ -5,32 +5,189 @@ import os import json import sys import traceback +import collections import CRL import helpers -from helpers.io import ErrorMessage, WarningMessage -from helpers import trace, l, u, n +from helpers import trace, l, u, n +from helpers.io import ErrorMessage, WarningMessage +from helpers.overlay import UpdateSession import plugins -from Hurricane import DbU -from plugins.alpha.block.configuration import IoPin, GaugeConf +from Hurricane import Breakpoint, DbU, Transformation, Box, Instance +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() +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 scriptMain (**kw): """The mandatory function to be called by Coriolis CGT/Unicorn.""" global af - rvalue = True - coreSize = 5200.0 - chipBorder = 2*214.0 + 10*13.0 - ioSpecs = IoSpecs() - ioSpecs.loadFromPinmux( './non_generated/litex_pinpads.json' ) + #helpers.setTraceLevel( 550 ) + rvalue = True + coreSize = u(5850.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: - #helpers.setTraceLevel( 550 ) cell, editor = plugins.kwParseMain( **kw ) cell = af.getCell( 'ls180', CRL.Catalog.State.Logical ) if cell is None: @@ -38,7 +195,8 @@ def scriptMain (**kw): .format('ls180') )) sys.exit(1) if editor: editor.setCell( cell ) - ls180Conf = ChipConf( cell, ioPads=ioSpecs.ioPadsSpec ) + #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 @@ -50,7 +208,7 @@ def scriptMain (**kw): ls180Conf.cfg.katana.vTracksReservedLocal = 3 ls180Conf.cfg.katana.hTracksReservedMin = 3 ls180Conf.cfg.katana.vTracksReservedMin = 1 - ls180Conf.cfg.block.spareSide = u(200) + ls180Conf.cfg.block.spareSide = u(156) ls180Conf.cfg.chip.supplyRailWidth = u(35) ls180Conf.cfg.chip.supplyRailPitch = u(90) ls180Conf.editor = editor @@ -61,8 +219,39 @@ def scriptMain (**kw): ls180Conf.bRows = 2 ls180Conf.chipConf.name = 'chip' ls180Conf.chipConf.ioPadGauge = 'LibreSOCIO' - ls180Conf.coreSize = (u(coreSize), u(coreSize)) - ls180Conf.chipSize = (u(coreSize + chipBorder), u(coreSize + chipBorder)) + ls180Conf.coreSize = (coreSize, coreSize) + ls180Conf.chipSize = (coreSize + chipBorder, coreSize + chipBorder) + + with UpdateSession(): + sliceHeight = ls180Conf.sliceHeight + coreAb = Box( 0, 0, coreSize, coreSize ) + rsetAbutmentBox( cell, coreAb ) + tiPath = 'subckt_38695_test_issuer.subckt_1_ti.' + sramPaths = [ tiPath+'subckt_3695_sram4k_0.subckt_144_SPBlock_512W64B8W' + , tiPath+'subckt_3696_sram4k_1.subckt_144_SPBlock_512W64B8W' + , tiPath+'subckt_3697_sram4k_2.subckt_144_SPBlock_512W64B8W' + , tiPath+'subckt_3698_sram4k_3.subckt_144_SPBlock_512W64B8W' + ] + sramAb = None + for i in range(4): + sram = rgetInstance( cell, sramPaths[i] ) + if not sram: + raise ErrorMessage( 1, 'SRAM instance "{}" not found.'.format(sramPaths[i]) ) + if i == 0: + Macro.wrap( sram.getMasterCell(), 'FlexLib', 3, 2 ) + sramAb = sram.getMasterCell().getAbutmentBox() + Macro.place( sram + , Transformation( coreAb.getXMin() + sramAb.getWidth ()*i + , coreAb.getYMax() - sramAb.getHeight() + , Transformation.Orientation.ID ) + , Instance.PlacementStatus.FIXED ) + ls180Conf.placeArea = Box( coreAb.getXMin() + , coreAb.getYMin() + , coreAb.getXMax() + , coreAb.getYMax() - sramAb.getHeight() + ) + Breakpoint.stop( 99, 'After core placement.' ) + ls180ToChip = CoreToChip( ls180Conf ) ls180ToChip.buildChip() chipBuilder = Chip( ls180Conf ) -- 2.30.2