mirror of https://github.com/VLSIDA/OpenRAM.git
First pass of multiple bitcells per decoder row
This commit is contained in:
parent
7888e54fc4
commit
2e67d44cd7
|
|
@ -32,11 +32,11 @@ class hierarchical_decoder(design.design):
|
|||
self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple
|
||||
except AttributeError:
|
||||
self.cell_multiple = 1
|
||||
# For debugging
|
||||
# self.cell_multiple = 2
|
||||
self.cell_height = self.cell_multiple * b.height
|
||||
|
||||
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.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.
|
||||
"""
|
||||
b = factory.create(module_type="bitcell")
|
||||
|
||||
# Old behavior
|
||||
if OPTS.netlist_only:
|
||||
return (b.height, 1)
|
||||
|
||||
# Search for the smallest multiple that works
|
||||
cell_multiple = 1
|
||||
|
|
@ -86,8 +90,8 @@ class hierarchical_decoder(design.design):
|
|||
self.setup_layout_constants()
|
||||
self.place_pre_decoder()
|
||||
self.place_row_decoder()
|
||||
self.route_input_rails()
|
||||
self.route_predecode_rails()
|
||||
self.route_inputs()
|
||||
self.route_decoder_bus()
|
||||
self.route_vdd_gnd()
|
||||
self.offset_all_coordinates()
|
||||
self.add_boundary()
|
||||
|
|
@ -141,7 +145,7 @@ class hierarchical_decoder(design.design):
|
|||
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.
|
||||
# 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
|
||||
# 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] ]
|
||||
|
|
@ -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
|
||||
|
||||
# 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
|
||||
if (self.num_inputs == 4 or self.num_inputs == 5):
|
||||
nand_width = self.and2.width
|
||||
else:
|
||||
nand_width = self.and3.width
|
||||
self.internal_routing_width = self.m2_pitch * self.total_number_of_predecoder_outputs
|
||||
self.row_decoder_height = self.inv.height * self.rows
|
||||
self.internal_routing_width = self.m2_pitch * (self.total_number_of_predecoder_outputs + 1)
|
||||
self.row_decoder_height = self.inv.height * self.num_rows
|
||||
|
||||
self.input_routing_width = (self.num_inputs + 1) * self.m2_pitch
|
||||
# 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.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):
|
||||
""" Create input rails for the predecoders """
|
||||
def route_inputs(self):
|
||||
""" Create input bus 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)
|
||||
min_x = min(min_x, self.pre2x4_inst[0].lx())
|
||||
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_bus_names = ["addr_{0}".format(i) for i in range(self.num_inputs)]
|
||||
self.input_rails = self.create_vertical_pin_bus(layer="m2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=input_offset,
|
||||
names=input_bus_names,
|
||||
length=input_height)
|
||||
self.input_bus = self.create_vertical_pin_bus(layer="m2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=input_offset,
|
||||
names=input_bus_names,
|
||||
length=input_height)
|
||||
|
||||
self.route_input_to_predecodes()
|
||||
|
||||
|
|
@ -222,7 +232,7 @@ class hierarchical_decoder(design.design):
|
|||
for i in range(2):
|
||||
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)
|
||||
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)
|
||||
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 i in range(3):
|
||||
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)
|
||||
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)
|
||||
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 """
|
||||
|
||||
self.add_via_center(layers=self.m2_stack,
|
||||
|
|
@ -334,18 +344,17 @@ class hierarchical_decoder(design.design):
|
|||
else:
|
||||
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):
|
||||
""" 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.pre3x8_inst[num].place(offset)
|
||||
self.pre3x8_inst[num].place(offset - vector(2 * self.m2_pitch, 0))
|
||||
|
||||
def create_row_decoder(self):
|
||||
""" 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):
|
||||
for i in range(len(self.predec_groups[0])):
|
||||
for j in range(len(self.predec_groups[1])):
|
||||
row = len(self.predec_groups[0]) * j + i
|
||||
if (row < self.num_outputs):
|
||||
name = self.AND_FORMAT.format(row)
|
||||
output = len(self.predec_groups[0]) * j + i
|
||||
if (output < self.num_outputs):
|
||||
name = self.AND_FORMAT.format(output)
|
||||
self.and_inst.append(self.add_inst(name=name,
|
||||
mod=self.and2))
|
||||
pins =["out_{0}".format(i),
|
||||
"out_{0}".format(j + len(self.predec_groups[0])),
|
||||
"decode_{0}".format(row),
|
||||
"decode_{0}".format(output),
|
||||
"vdd", "gnd"]
|
||||
self.connect_inst(pins)
|
||||
|
||||
|
|
@ -378,18 +387,18 @@ class hierarchical_decoder(design.design):
|
|||
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])):
|
||||
row = (len(self.predec_groups[0]) * len(self.predec_groups[1])) * k \
|
||||
+ len(self.predec_groups[0]) * j + i
|
||||
output = (len(self.predec_groups[0]) * len(self.predec_groups[1])) * k \
|
||||
+ len(self.predec_groups[0]) * j + i
|
||||
|
||||
if (row < self.num_outputs):
|
||||
name = self.AND_FORMAT.format(row)
|
||||
if (output < self.num_outputs):
|
||||
name = self.AND_FORMAT.format(output)
|
||||
self.and_inst.append(self.add_inst(name=name,
|
||||
mod=self.and3))
|
||||
|
||||
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])),
|
||||
"decode_{0}".format(row),
|
||||
"decode_{0}".format(output),
|
||||
"vdd", "gnd"]
|
||||
self.connect_inst(pins)
|
||||
|
||||
|
|
@ -403,7 +412,10 @@ class hierarchical_decoder(design.design):
|
|||
self.route_decoder()
|
||||
|
||||
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.
|
||||
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)
|
||||
|
||||
def place_and_array(self, and_mod):
|
||||
""" Add a column of AND gates for the decoder above the predecoders."""
|
||||
|
||||
for row in range(self.num_outputs):
|
||||
"""
|
||||
Add a column of AND gates for the decoder above the predecoders.
|
||||
"""
|
||||
|
||||
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):
|
||||
y_off = and_mod.height * row
|
||||
mirror = "R0"
|
||||
|
|
@ -425,46 +441,52 @@ class hierarchical_decoder(design.design):
|
|||
y_off = and_mod.height * (row + 1)
|
||||
mirror = "MX"
|
||||
|
||||
self.and_inst[row].place(offset=[self.internal_routing_width, y_off],
|
||||
mirror=mirror)
|
||||
x_off = self.internal_routing_width + dec * and_mod.width
|
||||
self.and_inst[inst_index].place(offset=vector(x_off, y_off),
|
||||
mirror=mirror)
|
||||
|
||||
def route_decoder(self):
|
||||
""" Add the pins. """
|
||||
|
||||
for row in range(self.num_outputs):
|
||||
z_pin = self.and_inst[row].get_pin("Z")
|
||||
self.add_layout_pin(text="decode_{0}".format(row),
|
||||
for output in range(self.num_outputs):
|
||||
z_pin = self.and_inst[output].get_pin("Z")
|
||||
self.add_layout_pin(text="decode_{0}".format(output),
|
||||
layer="m1",
|
||||
offset=z_pin.ll(),
|
||||
width=z_pin.width(),
|
||||
height=z_pin.height())
|
||||
|
||||
def route_predecode_rails(self):
|
||||
""" Creates vertical metal 2 rails to connect predecoder and decoder stages."""
|
||||
def route_decoder_bus(self):
|
||||
"""
|
||||
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.
|
||||
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)]
|
||||
self.predecode_rails = self.create_vertical_pin_bus(layer="m2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=input_offset,
|
||||
names=input_bus_names,
|
||||
length=self.height)
|
||||
self.predecode_bus = self.create_vertical_pin_bus(layer="m2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=vector(0, 0),
|
||||
names=input_bus_names,
|
||||
length=self.height)
|
||||
|
||||
self.route_rails_to_predecodes()
|
||||
self.route_rails_to_decoder()
|
||||
|
||||
def route_rails_to_predecodes(self):
|
||||
""" Iterates through all of the predecodes and connects to the rails including the offsets """
|
||||
self.route_bus_to_predecodes()
|
||||
self.route_bus_to_decoder()
|
||||
|
||||
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
|
||||
for pre_num in range(self.no_of_pre2x4):
|
||||
for i in range(4):
|
||||
predecode_name = "predecode_{}".format(pre_num * 4 + i)
|
||||
out_name = "out_{}".format(i)
|
||||
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
|
||||
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)
|
||||
out_name = "out_{}".format(i)
|
||||
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):
|
||||
""" 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]
|
||||
def route_bus_to_decoder(self):
|
||||
"""
|
||||
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):
|
||||
for index_B in self.predec_groups[1]:
|
||||
for index_A in self.predec_groups[0]:
|
||||
# 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)
|
||||
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)
|
||||
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("B"))
|
||||
row_index = row_index + 1
|
||||
self.route_predecode_bus_outputs(predecode_name,
|
||||
self.and_inst[output_index].get_pin("B"),
|
||||
row_offset + self.m1_pitch)
|
||||
output_index = output_index + 1
|
||||
|
||||
elif (self.num_inputs > 5):
|
||||
for index_C in self.predec_groups[2]:
|
||||
for index_B in self.predec_groups[1]:
|
||||
for index_A in self.predec_groups[0]:
|
||||
# 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)
|
||||
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)
|
||||
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)
|
||||
self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("C"))
|
||||
row_index = row_index + 1
|
||||
self.route_predecode_bus_outputs(predecode_name,
|
||||
self.and_inst[output_index].get_pin("C"),
|
||||
row_offset + 2 * self.m1_pitch)
|
||||
output_index = output_index + 1
|
||||
|
||||
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.
|
||||
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, "gnd")
|
||||
|
||||
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("m1", [rail_pos, pin.lc()])
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=rail_pos)
|
||||
def route_predecode_bus_outputs(self, rail_name, pin, y_offset):
|
||||
"""
|
||||
Connect the routing rail to the given metal1 pin
|
||||
using a routing track at the given y_offset
|
||||
|
||||
"""
|
||||
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):
|
||||
""" Connect the routing rail to the given metal1 pin """
|
||||
def route_predecode_bus_inputs(self, rail_name, pin, x_offset):
|
||||
"""
|
||||
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.
|
||||
# It would be fixed with a channel router.
|
||||
mid_point = vector(pin.cx(), pin.cy() + self.inv.height / 2)
|
||||
rail_pos = vector(self.predecode_rails[rail_name].x, mid_point.y)
|
||||
pin_pos = pin.center()
|
||||
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,
|
||||
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)
|
||||
|
||||
def input_load(self):
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ class pnand3(pgate.pgate):
|
|||
self.nmos3_inst,
|
||||
self.inputC_yoffset,
|
||||
"C",
|
||||
position="center")
|
||||
position="left")
|
||||
|
||||
# FIXME: constant hack
|
||||
if OPTS.tech_name == "s8":
|
||||
|
|
@ -232,7 +232,7 @@ class pnand3(pgate.pgate):
|
|||
self.nmos1_inst,
|
||||
self.inputA_yoffset,
|
||||
"A",
|
||||
position="center")
|
||||
position="left")
|
||||
|
||||
def route_output(self):
|
||||
""" Route the Z output """
|
||||
|
|
@ -255,10 +255,10 @@ class pnand3(pgate.pgate):
|
|||
directions=("V", "V"))
|
||||
|
||||
# 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)
|
||||
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
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
|
|
|
|||
|
|
@ -20,15 +20,6 @@ class hierarchical_decoder_test(openram_test):
|
|||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
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
|
||||
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
|
||||
|
|
|
|||
Loading…
Reference in New Issue