Move pin name mapping to layout class.

This commit is contained in:
mrg 2020-11-16 11:04:03 -08:00
parent 93e94e26ec
commit 1d729e8f02
13 changed files with 101 additions and 92 deletions

View File

@ -8,30 +8,28 @@
class _cell:
def __init__(self, port_order, port_types, port_map=None, hard_cell=True, boundary_layer="boundary"):
# Specifies if this is a hard (i.e. GDS) cell
self._hard_cell = hard_cell
self._boundary_layer = boundary_layer
# Specifies the port directions
self._port_types_map = {x: y for (x, y) in zip(port_order, port_types)}
# Specifies a map from OpenRAM names to cell names
# by default it is 1:1
if not port_map:
port_map = {x: x for x in port_order}
self._port_map = {x: x for x in port_order}
# Update mapping of names
self._pins = _pins(port_map)
self._port_order = port_order
# Update ordered name list
self._port_names = [getattr(self._pins, x) for x in self._port_order]
self._port_names = [self._port_map[x] for x in self._port_order]
# Update ordered type list
self._port_types = [self._port_types_map[x] for x in port_order]
self._port_types = [self._port_types_map[x] for x in self._port_order]
@property
def pin(self):
return self._pins
@property
def hard_cell(self):
return self._hard_cell

View File

@ -35,9 +35,11 @@ class design(hierarchy_design):
# This means it is a custom cell.
# It could have properties and not be a hard cell too (e.g. dff_buf)
if prop and prop.hard_cell:
# The pins get added from the spice file
# The pins get added from the spice file, so just check
# that they matched here
debug.check(prop.port_names == self.pins,
"Custom cell pin names do not match spice file:\n{0} vs {1}".format(prop.port_names, self.pins))
self.add_pin_names(prop.port_map)
self.add_pin_types(prop.port_types)
(width, height) = utils.get_libcell_size(self.cell_name,

View File

@ -39,12 +39,21 @@ class layout():
self.width = None
self.height = None
self.bounding_box = None
self.insts = [] # Holds module/cell layout instances
self.inst_names = set() # Set of names to check for duplicates
self.objs = [] # Holds all other objects (labels, geometries, etc)
self.pin_map = {} # Holds name->pin_layout map for all pins
self.visited = [] # List of modules we have already visited
self.is_library_cell = False # Flag for library cells
# Holds module/cell layout instances
self.insts = []
# Set of names to check for duplicates
self.inst_names = set()
# Holds all other objects (labels, geometries, etc)
self.objs = []
# This is a mapping of internal pin names to cell pin names
# If the key is not found, the internal pin names is assumed
self.pin_names = {}
# Holds name->pin_layout map for all pins
self.pin_map = {}
# List of modules we have already visited
self.visited = []
# Flag for library cells
self.is_library_cell = False
self.gds_read()
@ -54,8 +63,13 @@ class layout():
except ImportError:
self.pwr_grid_layer = "m3"
def add_pin_names(self, pin_dict):
"""
Create a mapping from internal pin names to external pin names.
"""
self.pin_names = pin_dict
############################################################
# GDS layout
############################################################
@ -311,23 +325,33 @@ class layout():
"""
Return the pin or list of pins
"""
if text in self.pin_names:
name = self.pin_names[text]
else:
name = text
try:
if len(self.pin_map[text]) > 1:
if len(self.pin_map[name]) > 1:
debug.error("Should use a pin iterator since more than one pin {}".format(text), -1)
# If we have one pin, return it and not the list.
# Otherwise, should use get_pins()
any_pin = next(iter(self.pin_map[text]))
any_pin = next(iter(self.pin_map[name]))
return any_pin
except Exception:
self.gds_write("missing_pin.gds")
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(text, self.cell_name), -1)
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(name, self.cell_name), -1)
def get_pins(self, text):
"""
Return a pin list (instead of a single pin)
"""
if text in self.pin_map.keys():
return self.pin_map[text]
if text in self.pin_names:
name = self.pin_names[text]
else:
name = text
if name in self.pin_map.keys():
return self.pin_map[name]
else:
return set()

View File

@ -24,37 +24,35 @@ class bitcell_1port(bitcell_base.bitcell_base):
def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
row_pins = [props.bitcell_1port.pin.wl]
row_pins = ["wl"]
return row_pins
def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
pin = props.bitcell_1port.pin
column_pins = [pin.bl, pin.br]
return column_pins
return ["bl", "br"]
def get_all_bl_names(self):
""" Creates a list of all bl pins names """
return [props.bitcell_1port.pin.bl]
return ["bl"]
def get_all_br_names(self):
""" Creates a list of all br pins names """
return [props.bitcell_1port.pin.br]
return ["br"]
def get_bl_name(self, port=0):
"""Get bl name"""
debug.check(port == 0, "One port for bitcell only.")
return props.bitcell_1port.pin.bl
return "bl"
def get_br_name(self, port=0):
"""Get bl name"""
debug.check(port == 0, "One port for bitcell only.")
return props.bitcell_1port.pin.br
return "br"
def get_wl_name(self, port=0):
"""Get wl name"""
debug.check(port == 0, "One port for bitcell only.")
return props.bitcell_1port.pin.wl
return "wl"
def build_graph(self, graph, inst_name, port_nets):
"""

View File

@ -22,65 +22,56 @@ class bitcell_2port(bitcell_base.bitcell_base):
super().__init__(name, prop=props.bitcell_2port)
debug.info(2, "Create bitcell with 2 ports")
self.bl_names = [props.bitcell_2port.pin.bl0, props.bitcell_2port.pin.bl1]
self.br_names = [props.bitcell_2port.pin.br0, props.bitcell_2port.pin.br1]
self.wl_names = [props.bitcell_2port.pin.wl0, props.bitcell_2port.pin.wl1]
self.bl_names = ["bl0", "bl1"]
self.br_names = ["br0", "br1"]
self.wl_names = ["wl0", "wl1"]
def get_bitcell_pins(self, col, row):
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array
"""
pin_name = props.bitcell_2port.pin
bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col),
"{0}_{1}".format(pin_name.br0, col),
"{0}_{1}".format(pin_name.bl1, col),
"{0}_{1}".format(pin_name.br1, col),
"{0}_{1}".format(pin_name.wl0, row),
"{0}_{1}".format(pin_name.wl1, row),
bitcell_pins = ["bl0_{0}".format(col),
"br0_{0}".format(col),
"bl1_{0}".format(col),
"br1_{0}".format(col),
"wl0_{0}".format(row),
"wl1_{0}".format(row),
"vdd",
"gnd"]
return bitcell_pins
def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
return [props.bitcell_2port.pin.wl0,
props.bitcell_2port.pin.wl1]
return self.wl_names
def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
return [props.bitcell_2port.pin.bl0,
props.bitcell_2port.pin.br0,
props.bitcell_2port.pin.bl1,
props.bitcell_2port.pin.br1]
return ["bl0", "br0", "bl1", "br1"]
def get_all_bl_names(self):
""" Creates a list of all bl pins names """
return [props.bitcell_2port.pin.bl0,
props.bitcell_2port.pin.bl1]
return ["bl0", "bl1"]
def get_all_br_names(self):
""" Creates a list of all br pins names """
return [props.bitcell_2port.pin.br0,
props.bitcell_2port.pin.br1]
return ["br0", "br1"]
def get_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """
return [props.bitcell_2port.pin.bl0,
props.bitcell_2port.pin.bl1]
return ["bl0", "bl1"]
def get_read_br_names(self):
""" Creates a list of br pin names associated with read ports """
return [props.bitcell_2port.pin.br0,
props.bitcell_2port.pin.br1]
return ["br0", "br1"]
def get_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """
return [props.bitcell_2port.pin.bl0]
return ["bl0"]
def get_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports"""
return [props.bitcell_2port.pin.br1]
return ["br1"]
def get_bl_name(self, port=0):
"""Get bl name by port"""

View File

@ -26,9 +26,8 @@ class bitcell_base(design.design):
self.nets_match = self.do_nets_exist(prop.storage_nets)
self.mirror = prop.mirror
self.end_caps = prop.end_caps
self.supplies = [prop.pin.vdd, prop.pin.gnd]
else:
self.supplies = ["vdd", "gnd"]
self.supplies = ["vdd", "gnd"]
def get_stage_effort(self, load):
parasitic_delay = 1

View File

@ -42,11 +42,10 @@ class replica_bitcell_2port(bitcell_base.bitcell_base):
"""Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function."""
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
pins = props.bitcell_2port.pin
# Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.bl0], self)
graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.br0], self)
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self)
graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self)
# Port 1 edges
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.bl1], self)
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.br1], self)
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)

View File

@ -25,18 +25,18 @@ class sense_amp(design.design):
debug.info(2, "Create sense_amp")
def get_bl_names(self):
return props.sense_amp.pin.bl
return "bl"
def get_br_names(self):
return props.sense_amp.pin.br
return "br"
@property
def dout_name(self):
return props.sense_amp.pin.dout
return "dout"
@property
def en_name(self):
return props.sense_amp.pin.en
return "en"
def get_cin(self):

View File

@ -23,18 +23,18 @@ class write_driver(design.design):
debug.info(2, "Create write_driver")
def get_bl_names(self):
return props.write_driver.pin.bl
return "bl"
def get_br_names(self):
return props.write_driver.pin.br
return "br"
@property
def din_name(self):
return props.write_driver.pin.din
return "din"
@property
def en_name(self):
return props.write_driver.pin.en
return "en"
def get_w_en_cin(self):
"""Get the relative capacitance of a single input"""

View File

@ -6,7 +6,6 @@
# All rights reserved.
#
import design
from tech import cell_properties as props
import debug
from sram_factory import factory
import math

View File

@ -7,7 +7,6 @@
#
import debug
import design
from tech import cell_properties as props
from vector import vector
from sram_factory import factory
from globals import OPTS
@ -138,7 +137,7 @@ class dff_array(design.design):
height=dout_pin.height())
# Create vertical spines to a single horizontal rail
clk_pin = self.dff_insts[0, 0].get_pin(props.dff.pin.clk)
clk_pin = self.dff_insts[0, 0].get_pin("clk")
clk_ypos = 2 * self.m3_pitch + self.m3_width
debug.check(clk_pin.layer == "m2", "DFF clk pin not on metal2")
self.add_layout_pin_segment_center(text="clk",
@ -146,7 +145,7 @@ class dff_array(design.design):
start=vector(0, clk_ypos),
end=vector(self.width, clk_ypos))
for col in range(self.columns):
clk_pin = self.dff_insts[0, col].get_pin(props.dff.pin.clk)
clk_pin = self.dff_insts[0, col].get_pin("clk")
# Make a vertical strip for each column
self.add_rect(layer="m2",
offset=clk_pin.ll().scale(1, 0),

View File

@ -72,6 +72,7 @@ class dff_buf(design.design):
self.add_mod(self.inv2)
def add_pins(self):
self.add_pin_names(props.dff_buf.port_map)
self.add_pin_list(props.dff_buf.port_names,
props.dff_buf.port_types)
@ -79,15 +80,15 @@ class dff_buf(design.design):
self.dff_inst=self.add_inst(name="dff_buf_dff",
mod=self.dff)
self.connect_inst([props.dff_buf.pin.D, "qint", props.dff_buf.pin.clk, props.dff_buf.pin.vdd, props.dff_buf.pin.gnd])
self.connect_inst(["D", "qint", "clk", "vdd", "gnd"])
self.inv1_inst=self.add_inst(name="dff_buf_inv1",
mod=self.inv1)
self.connect_inst(["qint", "Qb", props.dff_buf.pin.vdd, props.dff_buf.pin.gnd])
self.connect_inst(["qint", "Qb", "vdd", "gnd"])
self.inv2_inst=self.add_inst(name="dff_buf_inv2",
mod=self.inv2)
self.connect_inst(["Qb", props.dff_buf.pin.Q, props.dff_buf.pin.vdd, props.dff_buf.pin.gnd])
self.connect_inst(["Qb", "Q", "vdd", "gnd"])
def place_instances(self):
# Add the DFF
@ -121,7 +122,7 @@ class dff_buf(design.design):
self.route_layer = "m1"
# Route dff q to inv1 a
q_pin = self.dff_inst.get_pin(props.dff.pin.Q)
q_pin = self.dff_inst.get_pin("Q")
a1_pin = self.inv1_inst.get_pin("A")
mid1 = vector(a1_pin.cx(), q_pin.cy())
self.add_path(q_pin.layer, [q_pin.center(), mid1, a1_pin.center()], width=q_pin.height())
@ -138,30 +139,30 @@ class dff_buf(design.design):
def add_layout_pins(self):
# Continous vdd rail along with label.
vdd_pin=self.dff_inst.get_pin(props.dff.pin.vdd)
self.add_layout_pin(text=props.dff_buf.pin.vdd,
vdd_pin=self.dff_inst.get_pin("vdd")
self.add_layout_pin(text="vdd",
layer=vdd_pin.layer,
offset=vdd_pin.ll(),
width=self.width,
height=vdd_pin.height())
# Continous gnd rail along with label.
gnd_pin=self.dff_inst.get_pin(props.dff.pin.gnd)
self.add_layout_pin(text=props.dff_buf.pin.gnd,
gnd_pin=self.dff_inst.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer=gnd_pin.layer,
offset=gnd_pin.ll(),
width=self.width,
height=vdd_pin.height())
clk_pin = self.dff_inst.get_pin(props.dff.pin.clk)
self.add_layout_pin(text=props.dff_buf.pin.clk,
clk_pin = self.dff_inst.get_pin("clk")
self.add_layout_pin(text="clk",
layer=clk_pin.layer,
offset=clk_pin.ll(),
width=clk_pin.width(),
height=clk_pin.height())
din_pin = self.dff_inst.get_pin(props.dff_buf.pin.D)
self.add_layout_pin(text=props.dff_buf.pin.D,
din_pin = self.dff_inst.get_pin("D")
self.add_layout_pin(text="D",
layer=din_pin.layer,
offset=din_pin.ll(),
width=din_pin.width(),
@ -170,7 +171,7 @@ class dff_buf(design.design):
dout_pin = self.inv2_inst.get_pin("Z")
mid_pos = dout_pin.center() + vector(self.m2_nonpref_pitch, 0)
q_pos = mid_pos - vector(0, 2 * self.m2_nonpref_pitch)
self.add_layout_pin_rect_center(text=props.dff_buf.pin.Q,
self.add_layout_pin_rect_center(text="Q",
layer="m2",
offset=q_pos)
self.add_path(self.route_layer, [dout_pin.center(), mid_pos, q_pos])

View File

@ -7,7 +7,6 @@
#
import debug
import design
from tech import cell_properties as props
from vector import vector
from globals import OPTS
from sram_factory import factory
@ -148,7 +147,7 @@ class dff_buf_array(design.design):
def route_supplies(self):
for row in range(self.rows):
vdd0_pin=self.dff_insts[row, 0].get_pin(props.dff.pin.vdd)
vdd0_pin=self.dff_insts[row, 0].get_pin("vdd")
vddn_pin=self.dff_insts[row, self.columns - 1].get_pin("vdd")
self.add_path(vdd0_pin.layer, [vdd0_pin.lc(), vddn_pin.rc()], width=vdd0_pin.height())