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 pin_layout import pin_layout
from utils import round_to_grid
try:
from tech import special_purposes
except ImportError:
special_purposes = {}
class layout():
@ -36,9 +40,9 @@ class layout():
# This gets set in both spice and layout so either can be called first.
self.name = name
self.cell_name = cell_name
self.gds_file = OPTS.openram_tech + "gds_lib/" + cell_name + ".gds"
self.width = None
self.height = None
self.bounding_box = None # The rectangle shape
@ -58,7 +62,7 @@ class layout():
self.visited = []
# Flag for library cells
self.is_library_cell = False
self.gds_read()
try:
@ -66,7 +70,7 @@ class layout():
self.pwr_grid_layer = power_grid[0]
except ImportError:
self.pwr_grid_layer = "m3"
############################################################
# GDS layout
############################################################
@ -118,7 +122,7 @@ class layout():
if len(self.objs) > 0:
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)
if len(self.insts) > 0:
lowestx = min(min(inst.lx() for inst in self.insts), lowestx)
lowesty = min(min(inst.by() for inst in self.insts), lowesty)
@ -129,7 +133,7 @@ class layout():
continue
lowestx = min(min(pin.lx() for pin in pin_set), lowestx)
lowesty = min(min(pin.by() for pin in pin_set), lowesty)
return vector(lowestx, lowesty)
def find_highest_coords(self):
@ -138,7 +142,7 @@ class layout():
this layout
"""
highestx = highesty = -sys.maxsize - 1
if len(self.objs) > 0:
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)
@ -153,7 +157,7 @@ class layout():
continue
highestx = max(max(pin.rx() for pin in pin_set), highestx)
highesty = max(max(pin.uy() for pin in pin_set), highesty)
return vector(highestx, highesty)
def find_highest_layer_coords(self, layer):
@ -234,7 +238,7 @@ class layout():
# This is commented out for runtime reasons
# debug.info(4, "instance list: " + ",".join(x.name for x in self.insts))
return self.insts[-1]
def get_inst(self, name):
""" Retrieve an instance by name """
for inst in self.insts:
@ -332,7 +336,7 @@ class layout():
Return the pin or list of pins
"""
name = self.get_pin_name(text)
try:
if len(self.pin_map[name]) > 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)
"""
name = self.get_pin_name(text)
if name in self.pin_map.keys():
return self.pin_map[name]
else:
@ -360,12 +364,12 @@ class layout():
Create a mapping from internal pin names to external pin names.
"""
self.pin_names = pin_dict
self.original_pin_names = {y: x for (x, y) in self.pin_names.items()}
def get_pin_name(self, text):
""" Return the custom cell pin name """
if text in self.pin_names:
return self.pin_names[text]
else:
@ -373,7 +377,7 @@ class layout():
def get_original_pin_names(self):
""" Return the internal cell pin name """
# This uses the hierarchy_spice pins (in order)
return [self.get_original_pin_name(x) for x in self.pins]
@ -383,7 +387,7 @@ class layout():
return self.original_pin_names[text]
else:
return text
def get_pin_names(self):
"""
Return a pin list of all pins
@ -480,7 +484,7 @@ class layout():
offset=s.ll(),
width=s.width(),
height=s.height())
def replace_layout_pin(self, text, pin):
"""
Remove the old pin and replace with a new one
@ -495,7 +499,7 @@ class layout():
offset=pin.ll(),
width=pin.width(),
height=pin.height())
def add_layout_pin(self, text, layer, offset, width=None, height=None):
"""
Create a labeled pin
@ -777,7 +781,7 @@ class layout():
debug.info(3, "opening {}".format(self.gds_file))
self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
reader = gdsMill.Gds2reader(self.gds)
reader.loadFromFile(self.gds_file)
reader.loadFromFile(self.gds_file, special_purposes)
else:
debug.info(3, "Creating layout structure {}".format(self.name))
self.gds = gdsMill.VlsiLayout(name=self.name, units=GDS["unit"])
@ -789,7 +793,7 @@ class layout():
debug.info(4, "Printing {}".format(gds_file))
arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"])
reader = gdsMill.Gds2reader(arrayCellLayout, debugToTerminal=1)
reader.loadFromFile(gds_file)
reader.loadFromFile(gds_file, special_purposes)
def clear_visited(self):
""" Recursively clear the visited flag """
@ -1126,7 +1130,7 @@ class layout():
# self.add_inst(cr.name, cr)
# self.connect_inst([])
self.add_flat_inst(cr.name, cr)
def create_horizontal_channel_route(self, netlist, offset, layer_stack, directions=None):
"""
Wrapper to create a horizontal channel route
@ -1138,7 +1142,7 @@ class layout():
# self.add_inst(cr.name, cr)
# self.connect_inst([])
self.add_flat_inst(cr.name, cr)
def add_boundary(self, ll=vector(0, 0), ur=None):
""" Add boundary for debugging dimensions """
if OPTS.netlist_only:
@ -1331,7 +1335,7 @@ class layout():
new_name = pin.name
if not loc:
loc = pin.center()
# Hack for min area
if OPTS.tech_name == "sky130":
min_area = drc["minarea_{}".format(self.pwr_grid_layer)]
@ -1340,7 +1344,7 @@ class layout():
else:
width = None
height = None
if pin.layer == self.pwr_grid_layer:
self.add_layout_pin_rect_center(text=new_name,
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
offset_int = int(recordLength[0]) # extract length
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
record = self.fileHandle.read(recordLength[0]-2) #read the rest of it (first 2 bytes were already read)
return record
@ -669,11 +669,11 @@ class Gds2reader:
else:
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.readGds2()
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 math
import debug
from tech import use_purpose
class VlsiLayout:
"""Class represent a hierarchical layout"""
@ -81,6 +81,12 @@ class VlsiLayout:
coordinatesRotate.extend((newX,newY))
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):
# take the root structure and copy it to a new structure with the new name
self.structures[newName] = self.structures[self.rootStructureName]
@ -211,17 +217,17 @@ class VlsiLayout:
del transformPath[-1]
return
def initialize(self):
def initialize(self, special_purposes={}):
self.deduceHierarchy()
# self.traverseTheHierarchy()
self.populateCoordinateMap()
#only ones with text
# only ones with text
for layerNumber in self.layerNumbersInUse:
#if layerNumber not in no_pin_shape:
if layerNumber in use_purpose:
self.processLabelPins((layerNumber, use_purpose[layerNumber]))
else:
self.processLabelPins((layerNumber, None))
# if layerNumber not in no_pin_shape:
if layerNumber in special_purposes:
self.processLabelPins((layerNumber, special_purposes[layerNumber]))
else:
self.processLabelPins((layerNumber, None))
def populateCoordinateMap(self):
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])