OpenRAM/compiler/modules/rom_decoder.py

243 lines
9.2 KiB
Python
Raw Normal View History

2022-12-09 23:25:11 +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-09 23:25:11 +01:00
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from math import ceil, log
from openram.sram_factory import factory
2022-12-30 09:35:15 +01:00
from openram.base import vector, design
from openram import OPTS
from openram.tech import drc
2022-12-09 23:25:11 +01:00
class rom_decoder(design):
def __init__(self, num_outputs, fanout, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False):
2023-02-28 00:56:24 +01:00
2023-03-02 00:49:43 +01:00
# word lines in the base array become the address lines/cols in the decoder
# bit lines in the base array become the word lines/rows in the decoder
# array gets rotated 90deg so rows/cols switch
2022-12-09 23:25:11 +01:00
self.strap_spacing=strap_spacing
self.num_outputs = num_outputs
self.num_inputs = ceil(log(num_outputs, 2))
2022-12-09 23:25:11 +01:00
self.create_decode_map()
2023-03-01 06:10:52 +01:00
2022-12-09 23:25:11 +01:00
super().__init__(name)
b = factory.create(module_type=OPTS.bitcell)
self.cell_height = b.height
self.route_layer = route_layer
self.output_layer = output_layer
2023-01-17 01:15:03 +01:00
self.inv_route_layer = "m2"
self.fanout=fanout
2023-01-23 03:34:11 +01:00
self.invert_outputs=invert_outputs
2022-12-09 23:25:11 +01:00
self.create_netlist()
2023-01-23 03:34:11 +01:00
self.width = self.array_mod.height + self.wordline_buf.width
self.height = self.array_mod.width + self.control_array.height
2022-12-09 23:25:11 +01:00
self.create_layout()
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_instances()
def create_layout(self):
2023-01-17 01:15:03 +01:00
self.setup_layout_constants()
2022-12-09 23:25:11 +01:00
self.place_array()
2023-01-17 01:15:03 +01:00
self.place_input_buffer()
self.place_driver()
self.route_outputs()
2023-03-01 06:10:52 +01:00
2022-12-09 23:25:11 +01:00
self.connect_inputs()
2023-01-23 03:34:11 +01:00
self.route_supplies()
2022-12-09 23:25:11 +01:00
self.add_boundary()
2023-02-28 00:56:24 +01:00
def add_boundary(self):
ll = self.find_lowest_coords()
m1_offset = self.m1_width
self.translate_all(vector(0, ll.y))
ur = self.find_highest_coords()
2023-02-28 00:56:24 +01:00
ur = vector(ur.x, ur.y)
super().add_boundary(ll, ur)
self.width = ur.x
2023-03-01 06:10:52 +01:00
self.height = ur.y
2022-12-09 23:25:11 +01:00
2023-01-17 01:15:03 +01:00
def setup_layout_constants(self):
self.inv_route_width = drc["minwidth_{}".format(self.inv_route_layer)]
2022-12-09 23:25:11 +01:00
def create_decode_map(self):
self.decode_map = []
# create decoding map that will be the bitmap for the rom decoder
# row/col order in the map will be switched in the placed decoder/
for col in range(self.num_inputs):
2023-02-28 00:56:24 +01:00
2022-12-09 23:25:11 +01:00
# odd cols are address
# even cols are address bar
col_array = []
inv_col_array = []
for row in range(self.num_outputs):
2023-01-17 01:15:03 +01:00
addr_idx = -col - 1
2022-12-09 23:25:11 +01:00
addr = format(row, 'b')
if col >= len(addr) :
bin_digit = 0
else:
bin_digit = int(addr[addr_idx])
2023-03-01 06:10:52 +01:00
col_array.append(bin_digit)
2022-12-09 23:25:11 +01:00
if bin_digit == 0 : inv_col_array.append(1)
else : inv_col_array.append(0)
self.decode_map.append(col_array)
self.decode_map.append(inv_col_array)
self.decode_map.reverse()
def add_pins(self):
for i in range(self.num_inputs):
2023-01-17 01:15:03 +01:00
self.add_pin("A{0}".format(i), "INPUT")
2022-12-09 23:25:11 +01:00
for j in range(self.num_outputs):
2023-01-17 01:15:03 +01:00
self.add_pin("wl_{0}".format(j), "OUTPUT")
2023-01-23 03:34:11 +01:00
self.add_pin("precharge", "INPUT")
self.add_pin("clk", "INPUT")
2022-12-09 23:25:11 +01:00
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self):
2023-03-01 06:10:52 +01:00
self.control_array = factory.create(module_type="rom_address_control_array",
2023-01-23 03:34:11 +01:00
cols=self.num_inputs)
2023-03-01 06:10:52 +01:00
self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name),
rows=self.num_outputs,
fanout=ceil(self.fanout),
2023-01-23 03:34:11 +01:00
invert_outputs=self.invert_outputs,
tap_spacing=self.strap_spacing)
2023-03-01 06:10:52 +01:00
self.array_mod = factory.create(module_type="rom_base_array",
module_name="{}_array".format(self.name),
cols=self.num_outputs,
rows=2 * self.num_inputs,
2022-12-09 23:25:11 +01:00
bitmap=self.decode_map,
strap_spacing = self.strap_spacing,
2023-01-23 03:34:11 +01:00
bitline_layer=self.output_layer,
tap_direction="col")
2022-12-09 23:25:11 +01:00
def create_instances(self):
self.create_array_inst()
2023-01-17 01:15:03 +01:00
self.create_input_buffer()
self.create_wordline_buffer()
2022-12-09 23:25:11 +01:00
2023-01-17 01:15:03 +01:00
def create_input_buffer(self):
name = "pre_control_array"
self.buf_inst = self.add_inst(name=name, mod=self.control_array)
2022-12-09 23:25:11 +01:00
2023-01-17 01:15:03 +01:00
control_pins = []
2022-12-09 23:25:11 +01:00
for i in range(self.num_inputs):
2023-01-17 01:15:03 +01:00
control_pins.append("A{0}".format(i))
2023-01-27 00:48:38 +01:00
for i in range(self.num_inputs):
control_pins.append("A_int_{0}".format(i))
for i in range(self.num_inputs):
control_pins.append("Ab_int_{0}".format(i))
2023-02-28 00:56:24 +01:00
2023-01-17 01:15:03 +01:00
control_pins.append("clk")
control_pins.append("vdd")
control_pins.append("gnd")
self.connect_inst(control_pins)
2022-12-09 23:25:11 +01:00
def create_array_inst(self):
self.array_inst = self.add_inst(name="decode_array_inst", mod=self.array_mod)
2023-02-28 00:56:24 +01:00
2022-12-09 23:25:11 +01:00
array_pins = []
for j in range(self.num_outputs):
2023-01-17 01:15:03 +01:00
name = "wl_int{0}".format(j)
2022-12-09 23:25:11 +01:00
array_pins.append(name)
for i in reversed(range(self.num_inputs)):
2023-01-27 00:48:38 +01:00
array_pins.append("Ab_int_{0}".format(i))
array_pins.append("A_int_{0}".format(i))
2023-01-23 03:34:11 +01:00
array_pins.append("precharge")
2022-12-09 23:25:11 +01:00
array_pins.append("vdd")
array_pins.append("gnd")
self.connect_inst(array_pins)
2023-01-17 01:15:03 +01:00
def create_wordline_buffer(self):
self.wordline_buf_inst = self.add_inst("rom_wordline_driver", mod=self.wordline_buf)
in_pins = ["wl_int{}".format(wl) for wl in range(self.num_outputs)]
out_pins = ["wl_{}".format(wl) for wl in range(self.num_outputs)]
pwr_pins = ["vdd", "gnd"]
self.connect_inst(in_pins + out_pins + pwr_pins)
def place_input_buffer(self):
wl = self.array_mod.row_size - 1
align = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl]).cx() - self.buf_inst.get_pin("A0_out").cx()
self.buf_inst.place(vector(align, 0))
2022-12-09 23:25:11 +01:00
2023-01-23 03:34:11 +01:00
self.copy_layout_pin(self.buf_inst, "clk")
2022-12-09 23:25:11 +01:00
def place_array(self):
2023-01-17 01:15:03 +01:00
offset = vector(self.array_mod.height, self.control_array.height + self.m1_width + self.poly_contact.width)
2022-12-09 23:25:11 +01:00
self.array_inst.place(offset, rotate=90)
2023-02-28 00:56:24 +01:00
2023-01-17 01:15:03 +01:00
def place_driver(self):
2023-03-01 06:10:52 +01:00
2023-01-17 01:15:03 +01:00
offset = vector(self.array_inst.height + self.m1_width, self.array_inst.by())
self.wordline_buf_inst.place(offset)
2022-12-09 23:25:11 +01:00
2023-01-17 01:15:03 +01:00
# calculate the offset between the decode array and the buffer inputs now that their zeros are aligned
pin_offset = self.array_inst.get_pin("bl_0_0").cy() - self.wordline_buf_inst.get_pin("in_0").cy()
self.wordline_buf_inst.place(offset + vector(0, pin_offset))
2022-12-09 23:25:11 +01:00
2023-01-17 01:15:03 +01:00
def route_outputs(self):
2022-12-09 23:25:11 +01:00
for j in range(self.num_outputs):
2023-01-17 01:15:03 +01:00
self.copy_layout_pin(self.wordline_buf_inst, "out_{}".format(j), "wl_{}".format(j))
2023-01-23 03:34:11 +01:00
offset = self.wordline_buf_inst.get_pin("out_{}".format(j)).center()
2023-01-17 01:15:03 +01:00
array_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.num_outputs)]
driver_pins = [self.wordline_buf_inst.get_pin("in_{}".format(bl)) for bl in range(self.num_outputs)]
route_pins = array_pins + driver_pins
self.connect_row_pins(self.output_layer, route_pins, round=True)
2022-12-09 23:25:11 +01:00
def connect_inputs(self):
2022-12-30 09:35:15 +01:00
self.copy_layout_pin(self.array_inst, "precharge")
self.copy_layout_pin(self.array_inst, "precharge_r")
2022-12-09 23:25:11 +01:00
for i in range(self.num_inputs):
2023-01-17 01:15:03 +01:00
wl = (self.num_inputs - i) * 2 - 1
2022-12-09 23:25:11 +01:00
wl_bar = wl - 1
addr_pin = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl])
addr_bar_pin = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl_bar])
2023-01-17 01:15:03 +01:00
addr_out_pin = self.buf_inst.get_pin("A{}_out".format(i))
addr_bar_out_pin = self.buf_inst.get_pin("Abar{}_out".format(i))
addr_middle = vector(addr_pin.cx(), addr_out_pin.cy())
2023-03-01 06:10:52 +01:00
2023-01-17 01:15:03 +01:00
addr_bar_middle = vector(addr_bar_pin.cx(), addr_bar_out_pin.cy())
2022-12-09 23:25:11 +01:00
2023-01-17 01:15:03 +01:00
self.add_path(self.inv_route_layer, [addr_out_pin.center(), addr_middle, addr_pin.center()])
self.add_path(self.inv_route_layer, [addr_bar_out_pin.center(), addr_bar_middle, addr_bar_pin.center()])
2023-01-27 00:48:38 +01:00
self.copy_layout_pin(self.buf_inst, "A{}_in".format(i), "A{}".format(i))
2022-12-09 23:25:11 +01:00
def route_supplies(self):
2023-01-27 02:33:47 +01:00
2023-01-23 03:34:11 +01:00
self.copy_layout_pin(self.array_inst, "vdd")
self.copy_layout_pin(self.wordline_buf_inst, "vdd")
self.copy_layout_pin(self.buf_inst, "vdd")
2022-12-09 23:25:11 +01:00
2023-01-23 03:34:11 +01:00
self.copy_layout_pin(self.array_inst, "gnd")
self.copy_layout_pin(self.wordline_buf_inst, "gnd")
2023-02-28 00:56:24 +01:00
self.copy_layout_pin(self.buf_inst, "gnd")