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
|
|
@ -50,6 +50,10 @@ class geometry:
|
|||
ur = vector(max(first[0],second[0]),max(first[1],second[1]))
|
||||
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):
|
||||
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
||||
We must then re-find the ll and ur. The master is the cell instance. """
|
||||
|
|
@ -124,7 +128,7 @@ class instance(geometry):
|
|||
An instance of an instance/module with a specified location and
|
||||
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"""
|
||||
geometry.__init__(self)
|
||||
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:
|
||||
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):
|
||||
"""Adds an instance of a mod to this module"""
|
||||
|
|
|
|||
|
|
@ -91,19 +91,26 @@ class spice(verilog.verilog):
|
|||
group of modules are generated."""
|
||||
|
||||
if (check and (len(self.insts[-1].mod.pins) != len(args))):
|
||||
debug.error("Connections: {}".format(self.insts[-1].mod.pins))
|
||||
debug.error("Connections: {}".format(args))
|
||||
import pprint
|
||||
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),
|
||||
len(args)), 1)
|
||||
self.conns.append(args)
|
||||
|
||||
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,
|
||||
len(self.insts),
|
||||
len(self.conns)))
|
||||
debug.error("Instances: \n"+str(self.insts))
|
||||
debug.error("Instances: \n"+str(insts_string))
|
||||
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.width = self.column_size*self.cell.width + self.m1_width
|
||||
|
||||
self.add_pins()
|
||||
self.create_netlist()
|
||||
|
||||
self.create_layout()
|
||||
self.add_layout_pins()
|
||||
|
||||
# We don't offset this because we need to align
|
||||
# the replica bitcell in the control logic
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
row_list = self.cell.list_all_wl_names()
|
||||
|
|
@ -55,7 +54,6 @@ class bitcell_array(design.design):
|
|||
|
||||
def create_layout(self):
|
||||
xoffset = 0.0
|
||||
self.cell_inst = {}
|
||||
for col in range(self.column_size):
|
||||
yoffset = 0.0
|
||||
for row in range(self.row_size):
|
||||
|
|
@ -68,15 +66,28 @@ class bitcell_array(design.design):
|
|||
tempy = yoffset
|
||||
dir_key = ""
|
||||
|
||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
||||
mod=self.cell,
|
||||
self.place_inst(name=name,
|
||||
offset=[xoffset, tempy],
|
||||
mirror=dir_key)
|
||||
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
||||
|
||||
yoffset += self.cell.height
|
||||
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):
|
||||
""" Add the layout pins """
|
||||
|
|
|
|||
|
|
@ -29,11 +29,15 @@ class dff_array(design.design):
|
|||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_layout(self):
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_dff_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
|
@ -50,6 +54,18 @@ class dff_array(design.design):
|
|||
|
||||
def create_dff_array(self):
|
||||
self.dff_insts={}
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||
self.dff_insts[row,col]=self.add_inst(name=name,
|
||||
mod=self.dff)
|
||||
self.connect_inst([self.get_din_name(row,col),
|
||||
self.get_dout_name(row,col),
|
||||
"clk",
|
||||
"vdd",
|
||||
"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)
|
||||
|
|
@ -59,15 +75,9 @@ class dff_array(design.design):
|
|||
else:
|
||||
base = vector(col*self.dff.width,(row+1)*self.dff.height)
|
||||
mirror = "MX"
|
||||
self.dff_insts[row,col]=self.add_inst(name=name,
|
||||
mod=self.dff,
|
||||
self.place_inst(name=name,
|
||||
offset=base,
|
||||
mirror=mirror)
|
||||
self.connect_inst([self.get_din_name(row,col),
|
||||
self.get_dout_name(row,col),
|
||||
"clk",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
def get_din_name(self, row, col):
|
||||
if self.columns == 1:
|
||||
|
|
|
|||
|
|
@ -27,11 +27,15 @@ class dff_buf_array(design.design):
|
|||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_layout(self):
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_dff_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
|
@ -52,16 +56,8 @@ class dff_buf_array(design.design):
|
|||
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.dff_insts[row,col]=self.add_inst(name=name,
|
||||
mod=self.dff,
|
||||
offset=base,
|
||||
mirror=mirror)
|
||||
mod=self.dff)
|
||||
self.connect_inst([self.get_din_name(row,col),
|
||||
self.get_dout_name(row,col),
|
||||
self.get_dout_bar_name(row,col),
|
||||
|
|
@ -69,6 +65,20 @@ class dff_buf_array(design.design):
|
|||
"vdd",
|
||||
"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):
|
||||
if self.columns == 1:
|
||||
din_name = "din[{0}]".format(row)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ class hierarchical_decoder(design.design):
|
|||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell_height = self.mod_bitcell.height
|
||||
|
||||
self.NAND_FORMAT = "DEC_NAND[{0}]"
|
||||
self.INV_FORMAT = "DEC_INV_[{0}]"
|
||||
|
||||
self.pre2x4_inst = []
|
||||
self.pre3x8_inst = []
|
||||
|
||||
|
|
@ -33,20 +36,23 @@ class hierarchical_decoder(design.design):
|
|||
self.num_inputs = int(math.log(self.rows, 2))
|
||||
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def create_layout(self):
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.setup_layout_constants()
|
||||
self.setup_netlist_constants()
|
||||
self.add_pins()
|
||||
self.create_pre_decoder()
|
||||
self.create_row_decoder()
|
||||
self.create_input_rail()
|
||||
self.create_predecode_rail()
|
||||
|
||||
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):
|
||||
|
|
@ -89,7 +95,7 @@ class hierarchical_decoder(design.design):
|
|||
else:
|
||||
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.
|
||||
|
||||
# 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
|
||||
self.predec_groups.append(lines)
|
||||
|
||||
self.calculate_dimensions()
|
||||
|
||||
def create_input_rail(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.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 """
|
||||
def setup_layout_constants(self):
|
||||
""" Calculate the overall dimensions of the hierarchical decoder """
|
||||
|
||||
# If we have 4 or fewer rows, the predecoder is the decoder itself
|
||||
if self.num_inputs>=4:
|
||||
|
|
@ -228,23 +151,104 @@ class hierarchical_decoder(design.design):
|
|||
self.width = self.input_routing_width + self.predecoder_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):
|
||||
""" Creates pre-decoder and places labels input address [A] """
|
||||
|
||||
for i in range(self.no_of_pre2x4):
|
||||
self.add_pre2x4(i)
|
||||
self.create_pre2x4(i)
|
||||
|
||||
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 """
|
||||
|
||||
if (self.num_inputs == 2):
|
||||
base = vector(-self.pre2_4.width,0)
|
||||
index_off1 = index_off2 = 0
|
||||
else:
|
||||
base= vector(-self.pre2_4.width, num * self.pre2_4.height)
|
||||
index_off1 = num * 2
|
||||
index_off2 = num * 4
|
||||
|
||||
|
|
@ -256,20 +260,12 @@ class hierarchical_decoder(design.design):
|
|||
pins.extend(["vdd", "gnd"])
|
||||
|
||||
self.pre2x4_inst.append(self.add_inst(name="pre[{0}]".format(num),
|
||||
mod=self.pre2_4,
|
||||
offset=base))
|
||||
mod=self.pre2_4))
|
||||
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 """
|
||||
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
|
||||
# decode output bits
|
||||
in_index_offset = num * 3 + self.no_of_pre2x4 * 2
|
||||
|
|
@ -283,79 +279,112 @@ class hierarchical_decoder(design.design):
|
|||
pins.extend(["vdd", "gnd"])
|
||||
|
||||
self.pre3x8_inst.append(self.add_inst(name="pre3x8[{0}]".format(num),
|
||||
mod=self.pre3_8,
|
||||
offset=offset))
|
||||
mod=self.pre3_8))
|
||||
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):
|
||||
""" Create the row-decoder by placing NAND2/NAND3 and Inverters
|
||||
and add the primary decoder output pins. """
|
||||
if (self.num_inputs >= 4):
|
||||
self.add_decoder_nand_array()
|
||||
self.add_decoder_inv_array()
|
||||
self.route_decoder()
|
||||
self.create_decoder_nand_array()
|
||||
self.create_decoder_inv_array()
|
||||
|
||||
|
||||
def add_decoder_nand_array(self):
|
||||
def create_decoder_nand_array(self):
|
||||
""" Add a column of NAND gates for final decode """
|
||||
|
||||
self.nand_inst = []
|
||||
|
||||
# Row Decoder NAND GATE array for address 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 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),
|
||||
"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"]
|
||||
self.connect_inst(args=pins, check=False)
|
||||
self.connect_inst(pins)
|
||||
|
||||
|
||||
# Row Decoder NAND GATE array for address 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 j in range(len(self.predec_groups[1])):
|
||||
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
|
||||
|
||||
name = self.NAND_FORMAT.format(row)
|
||||
self.nand_inst.append(self.add_inst(name=name,
|
||||
mod=self.nand3))
|
||||
|
||||
pins = ["out[{0}]".format(i),
|
||||
"out[{0}]".format(j + len(self.predec_groups[0])),
|
||||
"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"]
|
||||
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."""
|
||||
|
||||
self.nand_inst = []
|
||||
def create_decoder_inv_array(self):
|
||||
"""
|
||||
Add a column of INV gates for the decoder.
|
||||
"""
|
||||
|
||||
self.inv_inst = []
|
||||
for row in range(self.rows):
|
||||
name = "DEC_NAND[{0}]".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.nand_inst.append(self.add_inst(name=name,
|
||||
mod=nand_mod,
|
||||
offset=[self.internal_routing_width, y_off],
|
||||
mirror=mirror))
|
||||
name = self.INV_FORMAT.format(row)
|
||||
self.inv_inst.append(self.add_inst(name=name,
|
||||
mod=self.inv))
|
||||
self.connect_inst(args=["Z[{0}]".format(row),
|
||||
"decode[{0}]".format(row),
|
||||
"vdd", "gnd"])
|
||||
|
||||
|
||||
|
||||
def add_decoder_inv_array(self):
|
||||
"""Add a column of INV gates for the decoder above the predecoders
|
||||
and to the right of the NAND decoders."""
|
||||
def place_decoder_inv_array(self):
|
||||
"""
|
||||
Place the column of INV gates for the decoder above the predecoders
|
||||
and to the right of the NAND decoders.
|
||||
"""
|
||||
|
||||
z_pin = self.inv.get_pin("Z")
|
||||
|
||||
|
|
@ -364,9 +393,8 @@ class hierarchical_decoder(design.design):
|
|||
else:
|
||||
x_off = self.internal_routing_width + self.nand3.width
|
||||
|
||||
self.inv_inst = []
|
||||
for row in range(self.rows):
|
||||
name = "DEC_INV_[{0}]".format(row)
|
||||
name = self.INV_FORMAT.format(row)
|
||||
if (row % 2 == 0):
|
||||
inv_row_height = self.inv.height * row
|
||||
mirror = "R0"
|
||||
|
|
@ -377,17 +405,52 @@ class hierarchical_decoder(design.design):
|
|||
y_dir = -1
|
||||
y_off = inv_row_height
|
||||
offset = vector(x_off,y_off)
|
||||
|
||||
self.inv_inst.append(self.add_inst(name=name,
|
||||
mod=self.inv,
|
||||
self.place_inst(name=name,
|
||||
offset=offset,
|
||||
mirror=mirror))
|
||||
mirror=mirror)
|
||||
|
||||
def place_row_decoder(self):
|
||||
"""
|
||||
Place the row-decoder by placing NAND2/NAND3 and Inverters
|
||||
and add the primary decoder output pins.
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
# This will not check that the inst connections match.
|
||||
self.connect_inst(args=["Z[{0}]".format(row),
|
||||
"decode[{0}]".format(row),
|
||||
"vdd", "gnd"],
|
||||
check=False)
|
||||
|
||||
|
||||
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."""
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
self.connect_rails_to_predecodes()
|
||||
self.connect_rails_to_decoder()
|
||||
self.route_rails_to_predecodes()
|
||||
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 """
|
||||
|
||||
# FIXME: convert to connect_bus
|
||||
|
|
@ -438,7 +501,7 @@ class hierarchical_decoder(design.design):
|
|||
predecode_name = "predecode[{}]".format(pre_num * 4 + i)
|
||||
out_name = "out[{}]".format(i)
|
||||
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
|
||||
|
|
@ -447,11 +510,11 @@ class hierarchical_decoder(design.design):
|
|||
predecode_name = "predecode[{}]".format(pre_num * 8 + i + self.no_of_pre2x4 * 4)
|
||||
out_name = "out[{}]".format(i)
|
||||
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.
|
||||
Inputs of NAND2/NAND3 gates come from different groups.
|
||||
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]:
|
||||
# FIXME: convert to connect_bus?
|
||||
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)
|
||||
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
|
||||
|
||||
elif (self.num_inputs > 5):
|
||||
|
|
@ -476,11 +539,11 @@ class hierarchical_decoder(design.design):
|
|||
for index_C in self.predec_groups[2]:
|
||||
# FIXME: convert to connect_bus?
|
||||
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)
|
||||
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)
|
||||
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
|
||||
|
||||
def route_vdd_gnd(self):
|
||||
|
|
@ -516,7 +579,7 @@ class hierarchical_decoder(design.design):
|
|||
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 """
|
||||
rail_pos = vector(self.predecode_rails[rail_name].x,pin.lc().y)
|
||||
self.add_path("metal1", [rail_pos, pin.lc()])
|
||||
|
|
@ -525,7 +588,7 @@ class hierarchical_decoder(design.design):
|
|||
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 """
|
||||
# This routes the pin up to the rail, basically, to avoid conflicts.
|
||||
# It would be fixed with a channel router.
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class hierarchical_predecode(design.design):
|
|||
# Height width are computed
|
||||
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 """
|
||||
input_names = ["in[{}]".format(x) for x in range(self.number_of_inputs)]
|
||||
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)
|
||||
|
||||
|
||||
def add_input_inverters(self):
|
||||
def create_input_inverters(self):
|
||||
""" Create the input inverters to invert input signals for the decode stage. """
|
||||
|
||||
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):
|
||||
name = "Xpre_inv[{0}]".format(inv_num)
|
||||
if (inv_num % 2 == 0):
|
||||
|
|
@ -99,18 +110,26 @@ class hierarchical_predecode(design.design):
|
|||
y_off = (inv_num + 1) * (self.inv.height)
|
||||
mirror="MX"
|
||||
offset = vector(self.x_off_inv_1, y_off)
|
||||
self.in_inst.append(self.add_inst(name=name,
|
||||
mod=self.inv,
|
||||
self.place_inst(name=name,
|
||||
offset=offset,
|
||||
mirror=mirror))
|
||||
self.connect_inst(["in[{0}]".format(inv_num),
|
||||
"inbar[{0}]".format(inv_num),
|
||||
"vdd", "gnd"])
|
||||
mirror=mirror)
|
||||
|
||||
def add_output_inverters(self):
|
||||
def create_output_inverters(self):
|
||||
""" Create inverters for the inverted output decode signals. """
|
||||
|
||||
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):
|
||||
name = "Xpre_nand_inv[{}]".format(inv_num)
|
||||
if (inv_num % 2 == 0):
|
||||
|
|
@ -120,19 +139,23 @@ class hierarchical_predecode(design.design):
|
|||
y_off =(inv_num + 1)*self.inv.height
|
||||
mirror = "MX"
|
||||
offset = vector(self.x_off_inv_2, y_off)
|
||||
self.inv_inst.append(self.add_inst(name=name,
|
||||
mod=self.inv,
|
||||
self.place_inst(name=name,
|
||||
offset=offset,
|
||||
mirror=mirror))
|
||||
self.connect_inst(["Z[{}]".format(inv_num),
|
||||
"out[{}]".format(inv_num),
|
||||
"vdd", "gnd"])
|
||||
mirror=mirror)
|
||||
|
||||
|
||||
|
||||
def add_nand(self,connections):
|
||||
def create_nand_array(self,connections):
|
||||
""" Create the NAND stage for the decodes """
|
||||
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):
|
||||
inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs)
|
||||
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
|
||||
mirror = "MX"
|
||||
offset = vector(self.x_off_nand, y_off)
|
||||
self.nand_inst.append(self.add_inst(name=name,
|
||||
mod=self.nand,
|
||||
self.place_inst(name=name,
|
||||
offset=offset,
|
||||
mirror=mirror))
|
||||
self.connect_inst(connections[nand_input])
|
||||
mirror=mirror)
|
||||
|
||||
|
||||
def route(self):
|
||||
|
|
|
|||
|
|
@ -14,8 +14,17 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
|||
self.add_pins()
|
||||
self.create_modules()
|
||||
self.setup_constraints()
|
||||
self.create_netlist()
|
||||
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):
|
||||
""" 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
|
||||
4) a set of NAND gates for inversion
|
||||
"""
|
||||
self.create_rails()
|
||||
self.add_input_inverters()
|
||||
self.add_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.add_nand(connections)
|
||||
self.route_rails()
|
||||
self.place_input_inverters()
|
||||
self.place_output_inverters()
|
||||
self.place_nand_array()
|
||||
self.route()
|
||||
self.DRC_LVS()
|
||||
|
||||
def get_nand_input_line_combination(self):
|
||||
""" 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.create_modules()
|
||||
self.setup_constraints()
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
self.DRC_LVS()
|
||||
|
||||
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.create_rails()
|
||||
self.add_input_inverters()
|
||||
self.add_output_inverters()
|
||||
def create_netlist(self):
|
||||
self.create_input_inverters()
|
||||
self.create_output_inverters()
|
||||
connections=[["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"],
|
||||
["in[0]", "inbar[1]", "inbar[2]", "Z[1]", "vdd", "gnd"],
|
||||
["inbar[0]", "in[1]", "inbar[2]", "Z[2]", "vdd", "gnd"],
|
||||
|
|
@ -35,8 +28,22 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
|||
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
|
||||
["inbar[0]", "in[1]", "in[2]", "Z[6]", "vdd", "gnd"],
|
||||
["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"]]
|
||||
self.add_nand(connections)
|
||||
self.create_nand(connections)
|
||||
|
||||
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):
|
||||
""" These are the decoder connections of the NAND gates to the A,B,C pins """
|
||||
|
|
|
|||
Loading…
Reference in New Issue