mirror of https://github.com/VLSIDA/OpenRAM.git
Add place_inst routine.
Separate create netlist and layout in some modules.
This commit is contained in:
parent
8c73a26daa
commit
138a70fc23
|
|
@ -49,6 +49,10 @@ class geometry:
|
||||||
ll = vector(min(first[0],second[0]),min(first[1],second[1]))
|
ll = vector(min(first[0],second[0]),min(first[1],second[1]))
|
||||||
ur = vector(max(first[0],second[0]),max(first[1],second[1]))
|
ur = vector(max(first[0],second[0]),max(first[1],second[1]))
|
||||||
self.boundary=[ll,ur]
|
self.boundary=[ll,ur]
|
||||||
|
|
||||||
|
def update_boundary(self):
|
||||||
|
""" Update the boundary with a new placement. """
|
||||||
|
self.compute_boundary(self.offset,self.mirror,self.rotate)
|
||||||
|
|
||||||
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
|
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
|
||||||
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
||||||
|
|
@ -124,7 +128,7 @@ class instance(geometry):
|
||||||
An instance of an instance/module with a specified location and
|
An instance of an instance/module with a specified location and
|
||||||
rotation
|
rotation
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, mod, offset, mirror, rotate):
|
def __init__(self, name, mod, offset=[0,0], mirror="R0", rotate=0):
|
||||||
"""Initializes an instance to represent a module"""
|
"""Initializes an instance to represent a module"""
|
||||||
geometry.__init__(self)
|
geometry.__init__(self)
|
||||||
debug.check(mirror not in ["R90","R180","R270"], "Please use rotation and not mirroring during instantiation.")
|
debug.check(mirror not in ["R90","R180","R270"], "Please use rotation and not mirroring during instantiation.")
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,15 @@ class layout(lef.lef):
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
pin.rect = [pin.ll() - offset, pin.ur() - offset]
|
pin.rect = [pin.ll() - offset, pin.ur() - offset]
|
||||||
|
|
||||||
|
def place_inst(self, name, offset, mirror="R0", rotate=0):
|
||||||
|
""" This updates the placement of an instance. """
|
||||||
|
inst = self.get_inst(name)
|
||||||
|
debug.info(3, "placing instance {}".format(inst))
|
||||||
|
# Update the placement of an already added instance
|
||||||
|
inst.offset = offset
|
||||||
|
inst.mirror = mirror
|
||||||
|
inst.rotate = rotate
|
||||||
|
inst.update_boundary()
|
||||||
|
|
||||||
def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0):
|
def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0):
|
||||||
"""Adds an instance of a mod to this module"""
|
"""Adds an instance of a mod to this module"""
|
||||||
|
|
|
||||||
|
|
@ -91,19 +91,26 @@ class spice(verilog.verilog):
|
||||||
group of modules are generated."""
|
group of modules are generated."""
|
||||||
|
|
||||||
if (check and (len(self.insts[-1].mod.pins) != len(args))):
|
if (check and (len(self.insts[-1].mod.pins) != len(args))):
|
||||||
debug.error("Connections: {}".format(self.insts[-1].mod.pins))
|
import pprint
|
||||||
debug.error("Connections: {}".format(args))
|
modpins_string=pprint.pformat(self.insts[-1].mod.pins)
|
||||||
|
argpins_string=pprint.pformat(args)
|
||||||
|
debug.error("Connections: {}".format(modpins_string))
|
||||||
|
debug.error("Connections: {}".format(argpins_string))
|
||||||
debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins),
|
debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins),
|
||||||
len(args)), 1)
|
len(args)), 1)
|
||||||
self.conns.append(args)
|
self.conns.append(args)
|
||||||
|
|
||||||
if check and (len(self.insts)!=len(self.conns)):
|
if check and (len(self.insts)!=len(self.conns)):
|
||||||
|
import pprint
|
||||||
|
insts_string=pprint.pformat(self.insts)
|
||||||
|
conns_string=pprint.pformat(self.conns)
|
||||||
|
|
||||||
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
||||||
len(self.insts),
|
len(self.insts),
|
||||||
len(self.conns)))
|
len(self.conns)))
|
||||||
debug.error("Instances: \n"+str(self.insts))
|
debug.error("Instances: \n"+str(insts_string))
|
||||||
debug.error("-----")
|
debug.error("-----")
|
||||||
debug.error("Connections: \n"+str(self.conns),1)
|
debug.error("Connections: \n"+str(conns_string),1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,15 +31,14 @@ class bitcell_array(design.design):
|
||||||
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
|
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
|
||||||
self.width = self.column_size*self.cell.width + self.m1_width
|
self.width = self.column_size*self.cell.width + self.m1_width
|
||||||
|
|
||||||
self.add_pins()
|
self.create_netlist()
|
||||||
|
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
self.add_layout_pins()
|
|
||||||
|
|
||||||
# We don't offset this because we need to align
|
# We don't offset this because we need to align
|
||||||
# the replica bitcell in the control logic
|
# the replica bitcell in the control logic
|
||||||
#self.offset_all_coordinates()
|
#self.offset_all_coordinates()
|
||||||
|
|
||||||
self.DRC_LVS()
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
row_list = self.cell.list_all_wl_names()
|
row_list = self.cell.list_all_wl_names()
|
||||||
|
|
@ -55,7 +54,6 @@ class bitcell_array(design.design):
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
xoffset = 0.0
|
xoffset = 0.0
|
||||||
self.cell_inst = {}
|
|
||||||
for col in range(self.column_size):
|
for col in range(self.column_size):
|
||||||
yoffset = 0.0
|
yoffset = 0.0
|
||||||
for row in range(self.row_size):
|
for row in range(self.row_size):
|
||||||
|
|
@ -68,16 +66,29 @@ class bitcell_array(design.design):
|
||||||
tempy = yoffset
|
tempy = yoffset
|
||||||
dir_key = ""
|
dir_key = ""
|
||||||
|
|
||||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
self.place_inst(name=name,
|
||||||
mod=self.cell,
|
offset=[xoffset, tempy],
|
||||||
offset=[xoffset, tempy],
|
mirror=dir_key)
|
||||||
mirror=dir_key)
|
|
||||||
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
|
||||||
|
|
||||||
yoffset += self.cell.height
|
yoffset += self.cell.height
|
||||||
xoffset += self.cell.width
|
xoffset += self.cell.width
|
||||||
|
|
||||||
|
self.add_layout_pins()
|
||||||
|
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
""" Create and connect the netlist """
|
||||||
|
self.add_pins()
|
||||||
|
|
||||||
|
self.cell_inst = {}
|
||||||
|
for col in range(self.column_size):
|
||||||
|
for row in range(self.row_size):
|
||||||
|
name = "bit_r{0}_c{1}".format(row, col)
|
||||||
|
self.cell_inst[row,col]=self.add_inst(name=name,
|
||||||
|
mod=self.cell)
|
||||||
|
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
||||||
|
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
""" Add the layout pins """
|
""" Add the layout pins """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,15 @@ class dff_array(design.design):
|
||||||
self.width = self.columns * self.dff.width
|
self.width = self.columns * self.dff.width
|
||||||
self.height = self.rows * self.dff.height
|
self.height = self.rows * self.dff.height
|
||||||
|
|
||||||
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_netlist(self):
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.create_dff_array()
|
self.create_dff_array()
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
|
self.place_dff_array()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -53,22 +57,28 @@ class dff_array(design.design):
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
for col in range(self.columns):
|
for col in range(self.columns):
|
||||||
name = "Xdff_r{0}_c{1}".format(row,col)
|
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||||
if (row % 2 == 0):
|
|
||||||
base = vector(col*self.dff.width,row*self.dff.height)
|
|
||||||
mirror = "R0"
|
|
||||||
else:
|
|
||||||
base = vector(col*self.dff.width,(row+1)*self.dff.height)
|
|
||||||
mirror = "MX"
|
|
||||||
self.dff_insts[row,col]=self.add_inst(name=name,
|
self.dff_insts[row,col]=self.add_inst(name=name,
|
||||||
mod=self.dff,
|
mod=self.dff)
|
||||||
offset=base,
|
|
||||||
mirror=mirror)
|
|
||||||
self.connect_inst([self.get_din_name(row,col),
|
self.connect_inst([self.get_din_name(row,col),
|
||||||
self.get_dout_name(row,col),
|
self.get_dout_name(row,col),
|
||||||
"clk",
|
"clk",
|
||||||
"vdd",
|
"vdd",
|
||||||
"gnd"])
|
"gnd"])
|
||||||
|
|
||||||
|
def place_dff_array(self):
|
||||||
|
for row in range(self.rows):
|
||||||
|
for col in range(self.columns):
|
||||||
|
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||||
|
if (row % 2 == 0):
|
||||||
|
base = vector(col*self.dff.width,row*self.dff.height)
|
||||||
|
mirror = "R0"
|
||||||
|
else:
|
||||||
|
base = vector(col*self.dff.width,(row+1)*self.dff.height)
|
||||||
|
mirror = "MX"
|
||||||
|
self.place_inst(name=name,
|
||||||
|
offset=base,
|
||||||
|
mirror=mirror)
|
||||||
|
|
||||||
def get_din_name(self, row, col):
|
def get_din_name(self, row, col):
|
||||||
if self.columns == 1:
|
if self.columns == 1:
|
||||||
din_name = "din[{0}]".format(row)
|
din_name = "din[{0}]".format(row)
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,15 @@ class dff_buf_array(design.design):
|
||||||
self.width = self.columns * self.dff.width
|
self.width = self.columns * self.dff.width
|
||||||
self.height = self.rows * self.dff.height
|
self.height = self.rows * self.dff.height
|
||||||
|
|
||||||
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_netlist(self):
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.create_dff_array()
|
self.create_dff_array()
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
|
self.place_dff_array()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -52,16 +56,8 @@ class dff_buf_array(design.design):
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
for col in range(self.columns):
|
for col in range(self.columns):
|
||||||
name = "Xdff_r{0}_c{1}".format(row,col)
|
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||||
if (row % 2 == 0):
|
|
||||||
base = vector(col*self.dff.width,row*self.dff.height)
|
|
||||||
mirror = "R0"
|
|
||||||
else:
|
|
||||||
base = vector(col*self.dff.width,(row+1)*self.dff.height)
|
|
||||||
mirror = "MX"
|
|
||||||
self.dff_insts[row,col]=self.add_inst(name=name,
|
self.dff_insts[row,col]=self.add_inst(name=name,
|
||||||
mod=self.dff,
|
mod=self.dff)
|
||||||
offset=base,
|
|
||||||
mirror=mirror)
|
|
||||||
self.connect_inst([self.get_din_name(row,col),
|
self.connect_inst([self.get_din_name(row,col),
|
||||||
self.get_dout_name(row,col),
|
self.get_dout_name(row,col),
|
||||||
self.get_dout_bar_name(row,col),
|
self.get_dout_bar_name(row,col),
|
||||||
|
|
@ -69,6 +65,20 @@ class dff_buf_array(design.design):
|
||||||
"vdd",
|
"vdd",
|
||||||
"gnd"])
|
"gnd"])
|
||||||
|
|
||||||
|
def place_dff_array(self):
|
||||||
|
for row in range(self.rows):
|
||||||
|
for col in range(self.columns):
|
||||||
|
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||||
|
if (row % 2 == 0):
|
||||||
|
base = vector(col*self.dff.width,row*self.dff.height)
|
||||||
|
mirror = "R0"
|
||||||
|
else:
|
||||||
|
base = vector(col*self.dff.width,(row+1)*self.dff.height)
|
||||||
|
mirror = "MX"
|
||||||
|
self.place_inst(name=name,
|
||||||
|
offset=base,
|
||||||
|
mirror=mirror)
|
||||||
|
|
||||||
def get_din_name(self, row, col):
|
def get_din_name(self, row, col):
|
||||||
if self.columns == 1:
|
if self.columns == 1:
|
||||||
din_name = "din[{0}]".format(row)
|
din_name = "din[{0}]".format(row)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ class hierarchical_decoder(design.design):
|
||||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||||
self.bitcell_height = self.mod_bitcell.height
|
self.bitcell_height = self.mod_bitcell.height
|
||||||
|
|
||||||
|
self.NAND_FORMAT = "DEC_NAND[{0}]"
|
||||||
|
self.INV_FORMAT = "DEC_INV_[{0}]"
|
||||||
|
|
||||||
self.pre2x4_inst = []
|
self.pre2x4_inst = []
|
||||||
self.pre3x8_inst = []
|
self.pre3x8_inst = []
|
||||||
|
|
||||||
|
|
@ -33,22 +36,25 @@ class hierarchical_decoder(design.design):
|
||||||
self.num_inputs = int(math.log(self.rows, 2))
|
self.num_inputs = int(math.log(self.rows, 2))
|
||||||
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
|
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
|
||||||
|
|
||||||
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
self.offset_all_coordinates()
|
|
||||||
|
|
||||||
self.DRC_LVS()
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_netlist(self):
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
self.setup_layout_constants()
|
self.setup_netlist_constants()
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.create_pre_decoder()
|
self.create_pre_decoder()
|
||||||
self.create_row_decoder()
|
self.create_row_decoder()
|
||||||
self.create_input_rail()
|
|
||||||
self.create_predecode_rail()
|
|
||||||
self.route_vdd_gnd()
|
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
|
self.setup_layout_constants()
|
||||||
|
self.place_pre_decoder()
|
||||||
|
self.place_row_decoder()
|
||||||
|
self.route_input_rails()
|
||||||
|
self.route_predecode_rails()
|
||||||
|
self.route_vdd_gnd()
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.inv = pinv()
|
self.inv = pinv()
|
||||||
self.add_mod(self.inv)
|
self.add_mod(self.inv)
|
||||||
|
|
@ -89,7 +95,7 @@ class hierarchical_decoder(design.design):
|
||||||
else:
|
else:
|
||||||
debug.error("Invalid number of inputs for hierarchical decoder",-1)
|
debug.error("Invalid number of inputs for hierarchical decoder",-1)
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_netlist_constants(self):
|
||||||
self.predec_groups = [] # This array is a 2D array.
|
self.predec_groups = [] # This array is a 2D array.
|
||||||
|
|
||||||
# Distributing vertical rails to different groups. One group belongs to one pre-decoder.
|
# Distributing vertical rails to different groups. One group belongs to one pre-decoder.
|
||||||
|
|
@ -112,92 +118,9 @@ class hierarchical_decoder(design.design):
|
||||||
index = index + 1
|
index = index + 1
|
||||||
self.predec_groups.append(lines)
|
self.predec_groups.append(lines)
|
||||||
|
|
||||||
self.calculate_dimensions()
|
|
||||||
|
|
||||||
def create_input_rail(self):
|
def setup_layout_constants(self):
|
||||||
""" Create input rails for the predecoders """
|
""" Calculate the overall dimensions of the hierarchical decoder """
|
||||||
# inputs should be as high as the decoders
|
|
||||||
input_height = self.no_of_pre2x4*self.pre2_4.height + self.no_of_pre3x8*self.pre3_8.height
|
|
||||||
|
|
||||||
# Find the left-most predecoder
|
|
||||||
min_x = 0
|
|
||||||
if self.no_of_pre2x4 > 0:
|
|
||||||
min_x = min(min_x, -self.pre2_4.width)
|
|
||||||
if self.no_of_pre3x8 > 0:
|
|
||||||
min_x = min(min_x, -self.pre3_8.width)
|
|
||||||
input_offset=vector(min_x - self.input_routing_width,0)
|
|
||||||
|
|
||||||
input_bus_names = ["addr[{0}]".format(i) for i in range(self.num_inputs)]
|
|
||||||
self.input_rails = self.create_vertical_pin_bus(layer="metal2",
|
|
||||||
pitch=self.m2_pitch,
|
|
||||||
offset=input_offset,
|
|
||||||
names=input_bus_names,
|
|
||||||
length=input_height)
|
|
||||||
|
|
||||||
self.connect_input_to_predecodes()
|
|
||||||
|
|
||||||
|
|
||||||
def connect_input_to_predecodes(self):
|
|
||||||
""" Connect the vertical input rail to the predecoders """
|
|
||||||
for pre_num in range(self.no_of_pre2x4):
|
|
||||||
for i in range(2):
|
|
||||||
index = pre_num * 2 + i
|
|
||||||
|
|
||||||
input_pos = self.input_rails["addr[{}]".format(index)]
|
|
||||||
|
|
||||||
in_name = "in[{}]".format(i)
|
|
||||||
decoder_pin = self.pre2x4_inst[pre_num].get_pin(in_name)
|
|
||||||
|
|
||||||
# To prevent conflicts, we will offset each input connect so
|
|
||||||
# that it aligns with the vdd/gnd rails
|
|
||||||
decoder_offset = decoder_pin.bc() + vector(0,(i+1)*self.inv.height)
|
|
||||||
input_offset = input_pos.scale(1,0) + decoder_offset.scale(0,1)
|
|
||||||
|
|
||||||
self.connect_input_rail(decoder_offset, input_offset)
|
|
||||||
|
|
||||||
|
|
||||||
for pre_num in range(self.no_of_pre3x8):
|
|
||||||
for i in range(3):
|
|
||||||
index = pre_num * 3 + i + self.no_of_pre2x4 * 2
|
|
||||||
|
|
||||||
input_pos = self.input_rails["addr[{}]".format(index)]
|
|
||||||
|
|
||||||
in_name = "in[{}]".format(i)
|
|
||||||
decoder_pin = self.pre3x8_inst[pre_num].get_pin(in_name)
|
|
||||||
|
|
||||||
# To prevent conflicts, we will offset each input connect so
|
|
||||||
# that it aligns with the vdd/gnd rails
|
|
||||||
decoder_offset = decoder_pin.bc() + vector(0,(i+1)*self.inv.height)
|
|
||||||
input_offset = input_pos.scale(1,0) + decoder_offset.scale(0,1)
|
|
||||||
|
|
||||||
self.connect_input_rail(decoder_offset, input_offset)
|
|
||||||
|
|
||||||
|
|
||||||
def connect_input_rail(self, input_offset, output_offset):
|
|
||||||
""" Connect a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """
|
|
||||||
|
|
||||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=input_offset,
|
|
||||||
rotate=90)
|
|
||||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=output_offset,
|
|
||||||
rotate=90)
|
|
||||||
self.add_path(("metal3"), [input_offset, output_offset])
|
|
||||||
|
|
||||||
|
|
||||||
def add_pins(self):
|
|
||||||
""" Add the module pins """
|
|
||||||
|
|
||||||
for i in range(self.num_inputs):
|
|
||||||
self.add_pin("addr[{0}]".format(i))
|
|
||||||
|
|
||||||
for j in range(self.rows):
|
|
||||||
self.add_pin("decode[{0}]".format(j))
|
|
||||||
self.add_pin("vdd")
|
|
||||||
self.add_pin("gnd")
|
|
||||||
|
|
||||||
def calculate_dimensions(self):
|
|
||||||
""" Calculate the overal dimensions of the hierarchical decoder """
|
|
||||||
|
|
||||||
# If we have 4 or fewer rows, the predecoder is the decoder itself
|
# If we have 4 or fewer rows, the predecoder is the decoder itself
|
||||||
if self.num_inputs>=4:
|
if self.num_inputs>=4:
|
||||||
|
|
@ -227,24 +150,105 @@ class hierarchical_decoder(design.design):
|
||||||
self.height = self.row_decoder_height
|
self.height = self.row_decoder_height
|
||||||
self.width = self.input_routing_width + self.predecoder_width \
|
self.width = self.input_routing_width + self.predecoder_width \
|
||||||
+ self.internal_routing_width + nand_width + self.inv.width
|
+ self.internal_routing_width + nand_width + self.inv.width
|
||||||
|
|
||||||
|
def route_input_rails(self):
|
||||||
|
""" Create input rails for the predecoders """
|
||||||
|
# inputs should be as high as the decoders
|
||||||
|
input_height = self.no_of_pre2x4*self.pre2_4.height + self.no_of_pre3x8*self.pre3_8.height
|
||||||
|
|
||||||
|
# Find the left-most predecoder
|
||||||
|
min_x = 0
|
||||||
|
if self.no_of_pre2x4 > 0:
|
||||||
|
min_x = min(min_x, -self.pre2_4.width)
|
||||||
|
if self.no_of_pre3x8 > 0:
|
||||||
|
min_x = min(min_x, -self.pre3_8.width)
|
||||||
|
input_offset=vector(min_x - self.input_routing_width,0)
|
||||||
|
|
||||||
|
input_bus_names = ["addr[{0}]".format(i) for i in range(self.num_inputs)]
|
||||||
|
self.input_rails = self.create_vertical_pin_bus(layer="metal2",
|
||||||
|
pitch=self.m2_pitch,
|
||||||
|
offset=input_offset,
|
||||||
|
names=input_bus_names,
|
||||||
|
length=input_height)
|
||||||
|
|
||||||
|
self.route_input_to_predecodes()
|
||||||
|
|
||||||
|
|
||||||
|
def route_input_to_predecodes(self):
|
||||||
|
""" Route the vertical input rail to the predecoders """
|
||||||
|
for pre_num in range(self.no_of_pre2x4):
|
||||||
|
for i in range(2):
|
||||||
|
index = pre_num * 2 + i
|
||||||
|
|
||||||
|
input_pos = self.input_rails["addr[{}]".format(index)]
|
||||||
|
|
||||||
|
in_name = "in[{}]".format(i)
|
||||||
|
decoder_pin = self.pre2x4_inst[pre_num].get_pin(in_name)
|
||||||
|
|
||||||
|
# To prevent conflicts, we will offset each input connect so
|
||||||
|
# that it aligns with the vdd/gnd rails
|
||||||
|
decoder_offset = decoder_pin.bc() + vector(0,(i+1)*self.inv.height)
|
||||||
|
input_offset = input_pos.scale(1,0) + decoder_offset.scale(0,1)
|
||||||
|
|
||||||
|
self.route_input_rail(decoder_offset, input_offset)
|
||||||
|
|
||||||
|
|
||||||
|
for pre_num in range(self.no_of_pre3x8):
|
||||||
|
for i in range(3):
|
||||||
|
index = pre_num * 3 + i + self.no_of_pre2x4 * 2
|
||||||
|
|
||||||
|
input_pos = self.input_rails["addr[{}]".format(index)]
|
||||||
|
|
||||||
|
in_name = "in[{}]".format(i)
|
||||||
|
decoder_pin = self.pre3x8_inst[pre_num].get_pin(in_name)
|
||||||
|
|
||||||
|
# To prevent conflicts, we will offset each input connect so
|
||||||
|
# that it aligns with the vdd/gnd rails
|
||||||
|
decoder_offset = decoder_pin.bc() + vector(0,(i+1)*self.inv.height)
|
||||||
|
input_offset = input_pos.scale(1,0) + decoder_offset.scale(0,1)
|
||||||
|
|
||||||
|
self.route_input_rail(decoder_offset, input_offset)
|
||||||
|
|
||||||
|
|
||||||
|
def route_input_rail(self, input_offset, output_offset):
|
||||||
|
""" Route a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """
|
||||||
|
|
||||||
|
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||||
|
offset=input_offset,
|
||||||
|
rotate=90)
|
||||||
|
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||||
|
offset=output_offset,
|
||||||
|
rotate=90)
|
||||||
|
self.add_path(("metal3"), [input_offset, output_offset])
|
||||||
|
|
||||||
|
|
||||||
|
def add_pins(self):
|
||||||
|
""" Add the module pins """
|
||||||
|
|
||||||
|
for i in range(self.num_inputs):
|
||||||
|
self.add_pin("addr[{0}]".format(i))
|
||||||
|
|
||||||
|
for j in range(self.rows):
|
||||||
|
self.add_pin("decode[{0}]".format(j))
|
||||||
|
self.add_pin("vdd")
|
||||||
|
self.add_pin("gnd")
|
||||||
|
|
||||||
|
|
||||||
def create_pre_decoder(self):
|
def create_pre_decoder(self):
|
||||||
""" Creates pre-decoder and places labels input address [A] """
|
""" Creates pre-decoder and places labels input address [A] """
|
||||||
|
|
||||||
for i in range(self.no_of_pre2x4):
|
for i in range(self.no_of_pre2x4):
|
||||||
self.add_pre2x4(i)
|
self.create_pre2x4(i)
|
||||||
|
|
||||||
for i in range(self.no_of_pre3x8):
|
for i in range(self.no_of_pre3x8):
|
||||||
self.add_pre3x8(i)
|
self.create_pre3x8(i)
|
||||||
|
|
||||||
def add_pre2x4(self,num):
|
def create_pre2x4(self,num):
|
||||||
""" Add a 2x4 predecoder to the left of the origin """
|
""" Add a 2x4 predecoder to the left of the origin """
|
||||||
|
|
||||||
if (self.num_inputs == 2):
|
if (self.num_inputs == 2):
|
||||||
base = vector(-self.pre2_4.width,0)
|
|
||||||
index_off1 = index_off2 = 0
|
index_off1 = index_off2 = 0
|
||||||
else:
|
else:
|
||||||
base= vector(-self.pre2_4.width, num * self.pre2_4.height)
|
|
||||||
index_off1 = num * 2
|
index_off1 = num * 2
|
||||||
index_off2 = num * 4
|
index_off2 = num * 4
|
||||||
|
|
||||||
|
|
@ -256,20 +260,12 @@ class hierarchical_decoder(design.design):
|
||||||
pins.extend(["vdd", "gnd"])
|
pins.extend(["vdd", "gnd"])
|
||||||
|
|
||||||
self.pre2x4_inst.append(self.add_inst(name="pre[{0}]".format(num),
|
self.pre2x4_inst.append(self.add_inst(name="pre[{0}]".format(num),
|
||||||
mod=self.pre2_4,
|
mod=self.pre2_4))
|
||||||
offset=base))
|
|
||||||
self.connect_inst(pins)
|
self.connect_inst(pins)
|
||||||
|
|
||||||
|
|
||||||
def add_pre3x8(self,num):
|
def create_pre3x8(self,num):
|
||||||
""" Add 3x8 predecoder to the left of the origin and above any 2x4 decoders """
|
""" Add 3x8 predecoder to the left of the origin and above any 2x4 decoders """
|
||||||
if (self.num_inputs == 3):
|
|
||||||
offset = vector(-self.pre_3_8.width,0)
|
|
||||||
mirror ="R0"
|
|
||||||
else:
|
|
||||||
height = self.no_of_pre2x4*self.pre2_4.height + num*self.pre3_8.height
|
|
||||||
offset = vector(-self.pre3_8.width, height)
|
|
||||||
|
|
||||||
# If we had 2x4 predecodes, those are used as the lower
|
# If we had 2x4 predecodes, those are used as the lower
|
||||||
# decode output bits
|
# decode output bits
|
||||||
in_index_offset = num * 3 + self.no_of_pre2x4 * 2
|
in_index_offset = num * 3 + self.no_of_pre2x4 * 2
|
||||||
|
|
@ -283,79 +279,112 @@ class hierarchical_decoder(design.design):
|
||||||
pins.extend(["vdd", "gnd"])
|
pins.extend(["vdd", "gnd"])
|
||||||
|
|
||||||
self.pre3x8_inst.append(self.add_inst(name="pre3x8[{0}]".format(num),
|
self.pre3x8_inst.append(self.add_inst(name="pre3x8[{0}]".format(num),
|
||||||
mod=self.pre3_8,
|
mod=self.pre3_8))
|
||||||
offset=offset))
|
|
||||||
self.connect_inst(pins)
|
self.connect_inst(pins)
|
||||||
|
|
||||||
|
|
||||||
|
def place_pre_decoder(self):
|
||||||
|
""" Creates pre-decoder and places labels input address [A] """
|
||||||
|
|
||||||
|
for i in range(self.no_of_pre2x4):
|
||||||
|
self.place_pre2x4(i)
|
||||||
|
|
||||||
|
for i in range(self.no_of_pre3x8):
|
||||||
|
self.place_pre3x8(i)
|
||||||
|
|
||||||
|
def place_pre2x4(self,num):
|
||||||
|
""" Place 2x4 predecoder to the left of the origin """
|
||||||
|
|
||||||
|
if (self.num_inputs == 2):
|
||||||
|
base = vector(-self.pre2_4.width,0)
|
||||||
|
else:
|
||||||
|
base= vector(-self.pre2_4.width, num * self.pre2_4.height)
|
||||||
|
|
||||||
|
self.place_inst(name="pre[{0}]".format(num),
|
||||||
|
offset=base)
|
||||||
|
|
||||||
|
|
||||||
|
def place_pre3x8(self,num):
|
||||||
|
""" Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """
|
||||||
|
if (self.num_inputs == 3):
|
||||||
|
offset = vector(-self.pre_3_8.width,0)
|
||||||
|
mirror ="R0"
|
||||||
|
else:
|
||||||
|
height = self.no_of_pre2x4*self.pre2_4.height + num*self.pre3_8.height
|
||||||
|
offset = vector(-self.pre3_8.width, height)
|
||||||
|
|
||||||
|
self.place_inst(name="pre3x8[{0}]".format(num),
|
||||||
|
offset=offset)
|
||||||
|
|
||||||
|
|
||||||
def create_row_decoder(self):
|
def create_row_decoder(self):
|
||||||
""" Create the row-decoder by placing NAND2/NAND3 and Inverters
|
""" Create the row-decoder by placing NAND2/NAND3 and Inverters
|
||||||
and add the primary decoder output pins. """
|
and add the primary decoder output pins. """
|
||||||
if (self.num_inputs >= 4):
|
if (self.num_inputs >= 4):
|
||||||
self.add_decoder_nand_array()
|
self.create_decoder_nand_array()
|
||||||
self.add_decoder_inv_array()
|
self.create_decoder_inv_array()
|
||||||
self.route_decoder()
|
|
||||||
|
|
||||||
|
|
||||||
def add_decoder_nand_array(self):
|
def create_decoder_nand_array(self):
|
||||||
""" Add a column of NAND gates for final decode """
|
""" Add a column of NAND gates for final decode """
|
||||||
|
|
||||||
|
self.nand_inst = []
|
||||||
|
|
||||||
# Row Decoder NAND GATE array for address inputs <5.
|
# Row Decoder NAND GATE array for address inputs <5.
|
||||||
if (self.num_inputs == 4 or self.num_inputs == 5):
|
if (self.num_inputs == 4 or self.num_inputs == 5):
|
||||||
self.add_nand_array(nand_mod=self.nand2)
|
|
||||||
# FIXME: Can we convert this to the connect_inst with checks?
|
|
||||||
for i in range(len(self.predec_groups[0])):
|
for i in range(len(self.predec_groups[0])):
|
||||||
for j in range(len(self.predec_groups[1])):
|
for j in range(len(self.predec_groups[1])):
|
||||||
|
row = len(self.predec_groups[1])*i + j
|
||||||
|
name = self.NAND_FORMAT.format(row)
|
||||||
|
self.nand_inst.append(self.add_inst(name=name,
|
||||||
|
mod=self.nand2))
|
||||||
pins =["out[{0}]".format(i),
|
pins =["out[{0}]".format(i),
|
||||||
"out[{0}]".format(j + len(self.predec_groups[0])),
|
"out[{0}]".format(j + len(self.predec_groups[0])),
|
||||||
"Z[{0}]".format(len(self.predec_groups[1])*i + j),
|
"Z[{0}]".format(row),
|
||||||
"vdd", "gnd"]
|
"vdd", "gnd"]
|
||||||
self.connect_inst(args=pins, check=False)
|
self.connect_inst(pins)
|
||||||
|
|
||||||
|
|
||||||
# Row Decoder NAND GATE array for address inputs >5.
|
# Row Decoder NAND GATE array for address inputs >5.
|
||||||
elif (self.num_inputs > 5):
|
elif (self.num_inputs > 5):
|
||||||
self.add_nand_array(nand_mod=self.nand3,
|
|
||||||
correct=drc["minwidth_metal1"])
|
|
||||||
# This will not check that the inst connections match.
|
|
||||||
for i in range(len(self.predec_groups[0])):
|
for i in range(len(self.predec_groups[0])):
|
||||||
for j in range(len(self.predec_groups[1])):
|
for j in range(len(self.predec_groups[1])):
|
||||||
for k in range(len(self.predec_groups[2])):
|
for k in range(len(self.predec_groups[2])):
|
||||||
Z_index = len(self.predec_groups[1])*len(self.predec_groups[2]) * i \
|
row = len(self.predec_groups[1])*len(self.predec_groups[2]) * i \
|
||||||
+ len(self.predec_groups[2])*j + k
|
+ len(self.predec_groups[2])*j + k
|
||||||
|
|
||||||
|
name = self.NAND_FORMAT.format(row)
|
||||||
|
self.nand_inst.append(self.add_inst(name=name,
|
||||||
|
mod=self.nand3))
|
||||||
|
|
||||||
pins = ["out[{0}]".format(i),
|
pins = ["out[{0}]".format(i),
|
||||||
"out[{0}]".format(j + len(self.predec_groups[0])),
|
"out[{0}]".format(j + len(self.predec_groups[0])),
|
||||||
"out[{0}]".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])),
|
"out[{0}]".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])),
|
||||||
"Z[{0}]".format(Z_index),
|
"Z[{0}]".format(row),
|
||||||
"vdd", "gnd"]
|
"vdd", "gnd"]
|
||||||
self.connect_inst(args=pins, check=False)
|
self.connect_inst(pins)
|
||||||
|
|
||||||
def add_nand_array(self, nand_mod, correct=0):
|
|
||||||
""" Add a column of NAND gates for the decoder above the predecoders."""
|
def create_decoder_inv_array(self):
|
||||||
|
"""
|
||||||
|
Add a column of INV gates for the decoder.
|
||||||
|
"""
|
||||||
|
|
||||||
self.nand_inst = []
|
self.inv_inst = []
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
name = "DEC_NAND[{0}]".format(row)
|
name = self.INV_FORMAT.format(row)
|
||||||
if ((row % 2) == 0):
|
self.inv_inst.append(self.add_inst(name=name,
|
||||||
y_off = nand_mod.height*row
|
mod=self.inv))
|
||||||
y_dir = 1
|
self.connect_inst(args=["Z[{0}]".format(row),
|
||||||
mirror = "R0"
|
"decode[{0}]".format(row),
|
||||||
else:
|
"vdd", "gnd"])
|
||||||
y_off = nand_mod.height*(row + 1)
|
|
||||||
y_dir = -1
|
|
||||||
mirror = "MX"
|
|
||||||
|
|
||||||
self.nand_inst.append(self.add_inst(name=name,
|
|
||||||
mod=nand_mod,
|
|
||||||
offset=[self.internal_routing_width, y_off],
|
|
||||||
mirror=mirror))
|
|
||||||
|
|
||||||
|
def place_decoder_inv_array(self):
|
||||||
|
"""
|
||||||
def add_decoder_inv_array(self):
|
Place the column of INV gates for the decoder above the predecoders
|
||||||
"""Add a column of INV gates for the decoder above the predecoders
|
and to the right of the NAND decoders.
|
||||||
and to the right of the NAND decoders."""
|
"""
|
||||||
|
|
||||||
z_pin = self.inv.get_pin("Z")
|
z_pin = self.inv.get_pin("Z")
|
||||||
|
|
||||||
|
|
@ -364,9 +393,8 @@ class hierarchical_decoder(design.design):
|
||||||
else:
|
else:
|
||||||
x_off = self.internal_routing_width + self.nand3.width
|
x_off = self.internal_routing_width + self.nand3.width
|
||||||
|
|
||||||
self.inv_inst = []
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
name = "DEC_INV_[{0}]".format(row)
|
name = self.INV_FORMAT.format(row)
|
||||||
if (row % 2 == 0):
|
if (row % 2 == 0):
|
||||||
inv_row_height = self.inv.height * row
|
inv_row_height = self.inv.height * row
|
||||||
mirror = "R0"
|
mirror = "R0"
|
||||||
|
|
@ -377,17 +405,52 @@ class hierarchical_decoder(design.design):
|
||||||
y_dir = -1
|
y_dir = -1
|
||||||
y_off = inv_row_height
|
y_off = inv_row_height
|
||||||
offset = vector(x_off,y_off)
|
offset = vector(x_off,y_off)
|
||||||
|
self.place_inst(name=name,
|
||||||
self.inv_inst.append(self.add_inst(name=name,
|
offset=offset,
|
||||||
mod=self.inv,
|
mirror=mirror)
|
||||||
offset=offset,
|
|
||||||
mirror=mirror))
|
|
||||||
|
|
||||||
# This will not check that the inst connections match.
|
def place_row_decoder(self):
|
||||||
self.connect_inst(args=["Z[{0}]".format(row),
|
"""
|
||||||
"decode[{0}]".format(row),
|
Place the row-decoder by placing NAND2/NAND3 and Inverters
|
||||||
"vdd", "gnd"],
|
and add the primary decoder output pins.
|
||||||
check=False)
|
"""
|
||||||
|
if (self.num_inputs >= 4):
|
||||||
|
self.place_decoder_nand_array()
|
||||||
|
self.place_decoder_inv_array()
|
||||||
|
self.route_decoder()
|
||||||
|
|
||||||
|
|
||||||
|
def place_decoder_nand_array(self):
|
||||||
|
""" Add a column of NAND gates for final decode """
|
||||||
|
|
||||||
|
# Row Decoder NAND GATE array for address inputs <5.
|
||||||
|
if (self.num_inputs == 4 or self.num_inputs == 5):
|
||||||
|
self.place_nand_array(nand_mod=self.nand2)
|
||||||
|
|
||||||
|
# Row Decoder NAND GATE array for address inputs >5.
|
||||||
|
# FIXME: why this correct offset?)
|
||||||
|
elif (self.num_inputs > 5):
|
||||||
|
self.place_nand_array(nand_mod=self.nand3)
|
||||||
|
|
||||||
|
def place_nand_array(self, nand_mod):
|
||||||
|
""" Add a column of NAND gates for the decoder above the predecoders."""
|
||||||
|
|
||||||
|
for row in range(self.rows):
|
||||||
|
name = self.NAND_FORMAT.format(row)
|
||||||
|
if ((row % 2) == 0):
|
||||||
|
y_off = nand_mod.height*row
|
||||||
|
y_dir = 1
|
||||||
|
mirror = "R0"
|
||||||
|
else:
|
||||||
|
y_off = nand_mod.height*(row + 1)
|
||||||
|
y_dir = -1
|
||||||
|
mirror = "MX"
|
||||||
|
|
||||||
|
self.place_inst(name=name,
|
||||||
|
offset=[self.internal_routing_width, y_off],
|
||||||
|
mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def route_decoder(self):
|
def route_decoder(self):
|
||||||
|
|
@ -412,7 +475,7 @@ class hierarchical_decoder(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_predecode_rail(self):
|
def route_predecode_rails(self):
|
||||||
""" Creates vertical metal 2 rails to connect predecoder and decoder stages."""
|
""" Creates vertical metal 2 rails to connect predecoder and decoder stages."""
|
||||||
|
|
||||||
# This is not needed for inputs <4 since they have no pre/decode stages.
|
# This is not needed for inputs <4 since they have no pre/decode stages.
|
||||||
|
|
@ -426,10 +489,10 @@ class hierarchical_decoder(design.design):
|
||||||
length=self.height)
|
length=self.height)
|
||||||
|
|
||||||
|
|
||||||
self.connect_rails_to_predecodes()
|
self.route_rails_to_predecodes()
|
||||||
self.connect_rails_to_decoder()
|
self.route_rails_to_decoder()
|
||||||
|
|
||||||
def connect_rails_to_predecodes(self):
|
def route_rails_to_predecodes(self):
|
||||||
""" Iterates through all of the predecodes and connects to the rails including the offsets """
|
""" Iterates through all of the predecodes and connects to the rails including the offsets """
|
||||||
|
|
||||||
# FIXME: convert to connect_bus
|
# FIXME: convert to connect_bus
|
||||||
|
|
@ -438,7 +501,7 @@ class hierarchical_decoder(design.design):
|
||||||
predecode_name = "predecode[{}]".format(pre_num * 4 + i)
|
predecode_name = "predecode[{}]".format(pre_num * 4 + i)
|
||||||
out_name = "out[{}]".format(i)
|
out_name = "out[{}]".format(i)
|
||||||
pin = self.pre2x4_inst[pre_num].get_pin(out_name)
|
pin = self.pre2x4_inst[pre_num].get_pin(out_name)
|
||||||
self.connect_predecode_rail_m3(predecode_name, pin)
|
self.route_predecode_rail_m3(predecode_name, pin)
|
||||||
|
|
||||||
|
|
||||||
# FIXME: convert to connect_bus
|
# FIXME: convert to connect_bus
|
||||||
|
|
@ -447,11 +510,11 @@ class hierarchical_decoder(design.design):
|
||||||
predecode_name = "predecode[{}]".format(pre_num * 8 + i + self.no_of_pre2x4 * 4)
|
predecode_name = "predecode[{}]".format(pre_num * 8 + i + self.no_of_pre2x4 * 4)
|
||||||
out_name = "out[{}]".format(i)
|
out_name = "out[{}]".format(i)
|
||||||
pin = self.pre3x8_inst[pre_num].get_pin(out_name)
|
pin = self.pre3x8_inst[pre_num].get_pin(out_name)
|
||||||
self.connect_predecode_rail_m3(predecode_name, pin)
|
self.route_predecode_rail_m3(predecode_name, pin)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def connect_rails_to_decoder(self):
|
def route_rails_to_decoder(self):
|
||||||
""" Use the self.predec_groups to determine the connections to the decoder NAND gates.
|
""" Use the self.predec_groups to determine the connections to the decoder NAND gates.
|
||||||
Inputs of NAND2/NAND3 gates come from different groups.
|
Inputs of NAND2/NAND3 gates come from different groups.
|
||||||
For example for these groups [ [0,1,2,3] ,[4,5,6,7],
|
For example for these groups [ [0,1,2,3] ,[4,5,6,7],
|
||||||
|
|
@ -465,9 +528,9 @@ class hierarchical_decoder(design.design):
|
||||||
for index_B in self.predec_groups[1]:
|
for index_B in self.predec_groups[1]:
|
||||||
# FIXME: convert to connect_bus?
|
# FIXME: convert to connect_bus?
|
||||||
predecode_name = "predecode[{}]".format(index_A)
|
predecode_name = "predecode[{}]".format(index_A)
|
||||||
self.connect_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A"))
|
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A"))
|
||||||
predecode_name = "predecode[{}]".format(index_B)
|
predecode_name = "predecode[{}]".format(index_B)
|
||||||
self.connect_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B"))
|
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B"))
|
||||||
row_index = row_index + 1
|
row_index = row_index + 1
|
||||||
|
|
||||||
elif (self.num_inputs > 5):
|
elif (self.num_inputs > 5):
|
||||||
|
|
@ -476,11 +539,11 @@ class hierarchical_decoder(design.design):
|
||||||
for index_C in self.predec_groups[2]:
|
for index_C in self.predec_groups[2]:
|
||||||
# FIXME: convert to connect_bus?
|
# FIXME: convert to connect_bus?
|
||||||
predecode_name = "predecode[{}]".format(index_A)
|
predecode_name = "predecode[{}]".format(index_A)
|
||||||
self.connect_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A"))
|
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A"))
|
||||||
predecode_name = "predecode[{}]".format(index_B)
|
predecode_name = "predecode[{}]".format(index_B)
|
||||||
self.connect_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B"))
|
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B"))
|
||||||
predecode_name = "predecode[{}]".format(index_C)
|
predecode_name = "predecode[{}]".format(index_C)
|
||||||
self.connect_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("C"))
|
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("C"))
|
||||||
row_index = row_index + 1
|
row_index = row_index + 1
|
||||||
|
|
||||||
def route_vdd_gnd(self):
|
def route_vdd_gnd(self):
|
||||||
|
|
@ -516,7 +579,7 @@ class hierarchical_decoder(design.design):
|
||||||
self.copy_layout_pin(pre, "gnd")
|
self.copy_layout_pin(pre, "gnd")
|
||||||
|
|
||||||
|
|
||||||
def connect_predecode_rail(self, rail_name, pin):
|
def route_predecode_rail(self, rail_name, pin):
|
||||||
""" Connect the routing rail to the given metal1 pin """
|
""" Connect the routing rail to the given metal1 pin """
|
||||||
rail_pos = vector(self.predecode_rails[rail_name].x,pin.lc().y)
|
rail_pos = vector(self.predecode_rails[rail_name].x,pin.lc().y)
|
||||||
self.add_path("metal1", [rail_pos, pin.lc()])
|
self.add_path("metal1", [rail_pos, pin.lc()])
|
||||||
|
|
@ -525,7 +588,7 @@ class hierarchical_decoder(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
|
|
||||||
def connect_predecode_rail_m3(self, rail_name, pin):
|
def route_predecode_rail_m3(self, rail_name, pin):
|
||||||
""" Connect the routing rail to the given metal1 pin """
|
""" Connect the routing rail to the given metal1 pin """
|
||||||
# This routes the pin up to the rail, basically, to avoid conflicts.
|
# This routes the pin up to the rail, basically, to avoid conflicts.
|
||||||
# It would be fixed with a channel router.
|
# It would be fixed with a channel router.
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ class hierarchical_predecode(design.design):
|
||||||
# Height width are computed
|
# Height width are computed
|
||||||
self.width = self.x_off_inv_2 + self.inv.width
|
self.width = self.x_off_inv_2 + self.inv.width
|
||||||
|
|
||||||
def create_rails(self):
|
def route_rails(self):
|
||||||
""" Create all of the rails for the inputs and vdd/gnd/inputs_bar/inputs """
|
""" Create all of the rails for the inputs and vdd/gnd/inputs_bar/inputs """
|
||||||
input_names = ["in[{}]".format(x) for x in range(self.number_of_inputs)]
|
input_names = ["in[{}]".format(x) for x in range(self.number_of_inputs)]
|
||||||
offset = vector(0.5*self.m2_width,2*self.m1_width)
|
offset = vector(0.5*self.m2_width,2*self.m1_width)
|
||||||
|
|
@ -86,10 +86,21 @@ class hierarchical_predecode(design.design):
|
||||||
length=self.height - 2*self.m1_width)
|
length=self.height - 2*self.m1_width)
|
||||||
|
|
||||||
|
|
||||||
def add_input_inverters(self):
|
def create_input_inverters(self):
|
||||||
""" Create the input inverters to invert input signals for the decode stage. """
|
""" Create the input inverters to invert input signals for the decode stage. """
|
||||||
|
|
||||||
self.in_inst = []
|
self.in_inst = []
|
||||||
|
for inv_num in range(self.number_of_inputs):
|
||||||
|
name = "Xpre_inv[{0}]".format(inv_num)
|
||||||
|
self.in_inst.append(self.add_inst(name=name,
|
||||||
|
mod=self.inv))
|
||||||
|
self.connect_inst(["in[{0}]".format(inv_num),
|
||||||
|
"inbar[{0}]".format(inv_num),
|
||||||
|
"vdd", "gnd"])
|
||||||
|
|
||||||
|
def place_input_inverters(self):
|
||||||
|
""" Place the input inverters to invert input signals for the decode stage. """
|
||||||
|
|
||||||
for inv_num in range(self.number_of_inputs):
|
for inv_num in range(self.number_of_inputs):
|
||||||
name = "Xpre_inv[{0}]".format(inv_num)
|
name = "Xpre_inv[{0}]".format(inv_num)
|
||||||
if (inv_num % 2 == 0):
|
if (inv_num % 2 == 0):
|
||||||
|
|
@ -99,18 +110,26 @@ class hierarchical_predecode(design.design):
|
||||||
y_off = (inv_num + 1) * (self.inv.height)
|
y_off = (inv_num + 1) * (self.inv.height)
|
||||||
mirror="MX"
|
mirror="MX"
|
||||||
offset = vector(self.x_off_inv_1, y_off)
|
offset = vector(self.x_off_inv_1, y_off)
|
||||||
self.in_inst.append(self.add_inst(name=name,
|
self.place_inst(name=name,
|
||||||
mod=self.inv,
|
offset=offset,
|
||||||
offset=offset,
|
mirror=mirror)
|
||||||
mirror=mirror))
|
|
||||||
self.connect_inst(["in[{0}]".format(inv_num),
|
|
||||||
"inbar[{0}]".format(inv_num),
|
|
||||||
"vdd", "gnd"])
|
|
||||||
|
|
||||||
def add_output_inverters(self):
|
def create_output_inverters(self):
|
||||||
""" Create inverters for the inverted output decode signals. """
|
""" Create inverters for the inverted output decode signals. """
|
||||||
|
|
||||||
self.inv_inst = []
|
self.inv_inst = []
|
||||||
|
for inv_num in range(self.number_of_outputs):
|
||||||
|
name = "Xpre_nand_inv[{}]".format(inv_num)
|
||||||
|
self.inv_inst.append(self.add_inst(name=name,
|
||||||
|
mod=self.inv))
|
||||||
|
self.connect_inst(["Z[{}]".format(inv_num),
|
||||||
|
"out[{}]".format(inv_num),
|
||||||
|
"vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
|
def place_output_inverters(self):
|
||||||
|
""" Place inverters for the inverted output decode signals. """
|
||||||
|
|
||||||
for inv_num in range(self.number_of_outputs):
|
for inv_num in range(self.number_of_outputs):
|
||||||
name = "Xpre_nand_inv[{}]".format(inv_num)
|
name = "Xpre_nand_inv[{}]".format(inv_num)
|
||||||
if (inv_num % 2 == 0):
|
if (inv_num % 2 == 0):
|
||||||
|
|
@ -120,19 +139,23 @@ class hierarchical_predecode(design.design):
|
||||||
y_off =(inv_num + 1)*self.inv.height
|
y_off =(inv_num + 1)*self.inv.height
|
||||||
mirror = "MX"
|
mirror = "MX"
|
||||||
offset = vector(self.x_off_inv_2, y_off)
|
offset = vector(self.x_off_inv_2, y_off)
|
||||||
self.inv_inst.append(self.add_inst(name=name,
|
self.place_inst(name=name,
|
||||||
mod=self.inv,
|
offset=offset,
|
||||||
offset=offset,
|
mirror=mirror)
|
||||||
mirror=mirror))
|
|
||||||
self.connect_inst(["Z[{}]".format(inv_num),
|
|
||||||
"out[{}]".format(inv_num),
|
|
||||||
"vdd", "gnd"])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_nand(self,connections):
|
def create_nand_array(self,connections):
|
||||||
""" Create the NAND stage for the decodes """
|
""" Create the NAND stage for the decodes """
|
||||||
self.nand_inst = []
|
self.nand_inst = []
|
||||||
|
for nand_input in range(self.number_of_outputs):
|
||||||
|
inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs)
|
||||||
|
name = "Xpre{0}_nand[{1}]".format(inout,nand_input)
|
||||||
|
self.nand_inst.append(self.add_inst(name=name,
|
||||||
|
mod=self.nand))
|
||||||
|
self.connect_inst(connections[nand_input])
|
||||||
|
|
||||||
|
|
||||||
|
def place_nand_array(self):
|
||||||
|
""" Place the NAND stage for the decodes """
|
||||||
for nand_input in range(self.number_of_outputs):
|
for nand_input in range(self.number_of_outputs):
|
||||||
inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs)
|
inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs)
|
||||||
name = "Xpre{0}_nand[{1}]".format(inout,nand_input)
|
name = "Xpre{0}_nand[{1}]".format(inout,nand_input)
|
||||||
|
|
@ -143,11 +166,9 @@ class hierarchical_predecode(design.design):
|
||||||
y_off = (nand_input + 1) * self.inv.height
|
y_off = (nand_input + 1) * self.inv.height
|
||||||
mirror = "MX"
|
mirror = "MX"
|
||||||
offset = vector(self.x_off_nand, y_off)
|
offset = vector(self.x_off_nand, y_off)
|
||||||
self.nand_inst.append(self.add_inst(name=name,
|
self.place_inst(name=name,
|
||||||
mod=self.nand,
|
offset=offset,
|
||||||
offset=offset,
|
mirror=mirror)
|
||||||
mirror=mirror))
|
|
||||||
self.connect_inst(connections[nand_input])
|
|
||||||
|
|
||||||
|
|
||||||
def route(self):
|
def route(self):
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,17 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.create_modules()
|
self.create_modules()
|
||||||
self.setup_constraints()
|
self.setup_constraints()
|
||||||
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
self.DRC_LVS()
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.create_input_inverters()
|
||||||
|
self.create_output_inverters()
|
||||||
|
connections =[["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"],
|
||||||
|
["in[0]", "inbar[1]", "Z[1]", "vdd", "gnd"],
|
||||||
|
["inbar[0]", "in[1]", "Z[2]", "vdd", "gnd"],
|
||||||
|
["in[0]", "in[1]", "Z[3]", "vdd", "gnd"]]
|
||||||
|
self.create_nand_array(connections)
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" The general organization is from left to right:
|
""" The general organization is from left to right:
|
||||||
|
|
@ -24,15 +33,12 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs
|
3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs
|
||||||
4) a set of NAND gates for inversion
|
4) a set of NAND gates for inversion
|
||||||
"""
|
"""
|
||||||
self.create_rails()
|
self.route_rails()
|
||||||
self.add_input_inverters()
|
self.place_input_inverters()
|
||||||
self.add_output_inverters()
|
self.place_output_inverters()
|
||||||
connections =[["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"],
|
self.place_nand_array()
|
||||||
["in[0]", "inbar[1]", "Z[1]", "vdd", "gnd"],
|
|
||||||
["inbar[0]", "in[1]", "Z[2]", "vdd", "gnd"],
|
|
||||||
["in[0]", "in[1]", "Z[3]", "vdd", "gnd"]]
|
|
||||||
self.add_nand(connections)
|
|
||||||
self.route()
|
self.route()
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
def get_nand_input_line_combination(self):
|
def get_nand_input_line_combination(self):
|
||||||
""" These are the decoder connections of the NAND gates to the A,B pins """
|
""" These are the decoder connections of the NAND gates to the A,B pins """
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,12 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.create_modules()
|
self.create_modules()
|
||||||
self.setup_constraints()
|
self.setup_constraints()
|
||||||
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
self.DRC_LVS()
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_netlist(self):
|
||||||
""" The general organization is from left to right:
|
self.create_input_inverters()
|
||||||
1) a set of M2 rails for input signals
|
self.create_output_inverters()
|
||||||
2) a set of inverters to invert input signals
|
|
||||||
3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs
|
|
||||||
4) a set of NAND gates for inversion
|
|
||||||
"""
|
|
||||||
self.create_rails()
|
|
||||||
self.add_input_inverters()
|
|
||||||
self.add_output_inverters()
|
|
||||||
connections=[["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"],
|
connections=[["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"],
|
||||||
["in[0]", "inbar[1]", "inbar[2]", "Z[1]", "vdd", "gnd"],
|
["in[0]", "inbar[1]", "inbar[2]", "Z[1]", "vdd", "gnd"],
|
||||||
["inbar[0]", "in[1]", "inbar[2]", "Z[2]", "vdd", "gnd"],
|
["inbar[0]", "in[1]", "inbar[2]", "Z[2]", "vdd", "gnd"],
|
||||||
|
|
@ -35,9 +28,23 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
|
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
|
||||||
["inbar[0]", "in[1]", "in[2]", "Z[6]", "vdd", "gnd"],
|
["inbar[0]", "in[1]", "in[2]", "Z[6]", "vdd", "gnd"],
|
||||||
["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"]]
|
["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"]]
|
||||||
self.add_nand(connections)
|
self.create_nand(connections)
|
||||||
self.route()
|
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
|
"""
|
||||||
|
The general organization is from left to right:
|
||||||
|
1) a set of M2 rails for input signals
|
||||||
|
2) a set of inverters to invert input signals
|
||||||
|
3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs
|
||||||
|
4) a set of NAND gates for inversion
|
||||||
|
"""
|
||||||
|
self.route_rails()
|
||||||
|
self.place_input_inverters()
|
||||||
|
self.place_output_inverters()
|
||||||
|
self.place_nand()
|
||||||
|
self.route()
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
def get_nand_input_line_combination(self):
|
def get_nand_input_line_combination(self):
|
||||||
""" These are the decoder connections of the NAND gates to the A,B,C pins """
|
""" These are the decoder connections of the NAND gates to the A,B,C pins """
|
||||||
combination = [["Abar[0]", "Abar[1]", "Abar[2]"],
|
combination = [["Abar[0]", "Abar[1]", "Abar[2]"],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue