mirror of https://github.com/VLSIDA/OpenRAM.git
131 lines
5.0 KiB
Python
131 lines
5.0 KiB
Python
# See LICENSE for licensing information.
|
|
#
|
|
# Copyright (c) 2016-2021 Regents of the University of California and The Board
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
# All rights reserved.
|
|
#
|
|
|
|
from openram.base import design
|
|
from openram.sram_factory import factory
|
|
from openram.base import vector
|
|
from openram.tech import layer, drc
|
|
|
|
|
|
|
|
class rom_inv_array(design):
|
|
"""
|
|
An array of inverters to create the inverted address lines for the rom decoder
|
|
"""
|
|
def __init__(self, cols, inv_size=None, name="", route_layer="m1"):
|
|
self.cols = cols
|
|
self.route_layer = route_layer
|
|
dff = factory.create(module_type="dff")
|
|
if name=="":
|
|
name = "rom_inv_array_{0}".format(cols)
|
|
if inv_size == None:
|
|
self.inv_size = dff.height * 0.5
|
|
else:
|
|
self.inv_size = inv_size
|
|
|
|
|
|
if "li" in layer:
|
|
self.inv_layer = "li"
|
|
else:
|
|
self.inv_layer = "m1"
|
|
super().__init__(name)
|
|
self.create_netlist()
|
|
self.create_layout()
|
|
|
|
def create_netlist(self):
|
|
self.create_modules()
|
|
self.add_pins()
|
|
self.create_instances()
|
|
|
|
|
|
def create_layout(self):
|
|
self.width = self.cols * self.poly_tap.height * 2
|
|
self.height = self.inv_mod.height
|
|
self.setup_layout_constants()
|
|
self.place_instances()
|
|
self.place_vias()
|
|
self.route_sources()
|
|
self.add_boundary()
|
|
|
|
|
|
def create_modules(self):
|
|
|
|
self.inv_mod = factory.create(module_type="pinv", module_name="inv_array_mod", height=self.inv_size, add_wells=False)
|
|
self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size)
|
|
# For layout constants
|
|
self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0)
|
|
|
|
def add_pins(self):
|
|
for col in range(self.cols):
|
|
self.add_pin("inv{0}_in".format(col), "INPUT")
|
|
self.add_pin("inv{0}_out".format(col), "OUTPUT")
|
|
self.add_pin("vdd", "POWER")
|
|
self.add_pin("gnd", "GROUND")
|
|
|
|
def create_instances(self):
|
|
self.inv_insts = []
|
|
|
|
for col in range(self.cols):
|
|
name = "Xinv_c{0}".format(col)
|
|
if col == self.cols - 1:
|
|
print("TAP ME DOWN")
|
|
self.inv_insts.append(self.add_inst(name=name, mod=self.end_inv))
|
|
else:
|
|
self.inv_insts.append(self.add_inst(name=name, mod=self.inv_mod))
|
|
inst_A = "inv{0}_in".format(col)
|
|
inst_Z = "inv{0}_out".format(col)
|
|
self.connect_inst([inst_A, inst_Z, "vdd", "gnd"])
|
|
|
|
def setup_layout_constants(self):
|
|
input_pin = self.inv_insts[0].get_pin("A")
|
|
output_pin = self.inv_insts[0].get_pin("Z")
|
|
|
|
# NEED TO OFFSET OUTPUT VIA IN ORDER TO ALIGN WITH PITCH OF ADDRESS INPUTS TO ARRAY
|
|
|
|
# print(self.poly_tap.get_pin("poly_tap").center())
|
|
|
|
# distance between input and output pins of inverter
|
|
in_out_distance = output_pin.cx() - input_pin.cx()
|
|
# distance from left edge of inverter to input plus right edge to output
|
|
edge_to_pins_distance = input_pin.cx() - self.inv_insts[0].lx() + self.inv_insts[0].rx() - output_pin.cx()
|
|
|
|
self.alignment_offset = edge_to_pins_distance - in_out_distance
|
|
|
|
def place_instances(self):
|
|
self.add_label("ZERO", self.route_layer)
|
|
for col in range(self.cols):
|
|
# base = vector(col*(self.inv_mod.width - self.alignment_offset), 0)
|
|
base = vector(col*(self.poly_tap.height * 2), 0)
|
|
self.inv_insts[col].place(offset=base)
|
|
#vdd_pin = self.inv_insts[0].get_pin("vdd").center()
|
|
#self.add_layout_pin_rect_center("vdd_align", self.inv_layer, vdd_pin, 0, 0)
|
|
|
|
def place_vias(self):
|
|
for i in range(self.cols):
|
|
input_pin = self.inv_insts[i].get_pin("A")
|
|
output_pin = self.inv_insts[i].get_pin("Z")
|
|
|
|
self.add_via_stack_center(input_pin.center(), self.inv_mod.route_layer, self.route_layer)
|
|
self.add_via_stack_center(output_pin.center(), self.inv_mod.route_layer, self.route_layer)
|
|
self.add_layout_pin_rect_center("inv{}_in".format(i), offset=input_pin.center(), layer=self.route_layer)
|
|
self.add_layout_pin_rect_center("inv{}_out".format(i), offset=output_pin.center(), layer=self.route_layer)
|
|
|
|
def route_sources(self):
|
|
|
|
vdd_start = self.inv_insts[0].get_pin("vdd")
|
|
vdd_end = self.inv_insts[-1].get_pin("vdd")
|
|
|
|
gnd_start = self.inv_insts[0].get_pin("gnd")
|
|
gnd_end = self.inv_insts[-1].get_pin("gnd")
|
|
|
|
self.copy_layout_pin(self.inv_insts[0], "vdd")
|
|
self.copy_layout_pin(self.inv_insts[0], "gnd")
|
|
# self.vdd = self.add_layout_pin_rect_ends("vdd", self.inv_layer, vdd_start.center(), vdd_end.center())[-1]
|
|
# self.gnd = self.add_layout_pin_rect_ends("gnd", self.inv_layer, gnd_start.center(), gnd_end.center())[-1]
|
|
|