OpenRAM/compiler/single_level_column_mux_arr...

273 lines
13 KiB
Python

from math import log
import design
from single_level_column_mux import single_level_column_mux
from contact import contact
from tech import drc
import debug
import math
from vector import vector
class single_level_column_mux_array(design.design):
"""
Dynamically generated column mux array.
Array of column mux to read the bitlines through the 6T.
"""
def __init__(self, rows, columns, word_size):
design.design.__init__(self, "columnmux_array")
debug.info(1, "Creating {0}".format(self.name))
self.rows = rows
self.columns = columns
self.word_size = word_size
self.words_per_row = self.columns / self.word_size
self.row_addr_size = self.decoder_inputs = int(math.log(self.rows, 2))
self.add_pins()
self.create_layout()
self.offset_all_coordinates()
self.DRC_LVS()
def add_pins(self):
for i in range(self.columns):
self.add_pin("bl[{0}]".format(i))
self.add_pin("br[{0}]".format(i))
for i in range(self.columns / self.words_per_row):
self.add_pin("bl_out[{0}]".format(i * self.words_per_row))
self.add_pin("br_out[{0}]".format(i * self.words_per_row))
for i in range(self.words_per_row):
self.add_pin("sel[{0}]".format(i))
self.add_pin("gnd")
def create_layout(self):
self.add_modules()
self.setup_layout_constants()
self.create_array()
self.add_routing()
def add_modules(self):
self.mux = single_level_column_mux(name="single_level_column_mux",
tx_size=8)
self.single_mux = self.mux
self.add_mod(self.mux)
# This is not instantiated and used for calculations only.
self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2"))
def setup_layout_constants(self):
self.column_addr_size = num_of_inputs = int(self.words_per_row / 2)
self.width = (self.columns * self.mux.width)
self.gnd_positions = []
self.BL_out_positions = []
self.BR_out_positions = []
self.BL_positions = []
self.BR_positions = []
self.addr_line_positions = []
spacing = self.m1m2_via.width + drc['metal1_to_metal1']
self.height = self.mux.height + spacing + 4 * drc['metal2_to_metal2']
if (self.words_per_row > 1):
# 1 for BL and another for BR
self.height = self.height + (self.words_per_row + 1) * spacing
def create_array(self):
for i in range(self.columns):
name = "XMUX{0}".format(i)
x_off = vector(i * self.mux.width, 0)
self.add_inst(name=name,
mod=self.mux,
offset=x_off)
""" draw a vertical m2 rail to extend BL BR & gnd on top of the cell """
# FIXME: These are just min metal squares, are they needed?
self.add_rect(layer="metal2",
offset=x_off + self.mux.BL_position,
width=drc['minwidth_metal2'],
height=drc['minwidth_metal2'])
self.add_rect(layer="metal2",
offset=x_off + self.mux.BR_position,
width=drc['minwidth_metal2'],
height=drc['minwidth_metal2'])
self.add_rect(layer="metal2",
offset=x_off + self.mux.gnd_position,
width=drc['minwidth_metal2'],
height=drc['minwidth_metal2'])
""" add labels for the column_mux array """
BL = self.mux.BL_position + vector(i * self.mux.width, 0)
self.BL_positions.append(BL)
self.add_label(text="bl[{0}]".format(i),
layer="metal2",
offset=BL)
BR = self.mux.BR_position + vector(i * self.mux.width, 0)
self.BR_positions.append(BR)
self.add_label(text="br[{0}]".format(i),
layer="metal2",
offset=BR)
gnd = self.mux.gnd_position + vector(i * self.mux.width, 0)
self.gnd_positions.append(gnd)
self.add_label(text="gnd",
layer="metal2",
offset=gnd)
for i in range(self.word_size):
base =vector(i * self.words_per_row * self.mux.width, 0)
BL_out = base + self.mux.BL_out_position
BR_out = base + self.mux.BR_out_position
self.add_label(text="bl_out[{0}]".format(i * self.words_per_row),
layer="metal2",
offset=BL_out)
self.add_label(text="br_out[{0}]".format(i * self.words_per_row),
layer="metal2",
offset=BR_out)
self.BL_out_positions.append(BL_out)
self.BR_out_positions.append(BR_out)
if(self.words_per_row == 2):
for i in range(self.columns / 2):
# This will not check that the inst connections match.
self.connect_inst(args=["bl[{0}]".format(2 * i),
"br[{0}]".format(2 * i),
"bl_out[{0}]".format(2 * i),
"br_out[{0}]".format(2 * i),
"sel[{0}]".format(0), "gnd"],
check=False)
# This will not check that the inst connections match.
self.connect_inst(args=["bl[{0}]".format(2 * i + 1),
"br[{0}]".format(2 * i + 1),
"bl_out[{0}]".format(2 * i),
"br_out[{0}]".format(2 * i),
"sel[{0}]".format(1), "gnd"],
check=False)
if(self.words_per_row == 4):
for i in range(self.columns / 4):
# This will not check that the inst connections match.
self.connect_inst(args=["bl[{0}]".format(4 * i),
"br[{0}]".format(4 * i),
"bl_out[{0}]".format(4 * i),
"br_out[{0}]".format(4 * i),
"sel[{0}]".format(0), "gnd"],
check=False)
# This will not check that the inst connections match.
self.connect_inst(args=["bl[{0}]".format(4 * i + 1),
"br[{0}]".format(4 * i + 1),
"bl_out[{0}]".format(4 * i),
"br_out[{0}]".format(4 * i),
"sel[{0}]".format(1), "gnd"],
check=False)
# This will not check that the inst connections match.
self.connect_inst(args=["bl[{0}]".format(4 * i + 2),
"br[{0}]".format(4 * i + 2),
"bl_out[{0}]".format(4 * i),
"br_out[{0}]".format(4 * i),
"sel[{0}]".format(2), "gnd"],
check=False)
# This will not check that the inst connections match.
self.connect_inst(args=["bl[{0}]".format(4 * i + 3),
"br[{0}]".format(4 * i + 3),
"bl_out[{0}]".format(4 * i),
"br_out[{0}]".format(4 * i),
"sel[{0}]".format(3), "gnd"],
check=False)
def add_routing(self):
self.add_horizontal_input_rail()
self.add_vertical_poly_rail()
self.routing_BL_BR()
def add_horizontal_input_rail(self):
""" HORIZONTAL ADDRESS INPUTS TO THE COLUMN MUX ARRAY """
if (self.words_per_row > 1):
for j in range(self.words_per_row):
offset = vector(0, -(j + 1) * self.m1m2_via.width
- j * drc['metal1_to_metal1'])
self.add_rect(layer="metal1",
offset=offset,
width=self.mux.width * self.columns,
height=self.m1m2_via.width)
self.addr_line_positions.append(offset)
def add_vertical_poly_rail(self):
""" VERTICAL POLY METAL EXTENSION AND POLY CONTACT """
for j1 in range(self.columns):
pattern = math.floor(j1 / self.words_per_row) * self.words_per_row
height = ((self.m1m2_via.width + drc['metal1_to_metal1'])
*(pattern - j1))
nmos1_poly = self.mux.nmos1_position + self.mux.nmos1.poly_positions[0]
offset = nmos1_poly.scale(1, 0) + vector(j1 * self.mux.width, 0)
self.add_rect(layer="poly",
offset=offset,
width=drc["minwidth_poly"],
height= height -self.m1m2_via.width)
# This is not instantiated and used for calculations only.
poly_contact = contact(layer_stack=("metal1", "contact", "poly"))
offset = offset.scale(1, 0) + vector(0, height - poly_contact.width)
self.add_contact(layers=("metal1", "contact", "poly"),
offset=offset,
mirror="MX",
rotate=90)
def routing_BL_BR(self):
""" OUTPUT BIT-LINE CONNECTIONS (BL_OUT, BR_OUT) """
if (self.words_per_row > 1):
for j in range(self.columns / self.words_per_row):
base = vector(self.mux.width * self.words_per_row * j,
self.m1m2_via.width + drc['metal1_to_metal1'])
width = self.m1m2_via.width + self.mux.width * (self.words_per_row - 1)
self.add_rect(layer="metal1",
offset=base.scale(1,-self.words_per_row) + self.mux.BL_position.scale(1,0),
width=width,
height=-self.m1m2_via.width)
self.add_rect(layer="metal1",
offset=base.scale(1,-self.words_per_row-1) + self.mux.BR_position.scale(1,0),
width=width,
height=-self.m1m2_via.width)
height = base.y * (self.words_per_row + 2) + 3 * drc['metal2_to_metal2']
base = vector(base.x, - height)
self.add_rect(layer="metal2",
offset=base + self.mux.BL_position.scale(1,0),
width=drc['minwidth_metal2'],
height=height)
self.add_rect(layer="metal2",
offset=base + self.mux.BR_position.scale(1,0),
width=drc['minwidth_metal2'],
height=height)
self.add_rect(layer="metal2",
offset=base + self.mux.gnd_position.scale(1,0),
width=drc['minwidth_metal2'],
height=height)
for j in range(self.columns):
""" adding vertical metal rails to route BL_out and BR_out vertical rails """
contact_spacing = self.m1m2_via.width + drc['metal1_to_metal1']
height = self.words_per_row * contact_spacing + self.m1m2_via.width
offset = vector(self.mux.BL_position.x + self.mux.width * j, 0)
self.add_rect(layer="metal2",
offset=offset,
width=drc['minwidth_metal2'],
height=-height)
offset = offset + vector(self.m1m2_via.height, - height)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset,
rotate=90)
offset = vector(self.mux.BR_position.x + self.mux.width * j, 0)
height = height + contact_spacing
self.add_rect(layer="metal2",
offset=offset,
width=drc['minwidth_metal2'],
height= - height)
offset = offset + vector(self.m1m2_via.height/2, - height)
layer_diff = (self.m1m2_via.second_layer_width - self.m1m2_via.first_layer_width)
self.add_via(layers=("metal1", "via1", "metal2"),
offset= offset + vector(layer_diff, 0),
rotate=90)
self.add_label(text="COLUMN_MUX",
layer="text",
offset=[self.width / 2.0, self.height / 2.0])