Make purposes argument to gdsMill. Create prefixGDS.py script.

This commit is contained in:
mrg 2021-06-22 14:40:43 -07:00
parent a0921b4afc
commit 8d71a98ce9
4 changed files with 65 additions and 34 deletions

View File

@ -20,6 +20,10 @@ from globals import OPTS
from vector import vector from vector import vector
from pin_layout import pin_layout from pin_layout import pin_layout
from utils import round_to_grid from utils import round_to_grid
try:
from tech import special_purposes
except ImportError:
special_purposes = {}
class layout(): class layout():
@ -36,9 +40,9 @@ class layout():
# This gets set in both spice and layout so either can be called first. # This gets set in both spice and layout so either can be called first.
self.name = name self.name = name
self.cell_name = cell_name self.cell_name = cell_name
self.gds_file = OPTS.openram_tech + "gds_lib/" + cell_name + ".gds" self.gds_file = OPTS.openram_tech + "gds_lib/" + cell_name + ".gds"
self.width = None self.width = None
self.height = None self.height = None
self.bounding_box = None # The rectangle shape self.bounding_box = None # The rectangle shape
@ -58,7 +62,7 @@ class layout():
self.visited = [] self.visited = []
# Flag for library cells # Flag for library cells
self.is_library_cell = False self.is_library_cell = False
self.gds_read() self.gds_read()
try: try:
@ -66,7 +70,7 @@ class layout():
self.pwr_grid_layer = power_grid[0] self.pwr_grid_layer = power_grid[0]
except ImportError: except ImportError:
self.pwr_grid_layer = "m3" self.pwr_grid_layer = "m3"
############################################################ ############################################################
# GDS layout # GDS layout
############################################################ ############################################################
@ -118,7 +122,7 @@ class layout():
if len(self.objs) > 0: if len(self.objs) > 0:
lowestx = min(min(obj.lx() for obj in self.objs if obj.name != "label"), lowestx) lowestx = min(min(obj.lx() for obj in self.objs if obj.name != "label"), lowestx)
lowesty = min(min(obj.by() for obj in self.objs if obj.name != "label"), lowesty) lowesty = min(min(obj.by() for obj in self.objs if obj.name != "label"), lowesty)
if len(self.insts) > 0: if len(self.insts) > 0:
lowestx = min(min(inst.lx() for inst in self.insts), lowestx) lowestx = min(min(inst.lx() for inst in self.insts), lowestx)
lowesty = min(min(inst.by() for inst in self.insts), lowesty) lowesty = min(min(inst.by() for inst in self.insts), lowesty)
@ -129,7 +133,7 @@ class layout():
continue continue
lowestx = min(min(pin.lx() for pin in pin_set), lowestx) lowestx = min(min(pin.lx() for pin in pin_set), lowestx)
lowesty = min(min(pin.by() for pin in pin_set), lowesty) lowesty = min(min(pin.by() for pin in pin_set), lowesty)
return vector(lowestx, lowesty) return vector(lowestx, lowesty)
def find_highest_coords(self): def find_highest_coords(self):
@ -138,7 +142,7 @@ class layout():
this layout this layout
""" """
highestx = highesty = -sys.maxsize - 1 highestx = highesty = -sys.maxsize - 1
if len(self.objs) > 0: if len(self.objs) > 0:
highestx = max(max(obj.rx() for obj in self.objs if obj.name != "label"), highestx) highestx = max(max(obj.rx() for obj in self.objs if obj.name != "label"), highestx)
highesty = max(max(obj.uy() for obj in self.objs if obj.name != "label"), highesty) highesty = max(max(obj.uy() for obj in self.objs if obj.name != "label"), highesty)
@ -153,7 +157,7 @@ class layout():
continue continue
highestx = max(max(pin.rx() for pin in pin_set), highestx) highestx = max(max(pin.rx() for pin in pin_set), highestx)
highesty = max(max(pin.uy() for pin in pin_set), highesty) highesty = max(max(pin.uy() for pin in pin_set), highesty)
return vector(highestx, highesty) return vector(highestx, highesty)
def find_highest_layer_coords(self, layer): def find_highest_layer_coords(self, layer):
@ -234,7 +238,7 @@ class layout():
# This is commented out for runtime reasons # This is commented out for runtime reasons
# debug.info(4, "instance list: " + ",".join(x.name for x in self.insts)) # debug.info(4, "instance list: " + ",".join(x.name for x in self.insts))
return self.insts[-1] return self.insts[-1]
def get_inst(self, name): def get_inst(self, name):
""" Retrieve an instance by name """ """ Retrieve an instance by name """
for inst in self.insts: for inst in self.insts:
@ -332,7 +336,7 @@ class layout():
Return the pin or list of pins Return the pin or list of pins
""" """
name = self.get_pin_name(text) name = self.get_pin_name(text)
try: try:
if len(self.pin_map[name]) > 1: if len(self.pin_map[name]) > 1:
debug.error("Should use a pin iterator since more than one pin {}".format(text), -1) debug.error("Should use a pin iterator since more than one pin {}".format(text), -1)
@ -349,7 +353,7 @@ class layout():
Return a pin list (instead of a single pin) Return a pin list (instead of a single pin)
""" """
name = self.get_pin_name(text) name = self.get_pin_name(text)
if name in self.pin_map.keys(): if name in self.pin_map.keys():
return self.pin_map[name] return self.pin_map[name]
else: else:
@ -360,12 +364,12 @@ class layout():
Create a mapping from internal pin names to external pin names. Create a mapping from internal pin names to external pin names.
""" """
self.pin_names = pin_dict self.pin_names = pin_dict
self.original_pin_names = {y: x for (x, y) in self.pin_names.items()} self.original_pin_names = {y: x for (x, y) in self.pin_names.items()}
def get_pin_name(self, text): def get_pin_name(self, text):
""" Return the custom cell pin name """ """ Return the custom cell pin name """
if text in self.pin_names: if text in self.pin_names:
return self.pin_names[text] return self.pin_names[text]
else: else:
@ -373,7 +377,7 @@ class layout():
def get_original_pin_names(self): def get_original_pin_names(self):
""" Return the internal cell pin name """ """ Return the internal cell pin name """
# This uses the hierarchy_spice pins (in order) # This uses the hierarchy_spice pins (in order)
return [self.get_original_pin_name(x) for x in self.pins] return [self.get_original_pin_name(x) for x in self.pins]
@ -383,7 +387,7 @@ class layout():
return self.original_pin_names[text] return self.original_pin_names[text]
else: else:
return text return text
def get_pin_names(self): def get_pin_names(self):
""" """
Return a pin list of all pins Return a pin list of all pins
@ -480,7 +484,7 @@ class layout():
offset=s.ll(), offset=s.ll(),
width=s.width(), width=s.width(),
height=s.height()) height=s.height())
def replace_layout_pin(self, text, pin): def replace_layout_pin(self, text, pin):
""" """
Remove the old pin and replace with a new one Remove the old pin and replace with a new one
@ -495,7 +499,7 @@ class layout():
offset=pin.ll(), offset=pin.ll(),
width=pin.width(), width=pin.width(),
height=pin.height()) height=pin.height())
def add_layout_pin(self, text, layer, offset, width=None, height=None): def add_layout_pin(self, text, layer, offset, width=None, height=None):
""" """
Create a labeled pin Create a labeled pin
@ -777,7 +781,7 @@ class layout():
debug.info(3, "opening {}".format(self.gds_file)) debug.info(3, "opening {}".format(self.gds_file))
self.gds = gdsMill.VlsiLayout(units=GDS["unit"]) self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
reader = gdsMill.Gds2reader(self.gds) reader = gdsMill.Gds2reader(self.gds)
reader.loadFromFile(self.gds_file) reader.loadFromFile(self.gds_file, special_purposes)
else: else:
debug.info(3, "Creating layout structure {}".format(self.name)) debug.info(3, "Creating layout structure {}".format(self.name))
self.gds = gdsMill.VlsiLayout(name=self.name, units=GDS["unit"]) self.gds = gdsMill.VlsiLayout(name=self.name, units=GDS["unit"])
@ -789,7 +793,7 @@ class layout():
debug.info(4, "Printing {}".format(gds_file)) debug.info(4, "Printing {}".format(gds_file))
arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"]) arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"])
reader = gdsMill.Gds2reader(arrayCellLayout, debugToTerminal=1) reader = gdsMill.Gds2reader(arrayCellLayout, debugToTerminal=1)
reader.loadFromFile(gds_file) reader.loadFromFile(gds_file, special_purposes)
def clear_visited(self): def clear_visited(self):
""" Recursively clear the visited flag """ """ Recursively clear the visited flag """
@ -1126,7 +1130,7 @@ class layout():
# self.add_inst(cr.name, cr) # self.add_inst(cr.name, cr)
# self.connect_inst([]) # self.connect_inst([])
self.add_flat_inst(cr.name, cr) self.add_flat_inst(cr.name, cr)
def create_horizontal_channel_route(self, netlist, offset, layer_stack, directions=None): def create_horizontal_channel_route(self, netlist, offset, layer_stack, directions=None):
""" """
Wrapper to create a horizontal channel route Wrapper to create a horizontal channel route
@ -1138,7 +1142,7 @@ class layout():
# self.add_inst(cr.name, cr) # self.add_inst(cr.name, cr)
# self.connect_inst([]) # self.connect_inst([])
self.add_flat_inst(cr.name, cr) self.add_flat_inst(cr.name, cr)
def add_boundary(self, ll=vector(0, 0), ur=None): def add_boundary(self, ll=vector(0, 0), ur=None):
""" Add boundary for debugging dimensions """ """ Add boundary for debugging dimensions """
if OPTS.netlist_only: if OPTS.netlist_only:
@ -1331,7 +1335,7 @@ class layout():
new_name = pin.name new_name = pin.name
if not loc: if not loc:
loc = pin.center() loc = pin.center()
# Hack for min area # Hack for min area
if OPTS.tech_name == "sky130": if OPTS.tech_name == "sky130":
min_area = drc["minarea_{}".format(self.pwr_grid_layer)] min_area = drc["minarea_{}".format(self.pwr_grid_layer)]
@ -1340,7 +1344,7 @@ class layout():
else: else:
width = None width = None
height = None height = None
if pin.layer == self.pwr_grid_layer: if pin.layer == self.pwr_grid_layer:
self.add_layout_pin_rect_center(text=new_name, self.add_layout_pin_rect_center(text=new_name,
layer=self.pwr_grid_layer, layer=self.pwr_grid_layer,

View File

@ -79,7 +79,7 @@ class Gds2reader:
recordLength = struct.unpack(">h",recordLengthAscii) #gives us a tuple with a short int inside recordLength = struct.unpack(">h",recordLengthAscii) #gives us a tuple with a short int inside
offset_int = int(recordLength[0]) # extract length offset_int = int(recordLength[0]) # extract length
offset += offset_int # count offset offset += offset_int # count offset
if(self.debugToTerminal==1): if(self.debugToTerminal==1):
print("Offset: " + str(offset)) #print out the record numbers for de-bugging print("Offset: " + str(offset)) #print out the record numbers for de-bugging
record = self.fileHandle.read(recordLength[0]-2) #read the rest of it (first 2 bytes were already read) record = self.fileHandle.read(recordLength[0]-2) #read the rest of it (first 2 bytes were already read)
return record return record
@ -669,11 +669,11 @@ class Gds2reader:
else: else:
print("There was an error parsing the GDS header. Aborting...") print("There was an error parsing the GDS header. Aborting...")
def loadFromFile(self, fileName): def loadFromFile(self, fileName, special_purposes={}):
self.fileHandle = open(fileName,"rb") self.fileHandle = open(fileName,"rb")
self.readGds2() self.readGds2()
self.fileHandle.close() self.fileHandle.close()
self.layoutObject.initialize() self.layoutObject.initialize(special_purposes)
############################################## ##############################################

View File

@ -3,7 +3,7 @@ from datetime import *
import numpy as np import numpy as np
import math import math
import debug import debug
from tech import use_purpose
class VlsiLayout: class VlsiLayout:
"""Class represent a hierarchical layout""" """Class represent a hierarchical layout"""
@ -81,6 +81,12 @@ class VlsiLayout:
coordinatesRotate.extend((newX,newY)) coordinatesRotate.extend((newX,newY))
return coordinatesRotate return coordinatesRotate
def prefixAll(self, prefix):
for name in self.structures:
if name == self.rootStructureName:
continue
self.structures[prefix + name] = self.structures[name]
def rename(self,newName): def rename(self,newName):
# take the root structure and copy it to a new structure with the new name # take the root structure and copy it to a new structure with the new name
self.structures[newName] = self.structures[self.rootStructureName] self.structures[newName] = self.structures[self.rootStructureName]
@ -211,17 +217,17 @@ class VlsiLayout:
del transformPath[-1] del transformPath[-1]
return return
def initialize(self): def initialize(self, special_purposes={}):
self.deduceHierarchy() self.deduceHierarchy()
# self.traverseTheHierarchy() # self.traverseTheHierarchy()
self.populateCoordinateMap() self.populateCoordinateMap()
#only ones with text # only ones with text
for layerNumber in self.layerNumbersInUse: for layerNumber in self.layerNumbersInUse:
#if layerNumber not in no_pin_shape: # if layerNumber not in no_pin_shape:
if layerNumber in use_purpose: if layerNumber in special_purposes:
self.processLabelPins((layerNumber, use_purpose[layerNumber])) self.processLabelPins((layerNumber, special_purposes[layerNumber]))
else: else:
self.processLabelPins((layerNumber, None)) self.processLabelPins((layerNumber, None))
def populateCoordinateMap(self): def populateCoordinateMap(self):
def addToXyTree(startingStructureName = None,transformPath = None): def addToXyTree(startingStructureName = None,transformPath = None):

21
compiler/prefixGDS.py Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
import sys
from gdsMill import gdsMill
if len(sys.argv) < 4:
print("Script to prefix every instance and structure to create a unique namespace.")
print("Usage: {0} prefix in.gds out.gds".format(sys.argv[0]))
sys.exit(1)
prefix = sys.argv[1]
gds_file = sys.argv[2]
arrayCellLayout = gdsMill.VlsiLayout()
gds = gdsMill.Gds2reader(arrayCellLayout,debugToTerminal = 1)
gds.loadFromFile(gds_file)
gds.prefixAll(prefix)
writer = gdsMill.Gds2writer(gds)
writer.writeToFile(sys.argv[3])