mirror of https://github.com/VLSIDA/OpenRAM.git
merge local with dev
This commit is contained in:
commit
ebb1a7bedb
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
class drc_error(Exception):
|
||||||
|
"""Exception raised for DRC errors.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
expression -- input expression in which the error occurred
|
||||||
|
message -- explanation of the error
|
||||||
|
"""
|
||||||
|
|
||||||
|
# def __init__(self, expression, message):
|
||||||
|
# self.expression = expression
|
||||||
|
# self.message = message
|
||||||
|
def __init__(self, message):
|
||||||
|
self.message = message
|
||||||
|
|
@ -45,11 +45,9 @@ class bank_select(design.design):
|
||||||
self.height = max([x.uy() for x in self.inv_inst]) + self.m1_width
|
self.height = max([x.uy() for x in self.inv_inst]) + self.m1_width
|
||||||
self.width = max([x.rx() for x in self.inv_inst])
|
self.width = max([x.rx() for x in self.inv_inst])
|
||||||
|
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
|
|
||||||
# Number of control lines in the bus
|
# Number of control lines in the bus
|
||||||
|
|
@ -75,9 +73,8 @@ class bank_select(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Create modules for later instantiation """
|
""" Create modules for later instantiation """
|
||||||
self.bitcell = factory.create(module_type="bitcell")
|
self.dff = factory.create(module_type="dff")
|
||||||
|
height = self.dff.height + drc("poly_to_active")
|
||||||
height = self.bitcell.height + drc("poly_to_active")
|
|
||||||
|
|
||||||
# 1x Inverter
|
# 1x Inverter
|
||||||
self.inv_sel = factory.create(module_type="pinv", height=height)
|
self.inv_sel = factory.create(module_type="pinv", height=height)
|
||||||
|
|
@ -98,14 +95,12 @@ class bank_select(design.design):
|
||||||
|
|
||||||
def calculate_module_offsets(self):
|
def calculate_module_offsets(self):
|
||||||
|
|
||||||
self.xoffset_nand = self.inv4x.width + 2*self.m2_pitch + drc("pwell_to_nwell")
|
self.xoffset_nand = self.inv4x.width + 3 * self.m2_pitch + drc("pwell_to_nwell")
|
||||||
self.xoffset_nor = self.inv4x.width + 2*self.m2_pitch + drc("pwell_to_nwell")
|
self.xoffset_nor = self.inv4x.width + 3 * self.m2_pitch + drc("pwell_to_nwell")
|
||||||
self.xoffset_bank_sel_inv = 0
|
self.xoffset_bank_sel_inv = 0
|
||||||
self.xoffset_inputs = 0
|
self.xoffset_inputs = 0
|
||||||
|
|
||||||
self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height
|
self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height
|
||||||
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
|
|
||||||
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
|
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
|
||||||
|
|
@ -201,7 +196,6 @@ class bank_select(design.design):
|
||||||
inv_inst.place(offset=[logic_inst.rx(), y_offset],
|
inv_inst.place(offset=[logic_inst.rx(), y_offset],
|
||||||
mirror=mirror)
|
mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
def route_instances(self):
|
def route_instances(self):
|
||||||
|
|
||||||
# bank_sel is vertical wire
|
# bank_sel is vertical wire
|
||||||
|
|
@ -234,7 +228,6 @@ class bank_select(design.design):
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=bank_sel_bar_pin.rc())
|
offset=bank_sel_bar_pin.rc())
|
||||||
|
|
||||||
|
|
||||||
for i in range(self.num_control_lines):
|
for i in range(self.num_control_lines):
|
||||||
|
|
||||||
logic_inst = self.logic_inst[i]
|
logic_inst = self.logic_inst[i]
|
||||||
|
|
@ -248,12 +241,13 @@ class bank_select(design.design):
|
||||||
xoffset_bank_signal = xoffset_bank_sel
|
xoffset_bank_signal = xoffset_bank_sel
|
||||||
|
|
||||||
# Connect the logic output to inverter input
|
# Connect the logic output to inverter input
|
||||||
pre = logic_inst.get_pin("Z").lc()
|
out_pin = logic_inst.get_pin("Z")
|
||||||
out_position = logic_inst.get_pin("Z").rc() + vector(0.5*self.m1_width,0)
|
out_pos = out_pin.rc()
|
||||||
in_position = inv_inst.get_pin("A").lc() + vector(0.5*self.m1_width,0)
|
in_pin = inv_inst.get_pin("A")
|
||||||
post = inv_inst.get_pin("A").rc()
|
in_pos = in_pin.lc()
|
||||||
self.add_path("m1", [pre, out_position, in_position, post])
|
mid1_pos = vector(0.5 * (out_pos.x + in_pos.x), out_pos.y)
|
||||||
|
mid2_pos = vector(0.5 * (out_pos.x + in_pos.x), in_pos.y)
|
||||||
|
self.add_path("m1", [out_pos, mid1_pos, mid2_pos, in_pos])
|
||||||
|
|
||||||
# Connect the logic B input to bank_sel / bank_sel_bar
|
# Connect the logic B input to bank_sel / bank_sel_bar
|
||||||
logic_pos = logic_inst.get_pin("B").lc() - vector(0.5 * contact.m1_via.height, 0)
|
logic_pos = logic_inst.get_pin("B").lc() - vector(0.5 * contact.m1_via.height, 0)
|
||||||
|
|
@ -263,7 +257,6 @@ class bank_select(design.design):
|
||||||
offset=logic_pos,
|
offset=logic_pos,
|
||||||
directions=("H", "H"))
|
directions=("H", "H"))
|
||||||
|
|
||||||
|
|
||||||
# Connect the logic A input to the input pin
|
# Connect the logic A input to the input pin
|
||||||
logic_pos = logic_inst.get_pin("A").lc()
|
logic_pos = logic_inst.get_pin("A").lc()
|
||||||
input_pos = vector(0, logic_pos.y)
|
input_pos = vector(0, logic_pos.y)
|
||||||
|
|
@ -286,7 +279,6 @@ class bank_select(design.design):
|
||||||
width=inv_inst.rx() - out_pin.lx(),
|
width=inv_inst.rx() - out_pin.lx(),
|
||||||
height=out_pin.height())
|
height=out_pin.height())
|
||||||
|
|
||||||
|
|
||||||
# Find the x offsets for where the vias/pins should be placed
|
# Find the x offsets for where the vias/pins should be placed
|
||||||
a_xoffset = self.logic_inst[0].lx()
|
a_xoffset = self.logic_inst[0].lx()
|
||||||
b_xoffset = self.inv_inst[0].lx()
|
b_xoffset = self.inv_inst[0].lx()
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,15 @@ import math
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
from errors import drc_error
|
||||||
|
from tech import cell_properties
|
||||||
|
|
||||||
|
|
||||||
class hierarchical_decoder(design.design):
|
class hierarchical_decoder(design.design):
|
||||||
"""
|
"""
|
||||||
Dynamically generated hierarchical decoder.
|
Dynamically generated hierarchical decoder.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, rows):
|
def __init__(self, name, num_outputs):
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
|
|
||||||
self.AND_FORMAT = "DEC_AND_{0}"
|
self.AND_FORMAT = "DEC_AND_{0}"
|
||||||
|
|
@ -25,9 +27,17 @@ class hierarchical_decoder(design.design):
|
||||||
self.pre2x4_inst = []
|
self.pre2x4_inst = []
|
||||||
self.pre3x8_inst = []
|
self.pre3x8_inst = []
|
||||||
|
|
||||||
(self.cell_height, self.cell_multiple) = self.find_decoder_height()
|
b = factory.create(module_type="bitcell")
|
||||||
self.rows = rows
|
try:
|
||||||
self.num_inputs = math.ceil(math.log(self.rows, 2))
|
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
|
||||||
|
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)
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
|
|
@ -35,20 +45,37 @@ class hierarchical_decoder(design.design):
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
def find_decoder_height(self):
|
def find_decoder_height(self):
|
||||||
|
"""
|
||||||
|
Dead code. This would dynamically determine the bitcell multiple,
|
||||||
|
but I just decided to hard code it in the tech file if it is not 1
|
||||||
|
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
|
# Old behavior
|
||||||
|
if OPTS.netlist_only:
|
||||||
return (b.height, 1)
|
return (b.height, 1)
|
||||||
|
|
||||||
# Search for the smallest multiple that works
|
# Search for the smallest multiple that works
|
||||||
cell_multiple = 1
|
cell_multiple = 1
|
||||||
while cell_multiple < 3:
|
while cell_multiple < 5:
|
||||||
cell_height = cell_multiple * b.height
|
cell_height = cell_multiple * b.height
|
||||||
|
# debug.info(2,"Trying mult = {0} height={1}".format(cell_multiple, cell_height))
|
||||||
|
try:
|
||||||
and3 = factory.create(module_type="pand3",
|
and3 = factory.create(module_type="pand3",
|
||||||
height=cell_height)
|
height=cell_height)
|
||||||
|
except drc_error:
|
||||||
|
# debug.info(1, "Incrementing decoder height by 1 bitcell height {}".format(b.height))
|
||||||
|
pass
|
||||||
|
else:
|
||||||
(drc_errors, lvs_errors) = and3.DRC_LVS(force_check=True)
|
(drc_errors, lvs_errors) = and3.DRC_LVS(force_check=True)
|
||||||
if drc_errors + lvs_errors == 0:
|
total_errors = drc_errors + lvs_errors
|
||||||
|
if total_errors == 0:
|
||||||
|
debug.info(1, "Decoder height is multiple of {} bitcells.".format(cell_multiple))
|
||||||
return (cell_height, cell_multiple)
|
return (cell_height, cell_multiple)
|
||||||
|
|
||||||
cell_multiple += 1
|
cell_multiple += 1
|
||||||
|
|
||||||
else:
|
else:
|
||||||
debug.error("Couldn't find a valid decoder height multiple.", -1)
|
debug.error("Couldn't find a valid decoder height multiple.", -1)
|
||||||
|
|
||||||
|
|
@ -63,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()
|
||||||
|
|
@ -118,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] ]
|
||||||
|
|
@ -157,35 +184,42 @@ 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
|
# Add extra pitch for good measure
|
||||||
|
self.height = max(self.predecoder_height, self.row_decoder_height) + self.m3_pitch
|
||||||
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,
|
||||||
|
|
@ -199,7 +233,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)
|
||||||
|
|
@ -209,13 +243,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)
|
||||||
|
|
@ -225,10 +259,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)
|
||||||
|
|
||||||
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,
|
||||||
offset=input_offset)
|
offset=input_offset)
|
||||||
|
|
@ -242,7 +279,7 @@ class hierarchical_decoder(design.design):
|
||||||
for i in range(self.num_inputs):
|
for i in range(self.num_inputs):
|
||||||
self.add_pin("addr_{0}".format(i), "INPUT")
|
self.add_pin("addr_{0}".format(i), "INPUT")
|
||||||
|
|
||||||
for j in range(self.rows):
|
for j in range(self.num_outputs):
|
||||||
self.add_pin("decode_{0}".format(j), "OUTPUT")
|
self.add_pin("decode_{0}".format(j), "OUTPUT")
|
||||||
self.add_pin("vdd", "POWER")
|
self.add_pin("vdd", "POWER")
|
||||||
self.add_pin("gnd", "GROUND")
|
self.add_pin("gnd", "GROUND")
|
||||||
|
|
@ -311,18 +348,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
|
||||||
|
|
@ -339,14 +375,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.rows):
|
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)
|
||||||
|
|
||||||
|
|
@ -355,18 +391,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.rows):
|
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)
|
||||||
|
|
||||||
|
|
@ -380,7 +416,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):
|
||||||
|
|
@ -392,9 +431,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.rows):
|
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"
|
||||||
|
|
@ -402,46 +445,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
|
||||||
|
self.and_inst[inst_index].place(offset=vector(x_off, y_off),
|
||||||
mirror=mirror)
|
mirror=mirror)
|
||||||
|
|
||||||
def route_decoder(self):
|
def route_decoder(self):
|
||||||
""" Add the pins. """
|
""" Add the pins. """
|
||||||
|
|
||||||
for row in range(self.rows):
|
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_predecodes_to_bus()
|
||||||
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_predecodes_to_bus(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):
|
||||||
|
|
@ -449,52 +498,82 @@ 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.rows):
|
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 + 1) * self.m3_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.m3_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.rows):
|
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 + 1) * self.m3_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.m3_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.m3_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 at the right of the cells.
|
||||||
|
xoffset = max(x.rx() for x in self.and_inst)
|
||||||
|
for num in range(0, self.num_outputs):
|
||||||
|
# Only add the power pin for the 1st in each row
|
||||||
|
if num % self.decoders_per_row:
|
||||||
|
continue
|
||||||
|
|
||||||
# The vias will be placed in the center and right of the cells, respectively.
|
|
||||||
xoffset = self.and_inst[0].rx()
|
|
||||||
for num in range(0, self.rows):
|
|
||||||
for pin_name in ["vdd", "gnd"]:
|
for pin_name in ["vdd", "gnd"]:
|
||||||
# The nand and inv are the same height rows...
|
# The nand and inv are the same height rows...
|
||||||
supply_pin = self.and_inst[num].get_pin(pin_name)
|
supply_pin = self.and_inst[num].get_pin(pin_name)
|
||||||
pin_pos = vector(xoffset, supply_pin.cy())
|
pin_pos = vector(xoffset, supply_pin.cy())
|
||||||
|
self.add_path("m1",
|
||||||
|
[supply_pin.lc(), vector(xoffset, supply_pin.cy())])
|
||||||
self.add_power_pin(name=pin_name,
|
self.add_power_pin(name=pin_name,
|
||||||
loc=pin_pos)
|
loc=pin_pos)
|
||||||
|
|
||||||
|
|
@ -503,23 +582,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
|
||||||
|
|
||||||
|
"""
|
||||||
|
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,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=rail_pos)
|
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):
|
||||||
|
|
|
||||||
|
|
@ -94,13 +94,10 @@ class port_address(design.design):
|
||||||
mid2 = decoder_out_pos.scale(0.5, 0) + driver_in_pos.scale(0.5, 1)
|
mid2 = decoder_out_pos.scale(0.5, 0) + driver_in_pos.scale(0.5, 1)
|
||||||
self.add_path("m1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
self.add_path("m1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
|
|
||||||
self.row_decoder = factory.create(module_type="decoder",
|
self.row_decoder = factory.create(module_type="decoder",
|
||||||
rows=self.num_rows)
|
num_outputs=self.num_rows)
|
||||||
self.add_mod(self.row_decoder)
|
self.add_mod(self.row_decoder)
|
||||||
|
|
||||||
self.wordline_driver = factory.create(module_type="wordline_driver",
|
self.wordline_driver = factory.create(module_type="wordline_driver",
|
||||||
|
|
@ -108,7 +105,6 @@ class port_address(design.design):
|
||||||
cols=self.num_cols)
|
cols=self.num_cols)
|
||||||
self.add_mod(self.wordline_driver)
|
self.add_mod(self.wordline_driver)
|
||||||
|
|
||||||
|
|
||||||
def create_row_decoder(self):
|
def create_row_decoder(self):
|
||||||
""" Create the hierarchical row decoder """
|
""" Create the hierarchical row decoder """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from globals import OPTS
|
||||||
from utils import round_to_grid
|
from utils import round_to_grid
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
from errors import drc_error
|
||||||
|
|
||||||
|
|
||||||
class pinv(pgate.pgate):
|
class pinv(pgate.pgate):
|
||||||
|
|
@ -108,11 +109,14 @@ class pinv(pgate.pgate):
|
||||||
# This is a poly-to-poly of a flipped cell
|
# This is a poly-to-poly of a flipped cell
|
||||||
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
||||||
self.poly_extend_active + self.poly_space)
|
self.poly_extend_active + self.poly_space)
|
||||||
total_height = tx_height + min_channel + 2 * self.top_bottom_space
|
|
||||||
|
|
||||||
debug.check(self.height > total_height,
|
total_height = tx_height + min_channel + 2 * self.top_bottom_space
|
||||||
"Cell height {0} too small for simple min height {1}.".format(self.height,
|
# debug.check(self.height > total_height,
|
||||||
total_height))
|
# "Cell height {0} too small for simple min height {1}.".format(self.height,
|
||||||
|
# total_height))
|
||||||
|
if total_height > self.height:
|
||||||
|
msg = "Cell height {0} too small for simple min height {1}.".format(self.height, total_height)
|
||||||
|
raise drc_error(msg)
|
||||||
|
|
||||||
# Determine the height left to the transistors to determine
|
# Determine the height left to the transistors to determine
|
||||||
# the number of fingers
|
# the number of fingers
|
||||||
|
|
@ -144,12 +148,16 @@ class pinv(pgate.pgate):
|
||||||
# with LVS property mismatch errors when fingers are not a grid
|
# with LVS property mismatch errors when fingers are not a grid
|
||||||
# length and get rounded in the offset geometry.
|
# length and get rounded in the offset geometry.
|
||||||
self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults)
|
self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults)
|
||||||
debug.check(self.nmos_width >= drc("minwidth_tx"),
|
# debug.check(self.nmos_width >= drc("minwidth_tx"),
|
||||||
"Cannot finger NMOS transistors to fit cell height.")
|
# "Cannot finger NMOS transistors to fit cell height.")
|
||||||
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
|
if self.nmos_width < drc("minwidth_tx"):
|
||||||
debug.check(self.pmos_width >= drc("minwidth_tx"),
|
raise drc_error("Cannot finger NMOS transistors to fit cell height.")
|
||||||
"Cannot finger PMOS transistors to fit cell height.")
|
|
||||||
|
|
||||||
|
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
|
||||||
|
#debug.check(self.pmos_width >= drc("minwidth_tx"),
|
||||||
|
# "Cannot finger PMOS transistors to fit cell height.")
|
||||||
|
if self.pmos_width < drc("minwidth_tx"):
|
||||||
|
raise drc_error("Cannot finger NMOS transistors to fit cell height.")
|
||||||
|
|
||||||
def add_ptx(self):
|
def add_ptx(self):
|
||||||
""" Create the PMOS and NMOS transistors. """
|
""" Create the PMOS and NMOS transistors. """
|
||||||
|
|
|
||||||
|
|
@ -178,8 +178,10 @@ class pnand2(pgate.pgate):
|
||||||
AFTER the wells are created
|
AFTER the wells are created
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.add_nwell_contact(self.pmos, self.pmos2_pos)
|
self.add_nwell_contact(self.pmos,
|
||||||
self.add_pwell_contact(self.nmos_nd, self.nmos2_pos)
|
self.pmos2_pos + vector(self.m1_pitch, 0))
|
||||||
|
self.add_pwell_contact(self.nmos_nd,
|
||||||
|
self.nmos2_pos + vector(self.m1_pitch, 0))
|
||||||
|
|
||||||
def connect_rails(self):
|
def connect_rails(self):
|
||||||
""" Connect the nmos and pmos to its respective power rails """
|
""" Connect the nmos and pmos to its respective power rails """
|
||||||
|
|
@ -197,7 +199,7 @@ class pnand2(pgate.pgate):
|
||||||
self.nmos2_inst,
|
self.nmos2_inst,
|
||||||
inputB_yoffset,
|
inputB_yoffset,
|
||||||
"B",
|
"B",
|
||||||
position="right")
|
position="center")
|
||||||
|
|
||||||
# This will help with the wells and the input/output placement
|
# This will help with the wells and the input/output placement
|
||||||
self.inputA_yoffset = self.pmos2_inst.by() - self.poly_extend_active \
|
self.inputA_yoffset = self.pmos2_inst.by() - self.poly_extend_active \
|
||||||
|
|
@ -209,6 +211,7 @@ class pnand2(pgate.pgate):
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
""" Route the Z output """
|
""" Route the Z output """
|
||||||
|
|
||||||
# PMOS1 drain
|
# PMOS1 drain
|
||||||
pmos_pin = self.pmos1_inst.get_pin("D")
|
pmos_pin = self.pmos1_inst.get_pin("D")
|
||||||
top_pin_offset = pmos_pin.center()
|
top_pin_offset = pmos_pin.center()
|
||||||
|
|
@ -217,28 +220,45 @@ class pnand2(pgate.pgate):
|
||||||
bottom_pin_offset = nmos_pin.center()
|
bottom_pin_offset = nmos_pin.center()
|
||||||
|
|
||||||
# Output pin
|
# Output pin
|
||||||
out_offset = vector(nmos_pin.center().x + self.m1_pitch,
|
c_pin = self.get_pin("B")
|
||||||
|
out_offset = vector(c_pin.cx() + self.m1_pitch,
|
||||||
self.inputA_yoffset)
|
self.inputA_yoffset)
|
||||||
|
|
||||||
# Midpoints of the L routes go horizontal first then vertical
|
# This routes on M2
|
||||||
mid1_offset = vector(out_offset.x, top_pin_offset.y)
|
# # Midpoints of the L routes go horizontal first then vertical
|
||||||
|
# mid1_offset = vector(out_offset.x, top_pin_offset.y)
|
||||||
|
# mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
|
||||||
|
|
||||||
|
# # Non-preferred active contacts
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# directions=("V", "H"),
|
||||||
|
# offset=pmos_pin.center())
|
||||||
|
# # Non-preferred active contacts
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# directions=("V", "H"),
|
||||||
|
# offset=nmos_pin.center())
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# offset=out_offset)
|
||||||
|
|
||||||
|
# # PMOS1 to mid-drain to NMOS2 drain
|
||||||
|
# self.add_path("m2",
|
||||||
|
# [top_pin_offset, mid1_offset, out_offset,
|
||||||
|
# mid2_offset, bottom_pin_offset])
|
||||||
|
|
||||||
|
# This routes on M1
|
||||||
|
# Midpoints of the L routes goes vertical first then horizontal
|
||||||
|
mid1_offset = vector(top_pin_offset.x, out_offset.y)
|
||||||
|
# Midpoints of the L routes goes horizontal first then vertical
|
||||||
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
|
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
|
||||||
|
|
||||||
# Non-preferred active contacts
|
self.add_path("m1",
|
||||||
self.add_via_center(layers=self.m1_stack,
|
[top_pin_offset, mid1_offset, out_offset])
|
||||||
directions=("V", "H"),
|
# Route in two segments to have the width rule
|
||||||
offset=pmos_pin.center())
|
self.add_path("m1",
|
||||||
# Non-preferred active contacts
|
[bottom_pin_offset, mid2_offset + vector(0.5 * self.m1_width, 0)],
|
||||||
self.add_via_center(layers=self.m1_stack,
|
width=nmos_pin.height())
|
||||||
directions=("V", "H"),
|
self.add_path("m1",
|
||||||
offset=nmos_pin.center())
|
[mid2_offset, out_offset])
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=out_offset)
|
|
||||||
|
|
||||||
# PMOS1 to mid-drain to NMOS2 drain
|
|
||||||
self.add_path("m2",
|
|
||||||
[top_pin_offset, mid1_offset, out_offset,
|
|
||||||
mid2_offset, bottom_pin_offset])
|
|
||||||
|
|
||||||
# This extends the output to the edge of the cell
|
# This extends the output to the edge of the cell
|
||||||
self.add_layout_pin_rect_center(text="Z",
|
self.add_layout_pin_rect_center(text="Z",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ from tech import drc, parameter, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
from globals import OPTS
|
||||||
|
|
||||||
|
|
||||||
class pnand3(pgate.pgate):
|
class pnand3(pgate.pgate):
|
||||||
|
|
@ -190,8 +191,10 @@ class pnand3(pgate.pgate):
|
||||||
def add_well_contacts(self):
|
def add_well_contacts(self):
|
||||||
""" Add n/p well taps to the layout and connect to supplies """
|
""" Add n/p well taps to the layout and connect to supplies """
|
||||||
|
|
||||||
self.add_nwell_contact(self.pmos, self.pmos3_pos)
|
self.add_nwell_contact(self.pmos,
|
||||||
self.add_pwell_contact(self.nmos_ns, self.nmos3_pos)
|
self.pmos3_pos + vector(self.m1_pitch, 0))
|
||||||
|
self.add_pwell_contact(self.nmos_ns,
|
||||||
|
self.nmos3_pos + vector(self.m1_pitch, 0))
|
||||||
|
|
||||||
def connect_rails(self):
|
def connect_rails(self):
|
||||||
""" Connect the nmos and pmos to its respective power rails """
|
""" Connect the nmos and pmos to its respective power rails """
|
||||||
|
|
@ -220,18 +223,22 @@ class pnand3(pgate.pgate):
|
||||||
self.nmos3_inst,
|
self.nmos3_inst,
|
||||||
self.inputC_yoffset,
|
self.inputC_yoffset,
|
||||||
"C",
|
"C",
|
||||||
position="center")
|
position="right")
|
||||||
|
|
||||||
# FIXME: constant hack
|
# FIXME: constant hack
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
self.inputA_yoffset = self.inputB_yoffset + 1.15 * m1_pitch
|
||||||
|
else:
|
||||||
self.inputA_yoffset = self.inputB_yoffset + 1.12 * m1_pitch
|
self.inputA_yoffset = self.inputB_yoffset + 1.12 * m1_pitch
|
||||||
self.route_input_gate(self.pmos1_inst,
|
self.route_input_gate(self.pmos1_inst,
|
||||||
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 """
|
||||||
|
|
||||||
# PMOS1 drain
|
# PMOS1 drain
|
||||||
pmos1_pin = self.pmos1_inst.get_pin("D")
|
pmos1_pin = self.pmos1_inst.get_pin("D")
|
||||||
# PMOS3 drain
|
# PMOS3 drain
|
||||||
|
|
@ -239,29 +246,56 @@ class pnand3(pgate.pgate):
|
||||||
# NMOS3 drain
|
# NMOS3 drain
|
||||||
nmos3_pin = self.nmos3_inst.get_pin("D")
|
nmos3_pin = self.nmos3_inst.get_pin("D")
|
||||||
|
|
||||||
# Go up to metal2 for ease on all output pins
|
# midpoint for routing
|
||||||
self.add_via_center(layers=self.m1_stack,
|
mid_offset = vector(nmos3_pin.cx() + self.m1_pitch,
|
||||||
offset=pmos1_pin.center(),
|
self.inputA_yoffset)
|
||||||
directions=("V", "V"))
|
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=pmos3_pin.center(),
|
|
||||||
directions=("V", "V"))
|
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=nmos3_pin.center(),
|
|
||||||
directions=("V", "V"))
|
|
||||||
|
|
||||||
# PMOS3 and NMOS3 are drain aligned
|
# Aligned with the well taps
|
||||||
self.add_path("m2", [pmos3_pin.center(), nmos3_pin.center()])
|
out_offset = vector(self.nwell_contact.cx(),
|
||||||
# Route in the A input track (top track)
|
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()])
|
# Go up to metal2 for ease on all output pins
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# offset=pmos1_pin.center(),
|
||||||
|
# directions=("V", "V"))
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# offset=pmos3_pin.center(),
|
||||||
|
# directions=("V", "V"))
|
||||||
|
# self.add_via_center(layers=self.m1_stack,
|
||||||
|
# offset=nmos3_pin.center(),
|
||||||
|
# directions=("V", "V"))
|
||||||
|
|
||||||
|
# # Route in the A input track (top track)
|
||||||
|
# mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset)
|
||||||
|
# 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,
|
||||||
offset=mid_offset)
|
# offset=mid_offset)
|
||||||
|
|
||||||
|
top_left_pin_offset = pmos1_pin.center()
|
||||||
|
top_right_pin_offset = pmos3_pin.center()
|
||||||
|
bottom_pin_offset = nmos3_pin.center()
|
||||||
|
|
||||||
|
# PMOS1 to output
|
||||||
|
self.add_path("m1", [top_left_pin_offset,
|
||||||
|
vector(top_left_pin_offset.x, out_offset.y),
|
||||||
|
out_offset])
|
||||||
|
# PMOS3 to output
|
||||||
|
self.add_path("m1", [top_right_pin_offset,
|
||||||
|
vector(top_right_pin_offset.x, mid_offset.y),
|
||||||
|
mid_offset])
|
||||||
|
# NMOS3 to output
|
||||||
|
mid2_offset = vector(mid_offset.x, bottom_pin_offset.y)
|
||||||
|
self.add_path("m1",
|
||||||
|
[bottom_pin_offset, mid2_offset],
|
||||||
|
width=nmos3_pin.height())
|
||||||
|
mid3_offset = vector(mid_offset.x, nmos3_pin.by())
|
||||||
|
self.add_path("m1", [mid3_offset, mid_offset])
|
||||||
|
|
||||||
self.add_layout_pin_rect_center(text="Z",
|
self.add_layout_pin_rect_center(text="Z",
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=mid_offset,
|
offset=out_offset,
|
||||||
width=contact.m1_via.first_layer_width,
|
width=contact.m1_via.first_layer_width,
|
||||||
height=contact.m1_via.first_layer_height)
|
height=contact.m1_via.first_layer_height)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,10 +107,7 @@ class ptx(design.design):
|
||||||
# be decided in the layout later.
|
# be decided in the layout later.
|
||||||
area_sd = 2.5 * self.poly_width * self.tx_width
|
area_sd = 2.5 * self.poly_width * self.tx_width
|
||||||
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
||||||
|
if OPTS.tech_name == "s8":
|
||||||
|
|
||||||
if OPTS.tech_name == None:
|
|
||||||
print("here {0}".format(self.name))
|
|
||||||
# s8 technology is in microns
|
# s8 technology is in microns
|
||||||
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
||||||
self.mults,
|
self.mults,
|
||||||
|
|
@ -499,14 +496,25 @@ class ptx(design.design):
|
||||||
well_type=self.well_type)
|
well_type=self.well_type)
|
||||||
|
|
||||||
if hasattr(self, "li_stack"):
|
if hasattr(self, "li_stack"):
|
||||||
self.add_via_center(layers=self.li_stack,
|
contact=self.add_via_center(layers=self.li_stack,
|
||||||
offset=pos)
|
offset=pos,
|
||||||
|
directions=("V", "V"))
|
||||||
|
|
||||||
|
# contact_area = contact.mod.second_layer_width * contact.mod.second_layer_height
|
||||||
|
# min_area = drc("minarea_m1")
|
||||||
|
# width = contact.mod.second_layer_width
|
||||||
|
# if contact_area < min_area:
|
||||||
|
# height = min_area / width
|
||||||
|
# else:
|
||||||
|
# height = contact.mod.second_layer_height
|
||||||
|
width = contact.mod.second_layer_width
|
||||||
|
height = contact.mod.second_layer_height
|
||||||
self.add_layout_pin_rect_center(text=label,
|
self.add_layout_pin_rect_center(text=label,
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=pos,
|
offset=pos,
|
||||||
width=contact.mod.second_layer_width,
|
width=width,
|
||||||
height=contact.mod.second_layer_height)
|
height=height)
|
||||||
|
|
||||||
return(contact)
|
return(contact)
|
||||||
|
|
||||||
def get_cin(self):
|
def get_cin(self):
|
||||||
|
|
|
||||||
|
|
@ -28,39 +28,39 @@ class hierarchical_decoder_test(openram_test):
|
||||||
|
|
||||||
factory.reset()
|
factory.reset()
|
||||||
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=16)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=16)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
factory.reset()
|
factory.reset()
|
||||||
debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=17)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=17)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
factory.reset()
|
factory.reset()
|
||||||
debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=23)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=23)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=32)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=32)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
factory.reset()
|
factory.reset()
|
||||||
debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=65)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=65)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=128)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=128)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
factory.reset()
|
factory.reset()
|
||||||
debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=341)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=341)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=512)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=512)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
|
||||||
|
|
@ -20,47 +20,38 @@ 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, rows=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", rows=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")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=16)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=16)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 17 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 17 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=17)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=17)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 23 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 23 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=23)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=23)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=32)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=32)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 65 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 65 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=65)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=65)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 128 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 128 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=128)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=128)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 341 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 341 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=341)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=341)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=512)
|
a = factory.create(module_type="hierarchical_decoder", num_outputs=512)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ class openram_back_end_test(openram_test):
|
||||||
self.assertEqual(len(re.findall('ERROR', output)), 0)
|
self.assertEqual(len(re.findall('ERROR', output)), 0)
|
||||||
self.assertEqual(len(re.findall('WARNING', output)), 0)
|
self.assertEqual(len(re.findall('WARNING', output)), 0)
|
||||||
|
|
||||||
|
|
||||||
# now clean up the directory
|
# now clean up the directory
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
if os.path.exists(out_path):
|
if os.path.exists(out_path):
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ class openram_front_end_test(openram_test):
|
||||||
self.assertEqual(len(re.findall('ERROR', output)), 0)
|
self.assertEqual(len(re.findall('ERROR', output)), 0)
|
||||||
self.assertEqual(len(re.findall('WARNING', output)), 0)
|
self.assertEqual(len(re.findall('WARNING', output)), 0)
|
||||||
|
|
||||||
|
|
||||||
# now clean up the directory
|
# now clean up the directory
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
if os.path.exists(out_path):
|
if os.path.exists(out_path):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue