OpenRAM/compiler/modules/rom_control_logic.py

141 lines
5.5 KiB
Python
Raw Normal View History

2022-12-30 09:35:15 +01:00
# See LICENSE for licensing information.
#
2023-02-28 00:56:24 +01:00
# Copyright (c) 2016-2023 Regents of the University of California and The Board
2022-12-30 09:35:15 +01:00
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from openram.sram_factory import factory
from openram.base import vector, design
2023-01-23 03:34:11 +01:00
from openram.tech import layer, drc
2022-12-30 09:35:15 +01:00
class rom_control_logic(design):
2023-01-23 03:34:11 +01:00
def __init__(self, num_outputs, clk_fanout, name="", height=None):
2022-12-30 09:35:15 +01:00
self.output_size = num_outputs
2023-01-23 03:34:11 +01:00
super().__init__(name, prop=False)
self.height = height
if self.height is not None:
2022-12-30 09:35:15 +01:00
2023-02-01 23:49:59 +01:00
self.driver_height = 0.5 * self.height
self.gate_height = 0.5 * self.height
2023-01-17 01:15:03 +01:00
else:
2023-01-23 03:34:11 +01:00
self.gate_height = 20 * self.m1_pitch
self.driver_height = self.gate_height
2023-01-17 01:15:03 +01:00
2023-03-01 06:10:52 +01:00
2023-01-23 03:34:11 +01:00
self.clk_fanout = clk_fanout
if "li" in layer:
self.route_stack = self.li_stack
else:
self.route_stack = self.m1_stack
2022-12-30 09:35:15 +01:00
self.create_netlist()
self.create_layout()
self.add_boundary()
def create_netlist(self):
self.add_modules()
self.add_pins()
def create_layout(self):
self.create_instances()
2023-01-23 03:34:11 +01:00
self.height=self.driver_inst.height + self.buf_inst.height
self.width= max(self.nand_inst.width + self.buf_inst.width, self.driver_inst.width)
2022-12-30 09:35:15 +01:00
self.place_instances()
self.route_insts()
def add_modules(self):
2023-03-01 06:10:52 +01:00
self.buf_mod = factory.create(module_type="pdriver",
module_name="rom_clock_driver",
2023-01-23 03:34:11 +01:00
height=self.gate_height,
fanout=self.clk_fanout + 2,
add_wells=True,
)
2023-03-01 06:10:52 +01:00
self.nand_mod = factory.create(module_type="pnand2",
module_name="rom_control_nand",
height=self.gate_height,
2023-01-23 03:34:11 +01:00
add_wells=False)
2023-03-01 06:10:52 +01:00
self.driver_mod = factory.create(module_type="pdriver",
module_name="rom_precharge_driver",
inverting=True,
fanout=self.output_size,
height=self.driver_height,
2023-01-23 03:34:11 +01:00
add_wells=True)
2023-02-28 00:56:24 +01:00
2022-12-30 09:35:15 +01:00
def add_pins(self):
2023-01-23 03:34:11 +01:00
self.add_pin("clk_in", "INPUT")
2022-12-30 09:35:15 +01:00
self.add_pin("CS", "INPUT")
self.add_pin("prechrg", "OUTPUT")
2023-01-23 03:34:11 +01:00
self.add_pin("clk_out", "OUTPUT")
2022-12-30 09:35:15 +01:00
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def create_instances(self):
2023-03-01 06:10:52 +01:00
self.buf_inst = self.add_inst(name="clk_driver", mod=self.buf_mod)
self.connect_inst(["clk_in", "clk_out", "vdd", "gnd"])
2022-12-30 09:35:15 +01:00
self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod)
self.connect_inst(["CS", "clk_out", "pre_drive", "vdd", "gnd"])
2022-12-30 09:35:15 +01:00
self.driver_inst = self.add_inst(name="precharge_driver", mod=self.driver_mod)
2022-12-30 09:35:15 +01:00
self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"])
def place_instances(self):
self.nand_inst.place(offset=[self.buf_inst.width, 0])
self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height], mirror="MX")
2023-03-03 07:47:47 +01:00
# hack to get around the fact these modules dont tile properly
offset = self.driver_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy()
self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height - offset], mirror="MX")
2022-12-30 09:35:15 +01:00
def route_insts(self):
2023-02-28 00:56:24 +01:00
2023-01-23 03:34:11 +01:00
route_width = drc["minwidth_{}".format(self.route_stack[2])]
self.copy_layout_pin(self.buf_inst, "A", "clk_in")
self.copy_layout_pin(self.buf_inst, "Z", "clk_out")
2022-12-30 09:35:15 +01:00
self.copy_layout_pin(self.driver_inst, "Z", "prechrg")
2023-02-01 23:49:59 +01:00
self.copy_layout_pin(self.nand_inst, "A", "CS")
2022-12-30 09:35:15 +01:00
self.copy_power_pin(self.buf_inst.get_pin("gnd"), directions="nonpref")
self.copy_power_pin(self.driver_inst.get_pin("gnd"), directions="nonpref")
self.copy_power_pin(self.buf_inst.get_pin("vdd"), directions="nonpref")
clk = self.buf_inst.get_pin("Z")
2022-12-30 09:35:15 +01:00
2023-01-23 03:34:11 +01:00
nand_B = self.nand_inst.get_pin("B")
2023-02-28 00:56:24 +01:00
2023-01-23 03:34:11 +01:00
# Connect buffered clock bar to nand input
mid = vector(clk.lx() - route_width - 2 * self.m1_space)
self.add_path(self.route_stack[2], [clk.center(), nand_B.center()])
2023-01-23 03:34:11 +01:00
self.add_via_stack_center(from_layer=clk.layer,
2023-01-23 03:34:11 +01:00
to_layer=self.route_stack[2],
offset=clk.center())
2023-01-23 03:34:11 +01:00
self.add_via_stack_center(from_layer=nand_B.layer,
to_layer=self.route_stack[2],
offset=nand_B.center())
# Connect nand output to precharge driver
nand_Z = self.nand_inst.get_pin("Z")
driver_A = self.driver_inst.get_pin("A")
mid = vector(driver_A.cx(), driver_A.cy() - 4 * route_width)
self.add_path(self.route_stack[2], [nand_Z.center(), mid, driver_A.center()])
2023-01-23 03:34:11 +01:00
self.add_via_stack_center(from_layer=nand_Z.layer,
to_layer=self.route_stack[2],
offset=nand_Z.center())
2023-02-28 00:56:24 +01:00
2023-01-23 03:34:11 +01:00
self.add_via_stack_center(from_layer=driver_A.layer,
to_layer=self.route_stack[2],
offset=driver_A.center())