mirror of https://github.com/VLSIDA/OpenRAM.git
142 lines
7.0 KiB
Python
142 lines
7.0 KiB
Python
from tech import drc
|
|
import debug
|
|
import design
|
|
from vector import vector
|
|
from hierarchical_predecode import hierarchical_predecode
|
|
|
|
|
|
class hierarchical_predecode3x8(hierarchical_predecode):
|
|
"""
|
|
Pre 3x8 decoder used in hierarchical_decoder.
|
|
"""
|
|
def __init__(self, nmos_width, cellname):
|
|
hierarchical_predecode.__init__(self, nmos_width, cellname, 3)
|
|
|
|
self.add_pins()
|
|
self.create_modules()
|
|
self.setup_constrains()
|
|
self.create_layout()
|
|
self.route()
|
|
|
|
def create_layout(self):
|
|
self.create_rails()
|
|
self.add_output_inverters()
|
|
connections=[["A[0]", "A[1]", "A[2]", "Z[7]", "vdd", "gnd"],
|
|
["A[0]", "A[1]", "B[2]", "Z[6]", "vdd", "gnd"],
|
|
["A[0]", "B[1]", "A[2]", "Z[5]", "vdd", "gnd"],
|
|
["A[0]", "B[1]", "B[2]", "Z[4]", "vdd", "gnd"],
|
|
["B[0]", "A[1]", "A[2]", "Z[3]", "vdd", "gnd"],
|
|
["B[0]", "A[1]", "B[2]", "Z[2]", "vdd", "gnd"],
|
|
["B[0]", "B[1]", "A[2]", "Z[1]", "vdd", "gnd"],
|
|
["B[0]", "B[1]", "B[2]", "Z[0]", "vdd", "gnd"]]
|
|
self.add_nand(connections)
|
|
|
|
def route_input_inverters(self):
|
|
# All conections of the inputs inverters [Inputs, outputs, vdd, gnd]
|
|
for inv_rout in range(self.number_of_inputs):
|
|
output_shift = 1.5 * drc["minwidth_metal1"]
|
|
|
|
if (inv_rout % 2 == 0):
|
|
base_offset=[self.x_off_inv_1, inv_rout * self.inv.height ]
|
|
y_dir = 1
|
|
else:
|
|
base_offset=[self.x_off_inv_1, 2 * self.inv.height - drc["minwidth_metal1"]]
|
|
y_dir = -1
|
|
inv_out_offset = base_offset+self.inv.Z_position.scale(1,y_dir)
|
|
inv_in_offset = base_offset+self.inv.A_position.scale(1,y_dir)
|
|
inv_vdd_offset = base_offset+self.inv.vdd_position.scale(1,y_dir)
|
|
inv_gnd_offset = base_offset+self.inv.gnd_position.scale(1,y_dir)
|
|
# output connection
|
|
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
|
off_via = [self.rails_x_offset[inv_rout + 5] + self.gap_between_rails,
|
|
inv_vdd_offset[1] - self.via_shift - correct]
|
|
path1 = vector(inv_out_offset[0] + 0.5*drc["minwidth_metal1"],
|
|
inv_out_offset[1]- 1.5*drc["minwidth_metal1"] - correct)
|
|
path2 = vector(path1.x,
|
|
inv_vdd_offset[1] + 0.5 * drc["minwidth_metal1"] - correct)
|
|
path3 = vector(self.rails_x_offset[inv_rout + 5] + drc["minwidth_metal2"],
|
|
path2.y)
|
|
self.add_path("metal1", [path1,path2,path3])
|
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
offset=off_via,
|
|
rotate=90)
|
|
self.route_input_inverters_input(inv_rout,inv_in_offset)
|
|
self.route_input_inverters_vdd(inv_vdd_offset)
|
|
self.route_input_inverters_gnd(inv_gnd_offset)
|
|
|
|
def route_nand_to_rails(self):
|
|
# This 2D array defines the connection mapping of the Nand3 gates to
|
|
# the rail
|
|
nand3_input_line_combination = [[5, 6, 7], [5, 6, 10],
|
|
[5, 9, 7], [5, 9, 10],
|
|
[8, 6, 7], [8, 6, 10],
|
|
[8, 9, 7], [8, 9, 10]]
|
|
for k in range(self.number_of_outputs):
|
|
index_lst = nand3_input_line_combination[k]
|
|
line_x_offset = []
|
|
for index in index_lst:
|
|
line_x_offset.append(self.rails_x_offset[index])
|
|
|
|
if (k % 2 == 0):
|
|
y_off = k * (self.nand.height)
|
|
y_dir =1
|
|
correct = [0,0,self.contact_shift]
|
|
else:
|
|
y_off = 2 * self.inv.height - drc["minwidth_metal1"] + (k - 1) * (self.nand.height)
|
|
y_dir = -1
|
|
correct = [0,self.contact_shift,0]
|
|
yoffset_nand_in = [y_off + y_dir*self.nand.A_position[1],
|
|
y_off + y_dir*self.nand.B_position[1],
|
|
y_off + y_dir*self.nand.C_position[1]]
|
|
|
|
for i in range(self.number_of_inputs):
|
|
# Connecting the i-th input of Nand3 gate
|
|
self.add_rect(layer="metal1",
|
|
offset=[line_x_offset[i], yoffset_nand_in[i]],
|
|
width=self.x_off_nand - line_x_offset[i],
|
|
height=drc["minwidth_metal1"])
|
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
offset=[line_x_offset[i]+ self.gap_between_rails,
|
|
yoffset_nand_in[i] - self.via_shift - correct[i]],
|
|
rotate=90)
|
|
#Extended of the top NAND2 to the left hand side input rails
|
|
if(k == self.number_of_outputs - 1):
|
|
for i in range(self.number_of_inputs):
|
|
self.add_rect(layer="metal1",
|
|
offset=[self.rails_x_offset[i], yoffset_nand_in[i]],
|
|
width=self.x_off_nand - self.rails_x_offset[i],
|
|
height=drc["minwidth_metal1"])
|
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
offset=[self.rails_x_offset[i] + self.gap_between_rails,
|
|
yoffset_nand_in[i] - self.via_shift],
|
|
rotate=90)
|
|
|
|
def route_vdd_gnd_from_rails_to_gates(self):
|
|
for k in range(self.number_of_outputs):
|
|
power_line_index = 4 - (k%2)
|
|
yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"]
|
|
self.add_rect(layer="metal1",
|
|
offset=[self.rails_x_offset[power_line_index], yoffset],
|
|
width=self.x_off_nand - self.rails_x_offset[power_line_index],
|
|
height=drc["minwidth_metal1"])
|
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails,
|
|
yoffset - self.via_shift - self.contact_shift],
|
|
rotate=90)
|
|
|
|
yoffset = (self.number_of_outputs * self.inv.height
|
|
- 0.5 * drc["minwidth_metal1"])
|
|
self.add_rect(layer="metal1",
|
|
offset=[self.rails_x_offset[4], yoffset],
|
|
width=self.x_off_nand - self.rails_x_offset[4],
|
|
height=drc["minwidth_metal1"])
|
|
|
|
self.add_rect(layer="metal2",
|
|
offset=[self.rails_x_offset[4], self.rail_height],
|
|
width=drc["minwidth_metal2"],
|
|
height=yoffset - self.rail_height)
|
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
offset=[self.rails_x_offset[4] + self.gap_between_rails - self.via_shift,
|
|
yoffset - self.via_shift - self.contact_shift],
|
|
rotate=90)
|