2016-11-08 18:57:35 +01:00
|
|
|
from tech import drc
|
|
|
|
|
import debug
|
|
|
|
|
import design
|
2016-11-22 21:23:55 +01:00
|
|
|
from nand_2 import nand_2
|
2016-11-08 18:57:35 +01:00
|
|
|
from vector import vector
|
|
|
|
|
from hierarchical_predecode import hierarchical_predecode
|
|
|
|
|
|
|
|
|
|
class hierarchical_predecode2x4(hierarchical_predecode):
|
|
|
|
|
"""
|
|
|
|
|
Pre 2x4 decoder used in hierarchical_decoder.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, nmos_width, cellname):
|
|
|
|
|
hierarchical_predecode.__init__(self, nmos_width, cellname, 2)
|
|
|
|
|
|
|
|
|
|
self.add_pins()
|
|
|
|
|
self.create_modules()
|
|
|
|
|
self.setup_constrains()
|
|
|
|
|
self.create_layout()
|
|
|
|
|
self.route()
|
|
|
|
|
|
2016-11-22 21:23:55 +01:00
|
|
|
def create_nand(self):
|
2017-06-02 20:11:57 +02:00
|
|
|
self.nand = nand_2(nmos_width=self.nmos_width,
|
2016-11-22 21:23:55 +01:00
|
|
|
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"])
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
def create_layout(self):
|
|
|
|
|
self.create_rails()
|
|
|
|
|
self.add_inv2x4()
|
|
|
|
|
self.add_output_inverters()
|
|
|
|
|
connections =[["A[0]", "A[1]", "Z[3]", "vdd", "gnd"],
|
|
|
|
|
["B[0]", "A[1]", "Z[2]", "vdd", "gnd"],
|
|
|
|
|
["A[0]", "B[1]", "Z[1]", "vdd", "gnd"],
|
|
|
|
|
["B[0]", "B[1]", "Z[0]", "vdd", "gnd"]]
|
|
|
|
|
self.add_nand(connections)
|
|
|
|
|
|
2016-11-22 21:23:55 +01:00
|
|
|
def set_height(self):
|
|
|
|
|
self.height = 4 * self.nand.height
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
def add_inv2x4(self):
|
|
|
|
|
self.A_positions = []
|
|
|
|
|
for inv_2x4 in range(self.number_of_inputs):
|
|
|
|
|
name = "Xpre2x4_inv[{0}]".format(inv_2x4)
|
|
|
|
|
if (inv_2x4 % 2 == 0):
|
|
|
|
|
y_off = inv_2x4 * (self.inv.height)
|
|
|
|
|
offset = vector(self.x_off_inv_1, y_off)
|
|
|
|
|
mirror = "R0"
|
|
|
|
|
A_off = self.inv.A_position.scale(0, 1)
|
|
|
|
|
else:
|
|
|
|
|
y_off = (inv_2x4 + 1) * (self.inv.height)
|
|
|
|
|
offset = vector(self.x_off_inv_1, y_off)
|
|
|
|
|
mirror="MX"
|
|
|
|
|
A_off = vector(0, - self.inv.A_position.y - drc["minwidth_metal1"])
|
|
|
|
|
self.A_positions.append(offset + A_off)
|
|
|
|
|
self.add_inst(name=name,
|
|
|
|
|
mod=self.inv,
|
|
|
|
|
offset=offset,
|
|
|
|
|
mirror=mirror)
|
|
|
|
|
self.connect_inst(["A[{0}]".format(inv_2x4),
|
|
|
|
|
"B[{0}]".format(inv_2x4),
|
|
|
|
|
"vdd", "gnd"])
|
|
|
|
|
|
2016-11-22 21:23:55 +01:00
|
|
|
def cal_input_inverters_output(self,setup,output_shift,inv_rout):
|
|
|
|
|
y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup
|
|
|
|
|
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
|
|
|
|
out_offset = vector(inv_out_offset)
|
|
|
|
|
if y_dir == -1:
|
|
|
|
|
out_offset.y = inv_vdd_offset.y + output_shift + drc["minwidth_metal1"]
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2016-11-22 21:23:55 +01:00
|
|
|
vertical1 = out_offset
|
|
|
|
|
vertical2 = vertical1 + vector(0,
|
|
|
|
|
(inv_vdd_offset.y - inv_out_offset.y) * y_dir
|
|
|
|
|
- output_shift)
|
|
|
|
|
horizontal1 = vector(inv_out_offset.x,
|
|
|
|
|
inv_vdd_offset.y - correct)
|
|
|
|
|
horizontal2 = horizontal1 + vector(self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"],
|
|
|
|
|
0)
|
|
|
|
|
return [[vertical1,vertical2],[horizontal1,horizontal2]]
|
|
|
|
|
|
|
|
|
|
def set_output_shift(self):
|
|
|
|
|
return 2 * drc["minwidth_metal1"]
|
|
|
|
|
|
|
|
|
|
def get_nand_input_line_combination(self):
|
|
|
|
|
combination = [[4, 5], [6, 5], [4, 7], [6, 7]]
|
|
|
|
|
return combination
|
|
|
|
|
|
|
|
|
|
def create_y_offsets(self,k):
|
|
|
|
|
# create y offset list
|
|
|
|
|
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
|
|
|
|
|
correct =[0,0]
|
|
|
|
|
yoffset_nand_in = [y_off + direct * self.nand.A_position.y,
|
|
|
|
|
y_off + direct * self.nand.B_position.y]
|
|
|
|
|
return yoffset_nand_in, correct
|
|
|
|
|
|
|
|
|
|
def get_via_correct(self):
|
|
|
|
|
return vector(0, self.via_shift)
|
|
|
|
|
|
|
|
|
|
def get_vertical_metal(self):
|
|
|
|
|
return "metal1"
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2016-11-22 21:23:55 +01:00
|
|
|
def get_via_y(self):
|
|
|
|
|
return self.rail_height
|
2017-05-30 21:50:07 +02:00
|
|
|
|
|
|
|
|
def delay(self, slope, load = 0.0 ):
|
|
|
|
|
# A -> B
|
|
|
|
|
a_t_b_delay = self.inv.delay(slope=slope,load = self.nand.input_load())
|
|
|
|
|
|
|
|
|
|
# out -> z
|
|
|
|
|
b_t_z_delay = self.nand.delay(slope=a_t_b_delay.slope,load = self.inv.input_load())
|
|
|
|
|
result = a_t_b_delay + b_t_z_delay
|
|
|
|
|
|
|
|
|
|
# Z -> out
|
|
|
|
|
a_t_out_delay = self.inv.delay(slope=b_t_z_delay.slope,load = load)
|
|
|
|
|
result = result + a_t_out_delay
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def input_load(self):
|
|
|
|
|
return self.inv.input_load()
|