mirror of https://github.com/VLSIDA/OpenRAM.git
Merge remote-tracking branch 'bin/merge_hierarchical_decoder'
This commit is contained in:
commit
2d0533a7d5
|
|
@ -3,8 +3,6 @@ import design
|
||||||
import math
|
import math
|
||||||
from tech import drc
|
from tech import drc
|
||||||
from contact import contact
|
from contact import contact
|
||||||
from nand_2 import nand_2
|
|
||||||
from nand_3 import nand_3
|
|
||||||
from pinv import pinv
|
from pinv import pinv
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
@ -41,14 +39,8 @@ class hierarchical_predecode(design.design):
|
||||||
beta=2,
|
beta=2,
|
||||||
height=self.bitcell_height)
|
height=self.bitcell_height)
|
||||||
self.add_mod(self.inv)
|
self.add_mod(self.inv)
|
||||||
if self.number_of_inputs ==2:
|
# create_nand redefine in sub class based on number of inputs
|
||||||
self.nand = nand_2(name="a_nand_2",
|
self.create_nand()
|
||||||
nmos_width=self.nmos_width,
|
|
||||||
height=self.bitcell_height)
|
|
||||||
elif self.number_of_inputs ==3:
|
|
||||||
self.nand = nand_3(name="a_nand_3",
|
|
||||||
nmos_width=self.nmos_width,
|
|
||||||
height=self.bitcell_height)
|
|
||||||
self.add_mod(self.nand)
|
self.add_mod(self.nand)
|
||||||
|
|
||||||
def set_up_constrain(self):
|
def set_up_constrain(self):
|
||||||
|
|
@ -75,12 +67,8 @@ class hierarchical_predecode(design.design):
|
||||||
self.gap_between_rail_offset = self.gap_between_rails + drc["minwidth_metal2"]
|
self.gap_between_rail_offset = self.gap_between_rails + drc["minwidth_metal2"]
|
||||||
|
|
||||||
self.rails_x_offset = []
|
self.rails_x_offset = []
|
||||||
if self.number_of_inputs == 2:
|
# set_rail_height redefine in sub class
|
||||||
self.rail_height = (self.number_of_outputs * self.nand.height
|
self.set_rail_height()
|
||||||
- (self.number_of_outputs - 1) * drc["minwidth_metal2"])
|
|
||||||
elif self.number_of_inputs == 3:
|
|
||||||
self.rail_height = (self.number_of_outputs * self.nand.height
|
|
||||||
- 1.5 * drc["minwidth_metal2"])
|
|
||||||
# Creating the left hand side metal2 rails for input connections
|
# Creating the left hand side metal2 rails for input connections
|
||||||
for hrail_1 in range(self.number_of_inputs):
|
for hrail_1 in range(self.number_of_inputs):
|
||||||
xoffset_1 = (self.metal2_extend_contact
|
xoffset_1 = (self.metal2_extend_contact
|
||||||
|
|
@ -100,10 +88,7 @@ class hierarchical_predecode(design.design):
|
||||||
|
|
||||||
def update_size(self):
|
def update_size(self):
|
||||||
self.width = self.x_off_inv_2 + self.inv.width
|
self.width = self.x_off_inv_2 + self.inv.width
|
||||||
if self.number_of_inputs ==2:
|
self.set_height()
|
||||||
self.height = 4 * self.nand.height
|
|
||||||
elif self.number_of_inputs ==3:
|
|
||||||
self.height = 8 * self.nand.height
|
|
||||||
self.size = vector(self.width, self.height)
|
self.size = vector(self.width, self.height)
|
||||||
correct =vector(0, 0.5 * drc["minwidth_metal1"])
|
correct =vector(0, 0.5 * drc["minwidth_metal1"])
|
||||||
self.vdd_position = self.size - correct - vector(0, self.inv.height)
|
self.vdd_position = self.size - correct - vector(0, self.inv.height)
|
||||||
|
|
@ -142,10 +127,8 @@ class hierarchical_predecode(design.design):
|
||||||
|
|
||||||
def add_nand(self,connections):
|
def add_nand(self,connections):
|
||||||
for nand_input in range(self.number_of_outputs):
|
for nand_input in range(self.number_of_outputs):
|
||||||
if self.number_of_inputs ==2:
|
inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs)
|
||||||
name = "Xpre2x4_nand[{0}]".format(nand_input)
|
name = "Xpre"+inout+"_nand[{0}]".format(nand_input)
|
||||||
elif self.number_of_inputs ==3:
|
|
||||||
name = "Xpre3x8_nand[{0}]".format(nand_input)
|
|
||||||
if (nand_input % 2 == 0):
|
if (nand_input % 2 == 0):
|
||||||
y_off = nand_input * (self.nand.height)
|
y_off = nand_input * (self.nand.height)
|
||||||
mirror = "R0"
|
mirror = "R0"
|
||||||
|
|
@ -167,30 +150,135 @@ class hierarchical_predecode(design.design):
|
||||||
self.connect_inst(connections[nand_input])
|
self.connect_inst(connections[nand_input])
|
||||||
|
|
||||||
def route(self):
|
def route(self):
|
||||||
# route sub funtions need to be redfined in sub class
|
|
||||||
self.route_input_inverters()
|
self.route_input_inverters()
|
||||||
self.route_nand_to_rails()
|
self.route_nand_to_rails()
|
||||||
self.route_vdd_gnd_from_rails_to_gates()
|
self.route_vdd_gnd_from_rails_to_gates()
|
||||||
|
|
||||||
def route_input_inverters_input(self,inv_rout,inv_in_offset):
|
def route_input_inverters(self):
|
||||||
|
# All conections of the inputs inverters [Inputs, outputs, vdd, gnd]
|
||||||
|
output_shift = self.set_output_shift()
|
||||||
|
for inv_rout in range(self.number_of_inputs):
|
||||||
|
setup = self.setup_route_input_inverter(inv_rout,output_shift)
|
||||||
|
y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup
|
||||||
|
#add output
|
||||||
|
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||||
|
output_metal = self.cal_input_inverters_output(setup,output_shift,inv_rout)
|
||||||
|
offset1,offset2=output_metal[0]
|
||||||
|
offset3,offset4=output_metal[1]
|
||||||
|
self.add_rect(layer="metal1",
|
||||||
|
offset=offset1,
|
||||||
|
width=drc["minwidth_metal1"],
|
||||||
|
height=offset2.y - offset1.y)
|
||||||
|
self.add_rect(layer="metal1",
|
||||||
|
offset=offset3,
|
||||||
|
width=offset4.x - offset3.x,
|
||||||
|
height=drc["minwidth_metal1"])
|
||||||
|
off_via = [self.rails_x_offset[inv_rout + self.number_of_inputs+2] + self.gap_between_rails,
|
||||||
|
inv_vdd_offset.y- self.via_shift - correct]
|
||||||
|
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||||
|
offset=off_via,
|
||||||
|
rotate=90)
|
||||||
|
#route input
|
||||||
|
self.add_rect(layer="metal1",
|
||||||
|
offset=[self.rails_x_offset[inv_rout],
|
||||||
|
inv_in_offset.y],
|
||||||
|
width=inv_in_offset.x - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"],
|
||||||
|
height=drc["minwidth_metal1"])
|
||||||
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
offset=[self.rails_x_offset[inv_rout] + self.gap_between_rails,
|
||||||
|
inv_in_offset.y - self.via_shift],
|
||||||
|
rotate=90)
|
||||||
|
# route vdd
|
||||||
|
self.add_rect(layer="metal1",
|
||||||
|
offset=inv_vdd_offset,
|
||||||
|
width=self.rails_x_offset[self.number_of_inputs] - inv_vdd_offset.x + drc["minwidth_metal2"],
|
||||||
|
height=drc["minwidth_metal1"])
|
||||||
|
# route gnd
|
||||||
|
self.add_rect(layer="metal1",
|
||||||
|
offset=inv_gnd_offset,
|
||||||
|
width=self.rails_x_offset[self.number_of_inputs+1] - inv_gnd_offset.x + drc["minwidth_metal2"],
|
||||||
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
|
def setup_route_input_inverter(self, inv_rout, output_shift):
|
||||||
|
# add Inputs, vdd, gnd of the inputs inverters
|
||||||
|
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)
|
||||||
|
#return info to create output of the input inverter
|
||||||
|
return [y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset]
|
||||||
|
|
||||||
|
def route_nand_to_rails(self):
|
||||||
|
# This 2D array defines the connection mapping
|
||||||
|
nand_input_line_combination = self.get_nand_input_line_combination()
|
||||||
|
for k in range(self.number_of_outputs):
|
||||||
|
# create x offset list
|
||||||
|
index_lst= nand_input_line_combination[k]
|
||||||
|
line_x_offset = []
|
||||||
|
for index in index_lst:
|
||||||
|
line_x_offset.append(self.rails_x_offset[index])
|
||||||
|
# create y offset list
|
||||||
|
yoffset_nand_in, correct= self.create_y_offsets(k)
|
||||||
|
# connect based on the two list
|
||||||
|
for i in range(self.number_of_inputs):
|
||||||
|
x_offset = line_x_offset[i]
|
||||||
|
y_offset = yoffset_nand_in[i]
|
||||||
|
# Connecting the i-th input of Nand3 gate
|
||||||
|
self.add_rect(layer="metal1",
|
||||||
|
offset=[x_offset, y_offset],
|
||||||
|
width=self.x_off_nand - x_offset,
|
||||||
|
height=drc["minwidth_metal1"])
|
||||||
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
offset=[x_offset+ self.gap_between_rails,
|
||||||
|
y_offset - 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):
|
||||||
|
x_offset = self.rails_x_offset[i]
|
||||||
|
self.add_rect(layer="metal1",
|
||||||
|
offset=[x_offset, y_offset],
|
||||||
|
width=self.x_off_nand - x_offset,
|
||||||
|
height=drc["minwidth_metal1"])
|
||||||
|
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||||
|
offset=[x_offset + self.gap_between_rails,
|
||||||
|
y_offset - self.via_shift],
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
def route_vdd_gnd_from_rails_to_gates(self):
|
||||||
|
via_correct = self.get_via_correct()
|
||||||
|
for k in range(self.number_of_outputs):
|
||||||
|
power_line_index = self.number_of_inputs + 1 - (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 - via_correct.y],
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
yoffset = (self.number_of_outputs * self.inv.height
|
||||||
|
- 0.5 * drc["minwidth_metal1"])
|
||||||
|
v_metal = self.get_vertical_metal()
|
||||||
|
via_y = self.get_via_y()
|
||||||
|
index = self.number_of_inputs + 1
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=[self.rails_x_offset[inv_rout],
|
offset=[self.rails_x_offset[index], yoffset],
|
||||||
inv_in_offset.y],
|
width=self.x_off_nand - self.rails_x_offset[index],
|
||||||
width=inv_in_offset.x - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"],
|
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_rect(layer=v_metal,
|
||||||
offset=[self.rails_x_offset[inv_rout] + self.gap_between_rails,
|
offset=[self.rails_x_offset[index], self.rail_height],
|
||||||
inv_in_offset.y - self.via_shift],
|
width=drc["minwidth_"+v_metal],
|
||||||
|
height=yoffset - self.rail_height)
|
||||||
|
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||||
|
offset=[self.rails_x_offset[index] + self.gap_between_rails,
|
||||||
|
via_y] - via_correct,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
def route_input_inverters_vdd(self,inv_vdd_offset):
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=inv_vdd_offset,
|
|
||||||
width=self.rails_x_offset[self.number_of_inputs] - inv_vdd_offset.x + drc["minwidth_metal2"],
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
|
|
||||||
def route_input_inverters_gnd(self,inv_gnd_offset):
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=inv_gnd_offset,
|
|
||||||
width=self.rails_x_offset[self.number_of_inputs+1] - inv_gnd_offset.x + drc["minwidth_metal2"],
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from tech import drc
|
from tech import drc
|
||||||
import debug
|
import debug
|
||||||
import design
|
import design
|
||||||
|
from nand_2 import nand_2
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from hierarchical_predecode import hierarchical_predecode
|
from hierarchical_predecode import hierarchical_predecode
|
||||||
|
|
||||||
|
|
@ -8,7 +9,6 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
"""
|
"""
|
||||||
Pre 2x4 decoder used in hierarchical_decoder.
|
Pre 2x4 decoder used in hierarchical_decoder.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, nmos_width, cellname):
|
def __init__(self, nmos_width, cellname):
|
||||||
hierarchical_predecode.__init__(self, nmos_width, cellname, 2)
|
hierarchical_predecode.__init__(self, nmos_width, cellname, 2)
|
||||||
|
|
||||||
|
|
@ -18,6 +18,15 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
self.route()
|
self.route()
|
||||||
|
|
||||||
|
def create_nand(self):
|
||||||
|
self.nand = nand_2(name="a_nand_2",
|
||||||
|
nmos_width=self.nmos_width,
|
||||||
|
height=self.bitcell_height)
|
||||||
|
|
||||||
|
def set_rail_height(self):
|
||||||
|
self.rail_height = (self.number_of_outputs * self.nand.height
|
||||||
|
- (self.number_of_outputs - 1) * drc["minwidth_metal2"])
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
self.create_rails()
|
self.create_rails()
|
||||||
self.add_inv2x4()
|
self.add_inv2x4()
|
||||||
|
|
@ -28,6 +37,9 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
["B[0]", "B[1]", "Z[0]", "vdd", "gnd"]]
|
["B[0]", "B[1]", "Z[0]", "vdd", "gnd"]]
|
||||||
self.add_nand(connections)
|
self.add_nand(connections)
|
||||||
|
|
||||||
|
def set_height(self):
|
||||||
|
self.height = 4 * self.nand.height
|
||||||
|
|
||||||
def add_inv2x4(self):
|
def add_inv2x4(self):
|
||||||
self.A_positions = []
|
self.A_positions = []
|
||||||
for inv_2x4 in range(self.number_of_inputs):
|
for inv_2x4 in range(self.number_of_inputs):
|
||||||
|
|
@ -51,109 +63,48 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
"B[{0}]".format(inv_2x4),
|
"B[{0}]".format(inv_2x4),
|
||||||
"vdd", "gnd"])
|
"vdd", "gnd"])
|
||||||
|
|
||||||
def route_input_inverters(self):
|
def cal_input_inverters_output(self,setup,output_shift,inv_rout):
|
||||||
# All conections of the inputs inverters [Inputs, outputs, vdd, gnd]
|
y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup
|
||||||
output_shift = 2 * drc["minwidth_metal1"]
|
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||||
for inv_rout in range(self.number_of_inputs):
|
out_offset = vector(inv_out_offset)
|
||||||
if (inv_rout % 2 == 0):
|
if y_dir == -1:
|
||||||
y_dir= 1
|
out_offset.y = inv_vdd_offset.y + output_shift + drc["minwidth_metal1"]
|
||||||
else:
|
|
||||||
y_dir= -1
|
|
||||||
base = vector(self.x_off_inv_1,
|
|
||||||
(1-y_dir) * (self.inv.height - 0.5 * drc["minwidth_metal1"]))
|
|
||||||
inv_out_offset = base + self.inv.Z_position.scale(1,y_dir)
|
|
||||||
inv_in_offset = base + self.inv.A_position.scale(1,y_dir)
|
|
||||||
inv_vdd_offset = base + self.inv.vdd_position.scale(1,y_dir)
|
|
||||||
inv_gnd_offset = base + self.inv.gnd_position.scale(1,y_dir)
|
|
||||||
out_y_mirrored = inv_vdd_offset.y+ output_shift + drc["minwidth_metal1"]
|
|
||||||
out_offset = [inv_out_offset.x,
|
|
||||||
inv_out_offset.y* (1 + y_dir) / 2
|
|
||||||
+ out_y_mirrored * (1 - y_dir) / 2]
|
|
||||||
# output connection
|
|
||||||
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
|
||||||
off_via = [self.rails_x_offset[inv_rout + 4] + self.gap_between_rails,
|
|
||||||
inv_vdd_offset.y- self.via_shift - correct]
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=out_offset,
|
|
||||||
width=drc["minwidth_metal1"],
|
|
||||||
height=(inv_vdd_offset.y- inv_out_offset.y) * y_dir - output_shift)
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=[inv_out_offset.x,
|
|
||||||
inv_vdd_offset.y- correct],
|
|
||||||
width=self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"],
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
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):
|
vertical1 = out_offset
|
||||||
# This 2D array defines the connection mapping
|
vertical2 = vertical1 + vector(0,
|
||||||
nand2_input_line_combination = [[4, 5], [6, 5], [4, 7], [6, 7]]
|
(inv_vdd_offset.y - inv_out_offset.y) * y_dir
|
||||||
for k in range(self.number_of_outputs):
|
- output_shift)
|
||||||
# create x offset list
|
horizontal1 = vector(inv_out_offset.x,
|
||||||
x_index = nand2_input_line_combination[k]
|
inv_vdd_offset.y - correct)
|
||||||
line_x_offset = [self.rails_x_offset[x_index[0]],
|
horizontal2 = horizontal1 + vector(self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"],
|
||||||
self.rails_x_offset[x_index[1]]]
|
0)
|
||||||
# create y offset list
|
return [[vertical1,vertical2],[horizontal1,horizontal2]]
|
||||||
if (k % 2 == 0):
|
|
||||||
y_off = k * (self.nand.height)
|
|
||||||
direct = 1
|
|
||||||
else:
|
|
||||||
y_off = (k + 1) * (self.nand.height) - drc["minwidth_metal1"]
|
|
||||||
direct = - 1
|
|
||||||
list_connect = [y_off + direct * self.nand.A_position.y,
|
|
||||||
y_off + direct * self.nand.B_position.y]
|
|
||||||
# connect based on the two list
|
|
||||||
for connect in list_connect:
|
|
||||||
x_offset = line_x_offset[list_connect.index(connect)]
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=[x_offset, connect],
|
|
||||||
width=self.x_off_nand - x_offset,
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
|
||||||
offset=[x_offset + self.gap_between_rails,
|
|
||||||
connect - self.via_shift],
|
|
||||||
rotate=90)
|
|
||||||
# Extended of the top NAND2 to the left hand side input rails
|
|
||||||
if(k == self.number_of_outputs - 1):
|
|
||||||
x_offset = self.rails_x_offset[list_connect.index(connect)]
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=[x_offset, connect],
|
|
||||||
width=self.x_off_nand - x_offset,
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
|
||||||
offset=[x_offset + self.gap_between_rails,
|
|
||||||
connect - self.via_shift],
|
|
||||||
rotate=90)
|
|
||||||
|
|
||||||
def route_vdd_gnd_from_rails_to_gates(self):
|
def set_output_shift(self):
|
||||||
for k in range(self.number_of_outputs):
|
return 2 * drc["minwidth_metal1"]
|
||||||
power_line_index = 3 - (k%2)
|
|
||||||
yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"]
|
def get_nand_input_line_combination(self):
|
||||||
self.add_rect(layer="metal1",
|
combination = [[4, 5], [6, 5], [4, 7], [6, 7]]
|
||||||
offset=[self.rails_x_offset[power_line_index],
|
return combination
|
||||||
yoffset],
|
|
||||||
width=self.x_off_nand - self.rails_x_offset[power_line_index],
|
def create_y_offsets(self,k):
|
||||||
height=drc["minwidth_metal1"])
|
# create y offset list
|
||||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
if (k % 2 == 0):
|
||||||
offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails,
|
y_off = k * (self.nand.height)
|
||||||
yoffset - self.via_shift],
|
direct = 1
|
||||||
rotate=90)
|
else:
|
||||||
|
y_off = (k + 1) * (self.nand.height) - drc["minwidth_metal1"]
|
||||||
yoffset = (self.number_of_outputs * self.inv.height
|
direct = - 1
|
||||||
- 0.5 * drc["minwidth_metal1"])
|
correct =[0,0]
|
||||||
self.add_rect(layer="metal1",
|
yoffset_nand_in = [y_off + direct * self.nand.A_position.y,
|
||||||
offset=[self.rails_x_offset[3], yoffset],
|
y_off + direct * self.nand.B_position.y]
|
||||||
width=self.x_off_nand - self.rails_x_offset[3],
|
return yoffset_nand_in, correct
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
self.add_rect(layer="metal1",
|
def get_via_correct(self):
|
||||||
offset=[self.rails_x_offset[3], self.rail_height],
|
return vector(0, self.via_shift)
|
||||||
width=drc["minwidth_metal1"],
|
|
||||||
height=yoffset - self.rail_height)
|
def get_vertical_metal(self):
|
||||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
return "metal1"
|
||||||
offset=[self.rails_x_offset[3] + self.gap_between_rails,
|
|
||||||
self.rail_height - self.via_shift],
|
def get_via_y(self):
|
||||||
rotate=90)
|
return self.rail_height
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from tech import drc
|
from tech import drc
|
||||||
import debug
|
import debug
|
||||||
import design
|
import design
|
||||||
|
from nand_3 import nand_3
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from hierarchical_predecode import hierarchical_predecode
|
from hierarchical_predecode import hierarchical_predecode
|
||||||
|
|
||||||
|
|
@ -18,6 +19,14 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
self.route()
|
self.route()
|
||||||
|
|
||||||
|
def create_nand(self):
|
||||||
|
self.nand = nand_3(name="a_nand_3",
|
||||||
|
nmos_width=self.nmos_width,
|
||||||
|
height=self.bitcell_height)
|
||||||
|
|
||||||
|
def set_rail_height(self):
|
||||||
|
self.rail_height = (self.number_of_outputs * self.nand.height
|
||||||
|
- 1.5 * drc["minwidth_metal2"])
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
self.create_rails()
|
self.create_rails()
|
||||||
self.add_output_inverters()
|
self.add_output_inverters()
|
||||||
|
|
@ -31,111 +40,53 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
["B[0]", "B[1]", "B[2]", "Z[0]", "vdd", "gnd"]]
|
["B[0]", "B[1]", "B[2]", "Z[0]", "vdd", "gnd"]]
|
||||||
self.add_nand(connections)
|
self.add_nand(connections)
|
||||||
|
|
||||||
def route_input_inverters(self):
|
def set_height(self):
|
||||||
# All conections of the inputs inverters [Inputs, outputs, vdd, gnd]
|
self.height = 8 * self.nand.height
|
||||||
for inv_rout in range(self.number_of_inputs):
|
|
||||||
output_shift = 1.5 * drc["minwidth_metal1"]
|
|
||||||
|
|
||||||
if (inv_rout % 2 == 0):
|
def cal_input_inverters_output(self,setup,output_shift,inv_rout):
|
||||||
base_offset=[self.x_off_inv_1, inv_rout * self.inv.height ]
|
y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup
|
||||||
y_dir = 1
|
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||||
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.y - self.via_shift - correct]
|
|
||||||
path1 = inv_out_offset + vector(0.5*drc["minwidth_metal1"],
|
|
||||||
- 1.5*drc["minwidth_metal1"] - correct)
|
|
||||||
path2 = vector(path1.x,
|
|
||||||
inv_vdd_offset.y + 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):
|
out_offset = inv_out_offset + vector(0, output_shift + correct)
|
||||||
# This 2D array defines the connection mapping of the Nand3 gates to
|
vertical1 = out_offset
|
||||||
# the rail
|
vertical2 = (vertical1.scale(1, 0) + inv_vdd_offset.scale(0, 1)
|
||||||
nand3_input_line_combination = [[5, 6, 7], [5, 6, 10],
|
+ vector(0, - correct))
|
||||||
[5, 9, 7], [5, 9, 10],
|
horizontal1 = vertical1
|
||||||
[8, 6, 7], [8, 6, 10],
|
horizontal2 = vector(self.rails_x_offset[inv_rout + 5] + drc["minwidth_metal2"],
|
||||||
[8, 9, 7], [8, 9, 10]]
|
vertical2.y)
|
||||||
for k in range(self.number_of_outputs):
|
return [[vertical1,vertical2],[horizontal1,horizontal2]]
|
||||||
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):
|
def set_output_shift(self):
|
||||||
y_off = k * (self.nand.height)
|
return 1.5 * drc["minwidth_metal1"]
|
||||||
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):
|
def get_nand_input_line_combination(self):
|
||||||
# Connecting the i-th input of Nand3 gate
|
combination = [[5, 6, 7], [5, 6, 10],
|
||||||
self.add_rect(layer="metal1",
|
[5, 9, 7], [5, 9, 10],
|
||||||
offset=[line_x_offset[i], yoffset_nand_in[i]],
|
[8, 6, 7], [8, 6, 10],
|
||||||
width=self.x_off_nand - line_x_offset[i],
|
[8, 9, 7], [8, 9, 10]]
|
||||||
height=drc["minwidth_metal1"])
|
return combination
|
||||||
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):
|
def create_y_offsets(self,k):
|
||||||
for k in range(self.number_of_outputs):
|
if (k % 2 == 0):
|
||||||
power_line_index = 4 - (k%2)
|
y_off = k * (self.nand.height)
|
||||||
yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"]
|
y_dir =1
|
||||||
self.add_rect(layer="metal1",
|
correct = [0,0,self.contact_shift]
|
||||||
offset=[self.rails_x_offset[power_line_index], yoffset],
|
else:
|
||||||
width=self.x_off_nand - self.rails_x_offset[power_line_index],
|
y_off = 2 * self.inv.height - drc["minwidth_metal1"] + (k - 1) * (self.nand.height)
|
||||||
height=drc["minwidth_metal1"])
|
y_dir = -1
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
correct = [0,self.contact_shift,0]
|
||||||
offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails,
|
yoffset_nand_in = [y_off + y_dir*self.nand.A_position[1],
|
||||||
yoffset - self.via_shift - self.contact_shift],
|
y_off + y_dir*self.nand.B_position[1],
|
||||||
rotate=90)
|
y_off + y_dir*self.nand.C_position[1]]
|
||||||
|
return yoffset_nand_in, correct
|
||||||
|
|
||||||
|
def get_via_correct(self):
|
||||||
|
return vector(0, self.via_shift+self.contact_shift)
|
||||||
|
|
||||||
|
def get_vertical_metal(self):
|
||||||
|
return "metal2"
|
||||||
|
|
||||||
|
def get_via_y(self):
|
||||||
yoffset = (self.number_of_outputs * self.inv.height
|
yoffset = (self.number_of_outputs * self.inv.height
|
||||||
- 0.5 * drc["minwidth_metal1"])
|
- 0.5 * drc["minwidth_metal1"])
|
||||||
self.add_rect(layer="metal1",
|
return yoffset
|
||||||
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)
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue