OpenRAM/compiler/modules/rom_address_control_buf.py

215 lines
7.6 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_address_control_buf(design):
"""
Takes the input address lines and creates the address and address bar lines for the decoder.
Adds control logic for the precharge cycle so that all address lines are high before the read cycle
"""
def __init__(self, size, name="", route_layer="m1", add_wells=False):
self.route_layer = route_layer
self.add_wells = add_wells
self.size = 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.cell.height * 2
self.height = self.inv.width + 2 * self.nand.width
self.setup_layout_constants()
self.place_instances()
# self.place_vias()
self.route_gates()
self.route_sources()
self.add_boundary()
def create_modules(self):
# self.inv1_mod = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size, add_wells=False)
self.inv = factory.create(module_type="pinv_dec", module_name="inv_array_mod", add_wells=False, size=self.size)
# self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", size=self.size, add_wells=True)
self.nand = factory.create(module_type="nand2_dec", height=self.inv.height)
# For layout constants
self.cell = factory.create(module_type="rom_base_cell")
def add_pins(self):
self.add_pin("A_in", "INPUT")
self.add_pin("A_out", "INOUT")
self.add_pin("Abar_out", "OUTPUT")
self.add_pin("clk", "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def create_instances(self):
name = "XinvAbar"
self.inv_inst = self.add_inst(name=name, mod=self.inv)
inst_A = "A_in"
inst_Z = "Abar_internal"
self.connect_inst([inst_A, inst_Z, "vdd", "gnd"])
name = "Xnand_addr"
self.addr_nand = self.add_inst(name=name, mod=self.nand)
inst_A = "clk"
inst_B = "Abar_internal"
inst_Z = "A_out"
self.connect_inst([inst_A, inst_B, inst_Z, "vdd", "gnd"])
name = "Xnand_addr_bar"
self.addr_bar_nand = self.add_inst(name=name, mod=self.nand)
inst_A = "clk"
inst_B = "A_out"
inst_Z = "Abar_out"
self.connect_inst([inst_A, inst_B, inst_Z, "vdd", "gnd"])
def setup_layout_constants(self):
self.route_width = drc["minwidth_{}".format(self.route_layer)]
self.interconnect_width = drc["minwidth_{}".format(self.inv_layer)]
def place_instances(self):
self.inv_inst.place(offset=vector(self.inv_inst.height,0), rotate=90)
self.addr_nand.place(offset=vector(self.addr_nand.height , self.inv_inst.width + self.route_width ), rotate=90)
self.addr_bar_nand.place(offset=vector( self.addr_bar_nand.height, self.addr_nand.width + self.inv_inst.width + self.route_width), rotate=90)
def route_gates(self):
clk1_pin = self.addr_nand.get_pin("A")
clk2_pin = self.addr_bar_nand.get_pin("A")
# self.add_label("HERE I AM", "poly", clk_pins.cl())
Abar_out = self.addr_bar_nand.get_pin("Z")
A_out = self.addr_nand.get_pin("Z")
Abar_in = self.addr_nand.get_pin("B")
Abar_int_out = self.inv_inst.get_pin("Z")
Aint_in = self.addr_bar_nand.get_pin("B")
A_in = self.inv_inst.get_pin("A")
# Find the center of the pmos poly/gate
poly_right = clk1_pin.cx() + self.poly_enclose_contact + 0.5 * self.contact_width
ppoly_center = poly_right - 0.7 * self.poly_width
contact_offset = vector(ppoly_center, clk2_pin.cy())
# Route the two shared clk inputs together by connecting poly
self.add_segment_center("poly", contact_offset, vector(ppoly_center, A_out.cy()))
clk_offset = vector(clk2_pin.cx(), self.addr_nand.uy())
self.add_layout_pin_rect_center("clk", offset=clk_offset, layer=self.route_layer)
self.add_via_stack_center(from_layer=self.inv_layer, to_layer=self.route_layer, offset=self.addr_bar_nand.get_pin("A").center())
self.add_segment_center(self.route_layer, clk_offset, vector(clk_offset.x, clk2_pin.cy()))
# Route first NAND output to second NAND input
start = A_out.center()
end = Aint_in.center()
self.add_path("m2", [start, end])
self.add_via_stack_center(Aint_in.center(), self.inv_layer, "m2")
self.add_via_stack_center(A_out.center(), self.inv_layer, "m2")
# Route first NAND to output pin
self.add_segment_center("m2", end, vector(end.x, self.addr_bar_nand.uy()))
self.add_layout_pin_rect_center("A_out", offset=vector(end.x, self.addr_bar_nand.uy() - 0.5 * self.m2_width), layer="m2")
# Route second NAND to output pin
self.add_via_stack_center(Abar_out.center(), self.inv_layer, "m2")
self.add_segment_center("m2", Abar_out.center(), vector(Abar_out.cx(), self.addr_bar_nand.uy()))
self.add_layout_pin_rect_center("Abar_out", offset=vector(Abar_out.cx(), self.addr_bar_nand.uy() - 0.5 * self.m2_width), layer="m2")
# Route inverter output to NAND
end = vector(Abar_int_out.cx(), Abar_in.cy() + 0.5 * self.interconnect_width)
self.add_segment_center(self.inv_layer, Abar_int_out.center(), end)
self.copy_layout_pin(self.inv_inst, "A", "A_in")
def route_sources(self):
self.copy_layout_pin(self.addr_nand, "vdd")
self.copy_layout_pin(self.addr_bar_nand, "vdd")
self.copy_layout_pin(self.inv_inst, "vdd")
self.copy_layout_pin(self.addr_bar_nand, "gnd")
self.copy_layout_pin(self.addr_nand, "gnd")
self.copy_layout_pin(self.inv_inst, "gnd")
""" Add n/p well taps to the layout and connect to supplies """
source_pin = self.inv_inst.get_pin("vdd")
gnd_pin = self.inv_inst.get_pin("gnd")
left_edge = self.inv_inst.get_pin("Z").cx() - 2 * self.contact_width - 2 * self.active_contact_to_gate - 4 * self.active_enclose_contact - self.poly_width - self.active_space
contact_pos = vector(left_edge, source_pin.cy())
self.add_via_center(layers=self.active_stack,
offset=contact_pos,
implant_type="n",
well_type="n")
self.add_via_stack_center(offset=contact_pos,
from_layer=self.active_stack[2],
to_layer=self.route_layer)
contact_pos = vector(left_edge, gnd_pin.cy())
self.add_via_center(layers=self.active_stack,
offset=contact_pos,
implant_type="p",
well_type="p")
self.add_via_stack_center(offset=contact_pos,
from_layer=self.active_stack[2],
to_layer=self.route_layer)