First pass of multiple bitcells per decoder row

This commit is contained in:
mrg 2020-04-10 13:29:41 -07:00
parent 7888e54fc4
commit 2e67d44cd7
3 changed files with 159 additions and 103 deletions

View File

@ -32,11 +32,11 @@ class hierarchical_decoder(design.design):
self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple
except AttributeError: except AttributeError:
self.cell_multiple = 1 self.cell_multiple = 1
# For debugging
# self.cell_multiple = 2
self.cell_height = self.cell_multiple * b.height self.cell_height = self.cell_multiple * b.height
self.num_outputs = num_outputs self.num_outputs = num_outputs
# We may have more than one bitcell per decoder row
self.rows = math.ceil(num_outputs / self.cell_multiple)
self.num_inputs = math.ceil(math.log(self.num_outputs, 2)) self.num_inputs = math.ceil(math.log(self.num_outputs, 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)
@ -51,6 +51,10 @@ class hierarchical_decoder(design.design):
because a DRC tool would be required even to run in front-end mode. because a DRC tool would be required even to run in front-end mode.
""" """
b = factory.create(module_type="bitcell") b = factory.create(module_type="bitcell")
# Old behavior
if OPTS.netlist_only:
return (b.height, 1)
# Search for the smallest multiple that works # Search for the smallest multiple that works
cell_multiple = 1 cell_multiple = 1
@ -86,8 +90,8 @@ class hierarchical_decoder(design.design):
self.setup_layout_constants() self.setup_layout_constants()
self.place_pre_decoder() self.place_pre_decoder()
self.place_row_decoder() self.place_row_decoder()
self.route_input_rails() self.route_inputs()
self.route_predecode_rails() self.route_decoder_bus()
self.route_vdd_gnd() self.route_vdd_gnd()
self.offset_all_coordinates() self.offset_all_coordinates()
self.add_boundary() self.add_boundary()
@ -141,7 +145,7 @@ class hierarchical_decoder(design.design):
def setup_netlist_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 bus to different groups. One group belongs to one pre-decoder.
# For example, for two 2:4 pre-decoder and one 3:8 pre-decoder, we will # For example, for two 2:4 pre-decoder and one 3:8 pre-decoder, we will
# have total 16 output lines out of these 3 pre-decoders and they will # have total 16 output lines out of these 3 pre-decoders and they will
# be distributed as [ [0,1,2,3] ,[4,5,6,7], [8,9,10,11,12,13,14,15] ] # be distributed as [ [0,1,2,3] ,[4,5,6,7], [8,9,10,11,12,13,14,15] ]
@ -180,39 +184,45 @@ class hierarchical_decoder(design.design):
self.predecoder_height = self.pre2_4.height * self.no_of_pre2x4 + self.pre3_8.height * self.no_of_pre3x8 self.predecoder_height = self.pre2_4.height * self.no_of_pre2x4 + self.pre3_8.height * self.no_of_pre3x8
# We may have more than one bitcell per decoder row
self.num_rows = math.ceil(self.num_outputs / self.cell_multiple)
# We will place this many final decoders per row
self.decoders_per_row = math.ceil(self.num_outputs / self.num_rows)
# Calculates height and width of row-decoder # Calculates height and width of row-decoder
if (self.num_inputs == 4 or self.num_inputs == 5): if (self.num_inputs == 4 or self.num_inputs == 5):
nand_width = self.and2.width nand_width = self.and2.width
else: else:
nand_width = self.and3.width nand_width = self.and3.width
self.internal_routing_width = self.m2_pitch * self.total_number_of_predecoder_outputs self.internal_routing_width = self.m2_pitch * (self.total_number_of_predecoder_outputs + 1)
self.row_decoder_height = self.inv.height * self.rows self.row_decoder_height = self.inv.height * self.num_rows
self.input_routing_width = (self.num_inputs + 1) * self.m2_pitch self.input_routing_width = (self.num_inputs + 1) * self.m2_pitch
# Calculates height and width of hierarchical decoder # Calculates height and width of hierarchical decoder
self.height = self.row_decoder_height self.height = max(self.predecoder_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 \
+ self.decoders_per_row * nand_width + self.inv.width
def route_input_rails(self): def route_inputs(self):
""" Create input rails for the predecoders """ """ Create input bus for the predecoders """
# inputs should be as high as the decoders # 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 input_height = self.no_of_pre2x4 * self.pre2_4.height + self.no_of_pre3x8 * self.pre3_8.height
# Find the left-most predecoder # Find the left-most predecoder
min_x = 0 min_x = 0
if self.no_of_pre2x4 > 0: if self.no_of_pre2x4 > 0:
min_x = min(min_x, -self.pre2_4.width) min_x = min(min_x, self.pre2x4_inst[0].lx())
if self.no_of_pre3x8 > 0: if self.no_of_pre3x8 > 0:
min_x = min(min_x, -self.pre3_8.width) min_x = min(min_x, self.pre3x8_inst[0].lx())
input_offset=vector(min_x - self.input_routing_width, 0) input_offset=vector(min_x - self.input_routing_width, 0)
input_bus_names = ["addr_{0}".format(i) for i in range(self.num_inputs)] input_bus_names = ["addr_{0}".format(i) for i in range(self.num_inputs)]
self.input_rails = self.create_vertical_pin_bus(layer="m2", self.input_bus = self.create_vertical_pin_bus(layer="m2",
pitch=self.m2_pitch, pitch=self.m2_pitch,
offset=input_offset, offset=input_offset,
names=input_bus_names, names=input_bus_names,
length=input_height) length=input_height)
self.route_input_to_predecodes() self.route_input_to_predecodes()
@ -222,7 +232,7 @@ class hierarchical_decoder(design.design):
for i in range(2): for i in range(2):
index = pre_num * 2 + i index = pre_num * 2 + i
input_pos = self.input_rails["addr_{}".format(index)] input_pos = self.input_bus["addr_{}".format(index)]
in_name = "in_{}".format(i) in_name = "in_{}".format(i)
decoder_pin = self.pre2x4_inst[pre_num].get_pin(in_name) decoder_pin = self.pre2x4_inst[pre_num].get_pin(in_name)
@ -232,13 +242,13 @@ class hierarchical_decoder(design.design):
decoder_offset = decoder_pin.bc() + vector(0, (i + 1) * self.inv.height) decoder_offset = decoder_pin.bc() + vector(0, (i + 1) * self.inv.height)
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1) input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
self.route_input_rail(decoder_offset, input_offset) self.route_input_bus(decoder_offset, input_offset)
for pre_num in range(self.no_of_pre3x8): for pre_num in range(self.no_of_pre3x8):
for i in range(3): for i in range(3):
index = pre_num * 3 + i + self.no_of_pre2x4 * 2 index = pre_num * 3 + i + self.no_of_pre2x4 * 2
input_pos = self.input_rails["addr_{}".format(index)] input_pos = self.input_bus["addr_{}".format(index)]
in_name = "in_{}".format(i) in_name = "in_{}".format(i)
decoder_pin = self.pre3x8_inst[pre_num].get_pin(in_name) decoder_pin = self.pre3x8_inst[pre_num].get_pin(in_name)
@ -248,9 +258,9 @@ class hierarchical_decoder(design.design):
decoder_offset = decoder_pin.bc() + vector(0, (i + 1) * self.inv.height) decoder_offset = decoder_pin.bc() + vector(0, (i + 1) * self.inv.height)
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1) input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
self.route_input_rail(decoder_offset, input_offset) self.route_input_bus(decoder_offset, input_offset)
def route_input_rail(self, input_offset, output_offset): def route_input_bus(self, input_offset, output_offset):
""" Route a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """ """ Route a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """
self.add_via_center(layers=self.m2_stack, self.add_via_center(layers=self.m2_stack,
@ -334,18 +344,17 @@ class hierarchical_decoder(design.design):
else: else:
base= vector(-self.pre2_4.width, num * self.pre2_4.height) base= vector(-self.pre2_4.width, num * self.pre2_4.height)
self.pre2x4_inst[num].place(base) self.pre2x4_inst[num].place(base - vector(2 * self.m2_pitch, 0))
def place_pre3x8(self, num): def place_pre3x8(self, num):
""" Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """ """ Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """
if (self.num_inputs == 3): if (self.num_inputs == 3):
offset = vector(-self.pre_3_8.width, 0) offset = vector(-self.pre_3_8.width, 0)
mirror = "R0"
else: else:
height = self.no_of_pre2x4 * self.pre2_4.height + num * self.pre3_8.height height = self.no_of_pre2x4 * self.pre2_4.height + num * self.pre3_8.height
offset = vector(-self.pre3_8.width, height) offset = vector(-self.pre3_8.width, height)
self.pre3x8_inst[num].place(offset) self.pre3x8_inst[num].place(offset - vector(2 * self.m2_pitch, 0))
def create_row_decoder(self): def create_row_decoder(self):
""" Create the row-decoder by placing AND2/AND3 and Inverters """ Create the row-decoder by placing AND2/AND3 and Inverters
@ -362,14 +371,14 @@ class hierarchical_decoder(design.design):
if (self.num_inputs == 4 or self.num_inputs == 5): if (self.num_inputs == 4 or self.num_inputs == 5):
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[0]) * j + i output = len(self.predec_groups[0]) * j + i
if (row < self.num_outputs): if (output < self.num_outputs):
name = self.AND_FORMAT.format(row) name = self.AND_FORMAT.format(output)
self.and_inst.append(self.add_inst(name=name, self.and_inst.append(self.add_inst(name=name,
mod=self.and2)) mod=self.and2))
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])),
"decode_{0}".format(row), "decode_{0}".format(output),
"vdd", "gnd"] "vdd", "gnd"]
self.connect_inst(pins) self.connect_inst(pins)
@ -378,18 +387,18 @@ class hierarchical_decoder(design.design):
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])):
row = (len(self.predec_groups[0]) * len(self.predec_groups[1])) * k \ output = (len(self.predec_groups[0]) * len(self.predec_groups[1])) * k \
+ len(self.predec_groups[0]) * j + i + len(self.predec_groups[0]) * j + i
if (row < self.num_outputs): if (output < self.num_outputs):
name = self.AND_FORMAT.format(row) name = self.AND_FORMAT.format(output)
self.and_inst.append(self.add_inst(name=name, self.and_inst.append(self.add_inst(name=name,
mod=self.and3)) mod=self.and3))
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])),
"decode_{0}".format(row), "decode_{0}".format(output),
"vdd", "gnd"] "vdd", "gnd"]
self.connect_inst(pins) self.connect_inst(pins)
@ -403,7 +412,10 @@ class hierarchical_decoder(design.design):
self.route_decoder() self.route_decoder()
def place_decoder_and_array(self): def place_decoder_and_array(self):
""" Add a column of AND gates for final decode """ """
Add a column of AND gates for final decode.
This may have more than one decoder per row to match the bitcell height.
"""
# Row Decoder AND GATE array for address inputs <5. # Row Decoder AND 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):
@ -415,9 +427,13 @@ class hierarchical_decoder(design.design):
self.place_and_array(and_mod=self.and3) self.place_and_array(and_mod=self.and3)
def place_and_array(self, and_mod): def place_and_array(self, and_mod):
""" Add a column of AND gates for the decoder above the predecoders.""" """
Add a column of AND gates for the decoder above the predecoders.
for row in range(self.num_outputs): """
for inst_index in range(self.num_outputs):
row = math.floor(inst_index / self.decoders_per_row)
dec = inst_index % self.decoders_per_row
if ((row % 2) == 0): if ((row % 2) == 0):
y_off = and_mod.height * row y_off = and_mod.height * row
mirror = "R0" mirror = "R0"
@ -425,46 +441,52 @@ class hierarchical_decoder(design.design):
y_off = and_mod.height * (row + 1) y_off = and_mod.height * (row + 1)
mirror = "MX" mirror = "MX"
self.and_inst[row].place(offset=[self.internal_routing_width, y_off], x_off = self.internal_routing_width + dec * and_mod.width
mirror=mirror) self.and_inst[inst_index].place(offset=vector(x_off, y_off),
mirror=mirror)
def route_decoder(self): def route_decoder(self):
""" Add the pins. """ """ Add the pins. """
for row in range(self.num_outputs): for output in range(self.num_outputs):
z_pin = self.and_inst[row].get_pin("Z") z_pin = self.and_inst[output].get_pin("Z")
self.add_layout_pin(text="decode_{0}".format(row), self.add_layout_pin(text="decode_{0}".format(output),
layer="m1", layer="m1",
offset=z_pin.ll(), offset=z_pin.ll(),
width=z_pin.width(), width=z_pin.width(),
height=z_pin.height()) height=z_pin.height())
def route_predecode_rails(self): def route_decoder_bus(self):
""" Creates vertical metal 2 rails to connect predecoder and decoder stages.""" """
Creates vertical metal 2 bus 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.
if (self.num_inputs >= 4): if (self.num_inputs >= 4):
input_offset = vector(0.5 * self.m2_width, 0) # This leaves an offset for the predecoder output jogs
input_bus_names = ["predecode_{0}".format(i) for i in range(self.total_number_of_predecoder_outputs)] input_bus_names = ["predecode_{0}".format(i) for i in range(self.total_number_of_predecoder_outputs)]
self.predecode_rails = self.create_vertical_pin_bus(layer="m2", self.predecode_bus = self.create_vertical_pin_bus(layer="m2",
pitch=self.m2_pitch, pitch=self.m2_pitch,
offset=input_offset, offset=vector(0, 0),
names=input_bus_names, names=input_bus_names,
length=self.height) length=self.height)
self.route_rails_to_predecodes() self.route_bus_to_predecodes()
self.route_rails_to_decoder() self.route_bus_to_decoder()
def route_rails_to_predecodes(self):
""" Iterates through all of the predecodes and connects to the rails including the offsets """
def route_bus_to_predecodes(self):
"""
Iterates through all of the predecodes
and connects to the rails including the offsets
"""
# FIXME: convert to connect_bus # FIXME: convert to connect_bus
for pre_num in range(self.no_of_pre2x4): for pre_num in range(self.no_of_pre2x4):
for i in range(4): for i in range(4):
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.route_predecode_rail_m3(predecode_name, pin) x_offset = self.pre2x4_inst[pre_num].rx() + self.m2_pitch
self.route_predecode_bus_inputs(predecode_name, pin, x_offset)
# FIXME: convert to connect_bus # FIXME: convert to connect_bus
for pre_num in range(self.no_of_pre3x8): for pre_num in range(self.no_of_pre3x8):
@ -472,44 +494,68 @@ 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.route_predecode_rail_m3(predecode_name, pin) x_offset = self.pre3x8_inst[pre_num].rx() + self.m2_pitch
self.route_predecode_bus_inputs(predecode_name, pin, x_offset)
def route_rails_to_decoder(self): def route_bus_to_decoder(self):
""" Use the self.predec_groups to determine the connections to the decoder AND gates.
Inputs of AND2/AND3 gates come from different groups.
For example for these groups [ [0,1,2,3] ,[4,5,6,7],
[8,9,10,11,12,13,14,15] ] the first AND3 inputs are connected to
[0,4,8] and second AND3 is connected to [0,4,9] ........... and the
128th AND3 is connected to [3,7,15]
""" """
row_index = 0 Use the self.predec_groups to determine the connections to the decoder AND gates.
Inputs of AND2/AND3 gates come from different groups.
For example for these groups
[ [0,1,2,3] ,[4,5,6,7], [8,9,10,11,12,13,14,15] ]
the first AND3 inputs are connected to [0,4,8],
second AND3 is connected to [0,4,9],
...
and the 128th AND3 is connected to [3,7,15]
"""
output_index = 0
if (self.num_inputs == 4 or self.num_inputs == 5): if (self.num_inputs == 4 or self.num_inputs == 5):
for index_B in self.predec_groups[1]: for index_B in self.predec_groups[1]:
for index_A in self.predec_groups[0]: for index_A in self.predec_groups[0]:
# FIXME: convert to connect_bus? # FIXME: convert to connect_bus?
if (row_index < self.num_outputs): if (output_index < self.num_outputs):
row_index = math.floor(output_index / self.decoders_per_row)
row_remainder = (output_index % self.decoders_per_row)
row_offset = row_index * self.and_inst[0].height + (2 * row_remainder + 4) * self.m1_pitch
predecode_name = "predecode_{}".format(index_A) predecode_name = "predecode_{}".format(index_A)
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("A")) self.route_predecode_bus_outputs(predecode_name,
self.and_inst[output_index].get_pin("A"),
row_offset)
predecode_name = "predecode_{}".format(index_B) predecode_name = "predecode_{}".format(index_B)
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("B")) self.route_predecode_bus_outputs(predecode_name,
row_index = row_index + 1 self.and_inst[output_index].get_pin("B"),
row_offset + self.m1_pitch)
output_index = output_index + 1
elif (self.num_inputs > 5): elif (self.num_inputs > 5):
for index_C in self.predec_groups[2]: for index_C in self.predec_groups[2]:
for index_B in self.predec_groups[1]: for index_B in self.predec_groups[1]:
for index_A in self.predec_groups[0]: for index_A in self.predec_groups[0]:
# FIXME: convert to connect_bus? # FIXME: convert to connect_bus?
if (row_index < self.num_outputs): if (output_index < self.num_outputs):
row_index = math.floor(output_index / self.decoders_per_row)
row_remainder = (output_index % self.decoders_per_row)
row_offset = row_index * self.and_inst[0].height + (3 * row_remainder + 4) * self.m1_pitch
predecode_name = "predecode_{}".format(index_A) predecode_name = "predecode_{}".format(index_A)
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("A")) self.route_predecode_bus_outputs(predecode_name,
self.and_inst[output_index].get_pin("A"),
row_offset)
predecode_name = "predecode_{}".format(index_B) predecode_name = "predecode_{}".format(index_B)
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("B")) self.route_predecode_bus_outputs(predecode_name,
self.and_inst[output_index].get_pin("B"),
row_offset + self.m1_pitch)
predecode_name = "predecode_{}".format(index_C) predecode_name = "predecode_{}".format(index_C)
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("C")) self.route_predecode_bus_outputs(predecode_name,
row_index = row_index + 1 self.and_inst[output_index].get_pin("C"),
row_offset + 2 * self.m1_pitch)
output_index = output_index + 1
def route_vdd_gnd(self): def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """ """
Add a pin for each row of vdd/gnd which are
must-connects next level up.
"""
# The vias will be placed in the center and right of the cells, respectively. # The vias will be placed in the center and right of the cells, respectively.
xoffset = self.and_inst[0].rx() xoffset = self.and_inst[0].rx()
@ -526,23 +572,42 @@ class hierarchical_decoder(design.design):
self.copy_layout_pin(pre, "vdd") self.copy_layout_pin(pre, "vdd")
self.copy_layout_pin(pre, "gnd") self.copy_layout_pin(pre, "gnd")
def route_predecode_rail(self, rail_name, pin): def route_predecode_bus_outputs(self, rail_name, pin, y_offset):
""" Connect the routing rail to the given metal1 pin """ """
rail_pos = vector(self.predecode_rails[rail_name].x, pin.lc().y) Connect the routing rail to the given metal1 pin
self.add_path("m1", [rail_pos, pin.lc()]) using a routing track at the given y_offset
self.add_via_center(layers=self.m1_stack,
offset=rail_pos) """
pin_pos = pin.center()
# If we have a single decoder per row, we can route on M1
if self.decoders_per_row == 1:
rail_pos = vector(self.predecode_bus[rail_name].x, pin_pos.y)
self.add_path("m1", [rail_pos, pin_pos])
self.add_via_center(layers=self.m1_stack,
offset=rail_pos)
# If not, we must route over the decoder cells on M3
else:
rail_pos = vector(self.predecode_bus[rail_name].x, y_offset)
mid_pos = vector(pin_pos.x, rail_pos.y)
self.add_wire(self.m2_stack[::-1], [rail_pos, mid_pos, pin_pos])
self.add_via_center(layers=self.m2_stack,
offset=rail_pos)
self.add_via_center(layers=self.m1_stack,
offset=pin_pos)
def route_predecode_rail_m3(self, rail_name, pin): def route_predecode_bus_inputs(self, rail_name, pin, x_offset):
""" Connect the routing rail to the given metal1 pin """ """
Connect the routing rail to the given metal1 pin using a jog
to the right of the cell at the given x_offset.
"""
# 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.
mid_point = vector(pin.cx(), pin.cy() + self.inv.height / 2) pin_pos = pin.center()
rail_pos = vector(self.predecode_rails[rail_name].x, mid_point.y) mid_point1 = vector(x_offset, pin_pos.y)
mid_point2 = vector(x_offset, pin_pos.y + self.inv.height / 2)
rail_pos = vector(self.predecode_bus[rail_name].x, mid_point2.y)
self.add_wire(self.m1_stack, [pin_pos, mid_point1, mid_point2, rail_pos])
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
offset=pin.center())
self.add_wire(("m3", "via2", "m2"), [rail_pos, mid_point, pin.uc()])
self.add_via_center(layers=self.m2_stack,
offset=rail_pos) offset=rail_pos)
def input_load(self): def input_load(self):

View File

@ -221,7 +221,7 @@ class pnand3(pgate.pgate):
self.nmos3_inst, self.nmos3_inst,
self.inputC_yoffset, self.inputC_yoffset,
"C", "C",
position="center") position="left")
# FIXME: constant hack # FIXME: constant hack
if OPTS.tech_name == "s8": if OPTS.tech_name == "s8":
@ -232,7 +232,7 @@ class pnand3(pgate.pgate):
self.nmos1_inst, self.nmos1_inst,
self.inputA_yoffset, self.inputA_yoffset,
"A", "A",
position="center") position="left")
def route_output(self): def route_output(self):
""" Route the Z output """ """ Route the Z output """
@ -255,10 +255,10 @@ class pnand3(pgate.pgate):
directions=("V", "V")) directions=("V", "V"))
# PMOS3 and NMOS3 are drain aligned # PMOS3 and NMOS3 are drain aligned
self.add_path("m2", [pmos3_pin.center(), nmos3_pin.center()]) self.add_path("m1", [pmos3_pin.center(), nmos3_pin.center()])
# Route in the A input track (top track) # Route in the A input track (top track)
mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset) mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset)
self.add_path("m2", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()]) self.add_path("m1", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()])
# This extends the output to the edge of the cell # This extends the output to the edge of the cell
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,

View File

@ -20,15 +20,6 @@ class hierarchical_decoder_test(openram_test):
def runTest(self): def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
# Doesn't require hierarchical decoder
# debug.info(1, "Testing 4 row sample for hierarchical_decoder")
# a = hierarchical_decoder.hierarchical_decoder(name="hd1, num_outputs=4)
# self.local_check(a)
# Doesn't require hierarchical decoder
# debug.info(1, "Testing 8 row sample for hierarchical_decoder")
# a = hierarchical_decoder.hierarchical_decoder(name="hd2", num_outputs=8)
# self.local_check(a)
# check hierarchical decoder for single port # check hierarchical decoder for single port
debug.info(1, "Testing 16 row sample for hierarchical_decoder") debug.info(1, "Testing 16 row sample for hierarchical_decoder")