merge in dev

This commit is contained in:
jcirimel 2020-10-07 11:54:07 -07:00
commit 4a1a7e637e
43 changed files with 1135 additions and 156 deletions

View File

@ -37,6 +37,7 @@ class layout():
self.height = None self.height = None
self.bounding_box = None self.bounding_box = None
self.insts = [] # Holds module/cell layout instances self.insts = [] # Holds module/cell layout instances
self.inst_names = set() # Set of names to check for duplicates
self.objs = [] # Holds all other objects (labels, geometries, etc) self.objs = [] # Holds all other objects (labels, geometries, etc)
self.pin_map = {} # Holds name->pin_layout map for all pins self.pin_map = {} # Holds name->pin_layout map for all pins
self.visited = [] # List of modules we have already visited self.visited = [] # List of modules we have already visited
@ -214,9 +215,9 @@ class layout():
# Contacts are not really instances, so skip them # Contacts are not really instances, so skip them
if "contact" not in mod.name: if "contact" not in mod.name:
# Check that the instance name is unique # Check that the instance name is unique
for inst in self.insts: debug.check(name not in self.inst_names, "Duplicate named instance in {0}: {1}".format(self.name, name))
debug.check(name != inst.name, "Duplicate named instance in {0}: {1}".format(self.name, name))
self.inst_names.add(name)
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate)) self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
debug.info(3, "adding instance {}".format(self.insts[-1])) debug.info(3, "adding instance {}".format(self.insts[-1]))
# This is commented out for runtime reasons # This is commented out for runtime reasons

View File

@ -319,7 +319,7 @@ class stimuli():
# ngspice 27+ supports threading with "set num_threads=4" in the stimulus file or a .spiceinit # ngspice 27+ supports threading with "set num_threads=4" in the stimulus file or a .spiceinit
# Measurements can't be made with a raw file set in ngspice # Measurements can't be made with a raw file set in ngspice
# -r {2}timing.raw # -r {2}timing.raw
ng_cfg = open("{}.spinit".format(OPTS.openram_temp), "w") ng_cfg = open("{}.spiceinit".format(OPTS.openram_temp), "w")
ng_cfg.write("set num_threads={}\n".format(OPTS.num_threads)) ng_cfg.write("set num_threads={}\n".format(OPTS.num_threads))
ng_cfg.close() ng_cfg.close()

View File

@ -122,7 +122,7 @@ class and4_dec(design.design):
width=pin.width(), width=pin.width(),
height=pin.height()) height=pin.height())
for pin_name in ["A", "B", "C"]: for pin_name in ["A", "B", "C", "D"]:
pin = self.nand_inst.get_pin(pin_name) pin = self.nand_inst.get_pin(pin_name)
self.add_layout_pin_rect_center(text=pin_name, self.add_layout_pin_rect_center(text=pin_name,
layer=pin.layer, layer=pin.layer,

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 2048
write_size = 8
local_array_size = 32
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "freepdk45"
nominal_corners_only = True
route_supplies = False
check_lvsdrc = False
perimeter_pins = False
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 4096
write_size = 8
local_array_size = 32
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
route_supplies = False
check_lvsdrc = False
perimeter_pins = False
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,24 @@
word_size = 32
num_words = 256
write_size = 8
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
route_supplies = True
check_lvsdrc = True
perimeter_pins = True
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,24 @@
word_size = 32
num_words = 512
write_size = 8
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
route_supplies = True
check_lvsdrc = True
perimeter_pins = True
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 8192
write_size = 8
local_array_size = 32
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
route_supplies = False
check_lvsdrc = False
perimeter_pins = False
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,24 @@
word_size = 32
num_words = 1024
write_size = 8
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
route_supplies = True
check_lvsdrc = True
perimeter_pins = True
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 2048
write_size = 8
local_array_size = 32
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
route_supplies = False
check_lvsdrc = False
perimeter_pins = False
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 256
write_size = 8
local_array_size = 16
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "sky130"
nominal_corners_only = True
route_supplies = True
check_lvsdrc = True
perimeter_pins = True
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 512
write_size = 8
local_array_size = 16
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "sky130"
nominal_corners_only = True
route_supplies = True
check_lvsdrc = True
perimeter_pins = True
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 1024
write_size = 8
local_array_size = 16
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "sky130"
nominal_corners_only = True
route_supplies = True
check_lvsdrc = True
perimeter_pins = True
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -55,6 +55,11 @@ def parse_args():
action="store_false", action="store_false",
help="Disable all LVS/DRC checks", help="Disable all LVS/DRC checks",
dest="check_lvsdrc"), dest="check_lvsdrc"),
optparse.make_option("-j", "--threads",
action="store",
type="int",
help="Specify the number of threads (default: 2)",
dest="num_threads"),
optparse.make_option("-v", optparse.make_option("-v",
"--verbose", "--verbose",
action="count", action="count",

View File

@ -533,6 +533,9 @@ class bank(design.design):
elif self.col_addr_size == 3: elif self.col_addr_size == 3:
self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", self.column_decoder = factory.create(module_type="hierarchical_predecode3x8",
height=self.dff.height) height=self.dff.height)
elif self.col_addr_size == 4:
self.column_decoder = factory.create(module_type="hierarchical_predecode4x16",
height=self.dff.height)
else: else:
# No error checking before? # No error checking before?
debug.error("Invalid column decoder?", -1) debug.error("Invalid column decoder?", -1)

View File

@ -14,7 +14,7 @@ from globals import OPTS
from tech import cell_properties from tech import cell_properties
class single_level_column_mux_array(design.design): class column_mux_array(design.design):
""" """
Dynamically generated column mux array. Dynamically generated column mux array.
Array of column mux to read the bitlines through the 6T. Array of column mux to read the bitlines through the 6T.
@ -89,7 +89,7 @@ class single_level_column_mux_array(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
self.mux = factory.create(module_type="single_level_column_mux", self.mux = factory.create(module_type="column_mux",
bitcell_bl=self.bitcell_bl, bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br) bitcell_br=self.bitcell_br)
self.add_mod(self.mux) self.add_mod(self.mux)

View File

@ -24,13 +24,14 @@ class hierarchical_decoder(design.design):
self.pre2x4_inst = [] self.pre2x4_inst = []
self.pre3x8_inst = [] self.pre3x8_inst = []
self.pre4x16_inst = []
b = factory.create(module_type="bitcell") b = factory.create(module_type="bitcell")
self.cell_height = b.height self.cell_height = b.height
self.num_outputs = num_outputs self.num_outputs = num_outputs
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.no_of_pre4x16)=self.determine_predecodes(self.num_inputs)
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -86,25 +87,37 @@ class hierarchical_decoder(design.design):
height=self.cell_height) height=self.cell_height)
self.add_mod(self.pre3_8) self.add_mod(self.pre3_8)
self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16",
height=self.cell_height)
self.add_mod(self.pre4_16)
def determine_predecodes(self, num_inputs): def determine_predecodes(self, num_inputs):
""" Determines the number of 2:4 pre-decoder and 3:8 pre-decoder """
needed based on the number of inputs """ Determines the number of 2:4, 3:8 and 4:16 pre-decoders
needed based on the number of inputs
"""
if (num_inputs == 2): if (num_inputs == 2):
return (1, 0) return (1, 0, 0)
elif (num_inputs == 3): elif (num_inputs == 3):
return(0, 1) return(0, 1, 0)
elif (num_inputs == 4): elif (num_inputs == 4):
return(2, 0) return(2, 0, 0)
elif (num_inputs == 5): elif (num_inputs == 5):
return(1, 1) return(1, 1, 0)
elif (num_inputs == 6): elif (num_inputs == 6):
return(3, 0) return(3, 0, 0)
elif (num_inputs == 7): elif (num_inputs == 7):
return(2, 1) return(2, 1, 0)
elif (num_inputs == 8): elif (num_inputs == 8):
return(1, 2) return(1, 2, 0)
elif (num_inputs == 9): elif (num_inputs == 9):
return(0, 3) return(0, 3, 0)
elif (num_inputs == 10):
return(0, 2, 1)
elif (num_inputs == 11):
return(0, 1, 2)
elif (num_inputs == 12):
return(0, 0, 3)
else: else:
debug.error("Invalid number of inputs for hierarchical decoder", -1) debug.error("Invalid number of inputs for hierarchical decoder", -1)
@ -131,12 +144,19 @@ class hierarchical_decoder(design.design):
index = index + 1 index = index + 1
self.predec_groups.append(lines) self.predec_groups.append(lines)
for i in range(self.no_of_pre4x16):
lines = []
for j in range(16):
lines.append(index)
index = index + 1
self.predec_groups.append(lines)
def setup_layout_constants(self): def setup_layout_constants(self):
""" Calculate the overall dimensions of the hierarchical decoder """ """ Calculate the overall dimensions of the hierarchical decoder """
# If we have 4 or fewer rows, the predecoder is the decoder itself # If we have 4 or fewer rows, the predecoder is the decoder itself
if self.num_inputs>=4: if self.num_inputs>=4:
self.total_number_of_predecoder_outputs = 4 * self.no_of_pre2x4 + 8 * self.no_of_pre3x8 self.total_number_of_predecoder_outputs = 4 * self.no_of_pre2x4 + 8 * self.no_of_pre3x8 + 16 * self.no_of_pre4x16
else: else:
self.total_number_of_predecoder_outputs = 0 self.total_number_of_predecoder_outputs = 0
debug.error("Not enough rows ({}) for a hierarchical decoder. Non-hierarchical not supported yet.".format(self.num_inputs), debug.error("Not enough rows ({}) for a hierarchical decoder. Non-hierarchical not supported yet.".format(self.num_inputs),
@ -144,17 +164,20 @@ class hierarchical_decoder(design.design):
# Calculates height and width of pre-decoder, # Calculates height and width of pre-decoder,
# FIXME: Update with 4x16 # FIXME: Update with 4x16
if self.no_of_pre3x8 > 0 and self.no_of_pre2x4 > 0: self.predecoder_width = 0
self.predecoder_width = max(self.pre3_8.width, self.pre2_4.width) if self.no_of_pre2x4 > 0:
elif self.no_of_pre3x8 > 0: self.predecoder_width = max(self.predecoder_width, self.pre2_4.width)
self.predecoder_width = self.pre3_8.width if self.no_of_pre3x8 > 0:
else: self.predecoder_width = max(self.predecoder_width, self.pre3_8.width)
self.predecoder_width = self.pre2_4.width if self.no_of_pre4x16 > 0:
self.predecoder_width = max(self.predecoder_width, self.pre4_16.width)
# How much space between each predecoder # How much space between each predecoder
self.predecoder_spacing = 2 * self.and2.height self.predecoder_spacing = 2 * self.and2.height
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.no_of_pre2x4 + self.no_of_pre3x8 - 1) * self.predecoder_spacing + self.pre3_8.height * self.no_of_pre3x8 \
+ self.pre4_16.height * self.no_of_pre4x16 \
+ (self.no_of_pre2x4 + self.no_of_pre3x8 + self.no_of_pre4x16 - 1) * self.predecoder_spacing
# Inputs to cells are on input layer # Inputs to cells are on input layer
# Outputs from cells are on output layer # Outputs from cells are on output layer
@ -192,6 +215,8 @@ class hierarchical_decoder(design.design):
min_x = min(min_x, self.pre2x4_inst[0].lx()) 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.pre3x8_inst[0].lx()) min_x = min(min_x, self.pre3x8_inst[0].lx())
if self.no_of_pre4x16 > 0:
min_x = min(min_x, self.pre4x16_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)]
@ -232,6 +257,20 @@ class hierarchical_decoder(design.design):
self.route_input_bus(decoder_offset, input_offset) self.route_input_bus(decoder_offset, input_offset)
for pre_num in range(self.no_of_pre4x16):
for i in range(4):
index = pre_num * 4 + i + self.no_of_pre3x8 * 3 + self.no_of_pre2x4 * 2
input_pos = self.input_bus["addr_{}".format(index)].center()
in_name = "in_{}".format(i)
decoder_pin = self.pre4x16_inst[pre_num].get_pin(in_name)
decoder_offset = decoder_pin.center()
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
self.route_input_bus(decoder_offset, input_offset)
def route_input_bus(self, input_offset, output_offset): def route_input_bus(self, input_offset, output_offset):
""" """
Route a vertical M2 coordinate to another Route a vertical M2 coordinate to another
@ -267,6 +306,9 @@ class hierarchical_decoder(design.design):
for i in range(self.no_of_pre3x8): for i in range(self.no_of_pre3x8):
self.create_pre3x8(i) self.create_pre3x8(i)
for i in range(self.no_of_pre4x16):
self.create_pre4x16(i)
def create_pre2x4(self, num): def create_pre2x4(self, num):
""" Add a 2x4 predecoder to the left of the origin """ """ Add a 2x4 predecoder to the left of the origin """
@ -305,6 +347,24 @@ class hierarchical_decoder(design.design):
mod=self.pre3_8)) mod=self.pre3_8))
self.connect_inst(pins) self.connect_inst(pins)
def create_pre4x16(self, num):
""" Add 4x16 predecoder to the left of the origin and above any 3x8 decoders """
# If we had 2x4 predecodes, those are used as the lower
# decode output bits
in_index_offset = num * 4 + self.no_of_pre3x8 * 3 + self.no_of_pre2x4 * 2
out_index_offset = num * 16 + self.no_of_pre3x8 * 8 + self.no_of_pre2x4 * 4
pins = []
for input_index in range(4):
pins.append("addr_{0}".format(input_index + in_index_offset))
for output_index in range(16):
pins.append("out_{0}".format(output_index + out_index_offset))
pins.extend(["vdd", "gnd"])
self.pre4x16_inst.append(self.add_inst(name="pre4x16_{0}".format(num),
mod=self.pre4_16))
self.connect_inst(pins)
def place_pre_decoder(self): def place_pre_decoder(self):
""" Creates pre-decoder and places labels input address [A] """ """ Creates pre-decoder and places labels input address [A] """
@ -314,11 +374,16 @@ class hierarchical_decoder(design.design):
for i in range(self.no_of_pre3x8): for i in range(self.no_of_pre3x8):
self.place_pre3x8(i) self.place_pre3x8(i)
for i in range(self.no_of_pre4x16):
self.place_pre4x16(i)
self.predecode_height = 0 self.predecode_height = 0
if self.no_of_pre2x4 > 0: if self.no_of_pre2x4 > 0:
self.predecode_height = self.pre2x4_inst[-1].uy() self.predecode_height = self.pre2x4_inst[-1].uy()
if self.no_of_pre3x8 > 0: if self.no_of_pre3x8 > 0:
self.predecode_height = self.pre3x8_inst[-1].uy() self.predecode_height = self.pre3x8_inst[-1].uy()
if self.no_of_pre4x16 > 0:
self.predecode_height = self.pre4x16_inst[-1].uy()
def place_pre2x4(self, num): def place_pre2x4(self, num):
""" Place 2x4 predecoder to the left of the origin """ """ Place 2x4 predecoder to the left of the origin """
@ -333,6 +398,14 @@ class hierarchical_decoder(design.design):
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)
def place_pre4x16(self, num):
""" Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """
height = self.no_of_pre2x4 * (self.pre2_4.height + self.predecoder_spacing) \
+ self.no_of_pre3x8 * (self.pre3_8.height + self.predecoder_spacing) \
+ num * (self.pre4_16.height + self.predecoder_spacing)
offset = vector(-self.pre4_16.width, height)
self.pre4x16_inst[num].place(offset)
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
and add the primary decoder output pins. """ and add the primary decoder output pins. """
@ -468,7 +541,17 @@ class hierarchical_decoder(design.design):
x_offset = self.pre3x8_inst[pre_num].rx() + self.output_layer_pitch x_offset = self.pre3x8_inst[pre_num].rx() + self.output_layer_pitch
y_offset = self.pre3x8_inst[pre_num].by() + i * self.cell_height y_offset = self.pre3x8_inst[pre_num].by() + i * self.cell_height
self.route_predecode_bus_inputs(predecode_name, pin, x_offset, y_offset) self.route_predecode_bus_inputs(predecode_name, pin, x_offset, y_offset)
# FIXME: convert to connect_bus
for pre_num in range(self.no_of_pre4x16):
for i in range(16):
predecode_name = "predecode_{}".format(pre_num * 16 + i + self.no_of_pre3x8 * 8 + self.no_of_pre2x4 * 4)
out_name = "out_{}".format(i)
pin = self.pre4x16_inst[pre_num].get_pin(out_name)
x_offset = self.pre4x16_inst[pre_num].rx() + self.output_layer_pitch
y_offset = self.pre4x16_inst[pre_num].by() + i * self.cell_height
self.route_predecode_bus_inputs(predecode_name, pin, x_offset, y_offset)
def route_bus_to_decoder(self): def route_bus_to_decoder(self):
""" """
Use the self.predec_groups to determine the connections to the decoder AND gates. Use the self.predec_groups to determine the connections to the decoder AND gates.
@ -559,7 +642,7 @@ class hierarchical_decoder(design.design):
start_layer=supply_pin.layer) start_layer=supply_pin.layer)
# Copy the pins from the predecoders # Copy the pins from the predecoders
for pre in self.pre2x4_inst + self.pre3x8_inst: for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst:
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(pre, pin_name) self.copy_layout_pin(pre, pin_name)

View File

@ -45,7 +45,7 @@ class hierarchical_predecode(design.design):
def add_modules(self): def add_modules(self):
""" Add the INV and AND gate modules """ """ Add the INV and AND gate modules """
debug.check(self.number_of_inputs < 4, debug.check(self.number_of_inputs <= 4,
"Invalid number of predecode inputs: {}".format(self.number_of_inputs)) "Invalid number of predecode inputs: {}".format(self.number_of_inputs))
if self.column_decoder: if self.column_decoder:
@ -204,6 +204,7 @@ class hierarchical_predecode(design.design):
pin = top_and_gate.get_pin("D") pin = top_and_gate.get_pin("D")
else: else:
debug.error("Too many inputs for predecoder.", -1) debug.error("Too many inputs for predecoder.", -1)
y_offset = pin.cy() y_offset = pin.cy()
in_pin = "in_{}".format(num) in_pin = "in_{}".format(num)
a_pin = "A_{}".format(num) a_pin = "A_{}".format(num)
@ -288,10 +289,14 @@ class hierarchical_predecode(design.design):
if self.number_of_inputs == 2: if self.number_of_inputs == 2:
gate_lst = ["A", "B"] gate_lst = ["A", "B"]
else: elif self.number_of_inputs == 3:
gate_lst = ["A", "B", "C"] gate_lst = ["A", "B", "C"]
elif self.number_of_inputs == 4:
gate_lst = ["A", "B", "C", "D"]
else:
debug.error("Invalid number of nand inputs for decode", -1)
# this will connect pins A,B or A,B,C # this will connect pins A,B or A,B,C or A,B,C,D
for rail_pin, gate_pin in zip(index_lst, gate_lst): for rail_pin, gate_pin in zip(index_lst, gate_lst):
pin = self.and_inst[k].get_pin(gate_pin) pin = self.and_inst[k].get_pin(gate_pin)
pin_pos = pin.center() pin_pos = pin.center()

View File

@ -32,14 +32,14 @@ class hierarchical_predecode4x16(hierarchical_predecode):
["in_0", "inbar_1", "in_2", "inbar_3", "out_5", "vdd", "gnd"], ["in_0", "inbar_1", "in_2", "inbar_3", "out_5", "vdd", "gnd"],
["inbar_0", "in_1", "in_2", "inbar_3", "out_6", "vdd", "gnd"], ["inbar_0", "in_1", "in_2", "inbar_3", "out_6", "vdd", "gnd"],
["in_0", "in_1", "in_2", "inbar_3", "out_7", "vdd", "gnd"], ["in_0", "in_1", "in_2", "inbar_3", "out_7", "vdd", "gnd"],
["inbar_0", "inbar_1", "inbar_2", "in_3", "out_0", "vdd", "gnd"], ["inbar_0", "inbar_1", "inbar_2", "in_3", "out_8", "vdd", "gnd"],
["in_0", "inbar_1", "inbar_2", "in_3", "out_1", "vdd", "gnd"], ["in_0", "inbar_1", "inbar_2", "in_3", "out_9", "vdd", "gnd"],
["inbar_0", "in_1", "inbar_2", "in_3", "out_2", "vdd", "gnd"], ["inbar_0", "in_1", "inbar_2", "in_3", "out_10", "vdd", "gnd"],
["in_0", "in_1", "inbar_2", "in_3", "out_3", "vdd", "gnd"], ["in_0", "in_1", "inbar_2", "in_3", "out_11", "vdd", "gnd"],
["inbar_0", "inbar_1", "in_2", "in_3", "out_4", "vdd", "gnd"], ["inbar_0", "inbar_1", "in_2", "in_3", "out_12", "vdd", "gnd"],
["in_0", "inbar_1", "in_2", "in_3", "out_5", "vdd", "gnd"], ["in_0", "inbar_1", "in_2", "in_3", "out_13", "vdd", "gnd"],
["inbar_0", "in_1", "in_2", "in_3", "out_6", "vdd", "gnd"], ["inbar_0", "in_1", "in_2", "in_3", "out_14", "vdd", "gnd"],
["in_0", "in_1", "in_2", "in_3", "out_7", "vdd", "gnd"] ] ["in_0", "in_1", "in_2", "in_3", "out_15", "vdd", "gnd"] ]
self.create_and_array(connections) self.create_and_array(connections)

View File

@ -79,9 +79,12 @@ class port_address(design.design):
self.copy_power_pins(inst, "vdd") self.copy_power_pins(inst, "vdd")
self.copy_power_pins(inst, "gnd") self.copy_power_pins(inst, "gnd")
rbl_vdd_pin = self.rbl_driver_inst.get_pin("vdd") for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"):
self.add_power_pin("vdd", rbl_vdd_pin.lc()) if OPTS.tech_name == "sky130":
self.add_power_pin("vdd", rbl_vdd_pin.center())
else:
self.add_power_pin("vdd", rbl_vdd_pin.lc())
def route_pins(self): def route_pins(self):
for row in range(self.addr_size): for row in range(self.addr_size):
decoder_name = "addr_{}".format(row) decoder_name = "addr_{}".format(row)

View File

@ -290,8 +290,10 @@ class replica_column(bitcell_base_array):
bitcell_pins = [] bitcell_pins = []
for port in self.all_ports: for port in self.all_ports:
bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))])
bitcell_pins.append("vdd") if len(self.edge_cell.get_pins("vdd")) > 0:
bitcell_pins.append("gnd") bitcell_pins.append("vdd")
if len(self.edge_cell.get_pins("gnd")) > 0:
bitcell_pins.append("gnd")
return bitcell_pins return bitcell_pins

View File

@ -9,6 +9,7 @@ import optparse
import getpass import getpass
import os import os
class options(optparse.Values): class options(optparse.Values):
""" """
Class for holding all of the OpenRAM options. All Class for holding all of the OpenRAM options. All
@ -146,7 +147,7 @@ class options(optparse.Values):
bitcell_array = "bitcell_array" bitcell_array = "bitcell_array"
bitcell = "bitcell" bitcell = "bitcell"
buf_dec = "pbuf" buf_dec = "pbuf"
column_mux_array = "single_level_column_mux_array" column_mux_array = "column_mux_array"
control_logic = "control_logic" control_logic = "control_logic"
decoder = "hierarchical_decoder" decoder = "hierarchical_decoder"
delay_chain = "delay_chain" delay_chain = "delay_chain"
@ -155,7 +156,7 @@ class options(optparse.Values):
inv_dec = "pinv" inv_dec = "pinv"
nand2_dec = "pnand2" nand2_dec = "pnand2"
nand3_dec = "pnand3" nand3_dec = "pnand3"
nand4_dec = "pnand4" # Not available right now nand4_dec = "pnand4"
precharge_array = "precharge_array" precharge_array = "precharge_array"
ptx = "ptx" ptx = "ptx"
replica_bitline = "replica_bitline" replica_bitline = "replica_bitline"

View File

@ -10,14 +10,13 @@ import debug
from tech import drc, layer from tech import drc, layer
from vector import vector from vector import vector
from sram_factory import factory from sram_factory import factory
import logical_effort
from globals import OPTS from globals import OPTS
class single_level_column_mux(pgate.pgate): class column_mux(pgate.pgate):
""" """
This module implements the columnmux bitline cell used in the design. This module implements the columnmux bitline cell used in the design.
Creates a single columnmux cell with the given integer size relative Creates a single column mux cell with the given integer size relative
to minimum size. Default is 8x. Per Samira and Hodges-Jackson book: to minimum size. Default is 8x. Per Samira and Hodges-Jackson book:
Column-mux transistors driven by the decoder must be sized Column-mux transistors driven by the decoder must be sized
for optimal speed for optimal speed

165
compiler/pgates/pand4.py Normal file
View File

@ -0,0 +1,165 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
from vector import vector
import pgate
from sram_factory import factory
class pand4(pgate.pgate):
"""
This is a simple buffer used for driving loads.
"""
def __init__(self, name, size=1, height=None, vertical=False, add_wells=True):
debug.info(1, "Creating pand4 {}".format(name))
self.add_comment("size: {}".format(size))
self.vertical = vertical
self.size = size
# Creates the netlist and layout
super().__init__(name, height, add_wells)
def create_netlist(self):
self.add_pins()
self.create_modules()
self.create_insts()
def create_modules(self):
# Shield the cap, but have at least a stage effort of 4
self.nand = factory.create(module_type="pnand4",
height=self.height,
add_wells=self.vertical)
# Add the well tap to the inverter because when stacked
# vertically it is sometimes narrower
self.inv = factory.create(module_type="pdriver",
size_list=[self.size],
height=self.height,
add_wells=self.add_wells)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self):
if self.vertical:
self.height = 2 * self.nand.height
self.width = max(self.nand.width, self.inv.width)
else:
self.width = self.nand.width + self.inv.width
self.place_insts()
self.add_wires()
self.add_layout_pins()
self.route_supply_rails()
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
self.add_pin("A", "INPUT")
self.add_pin("B", "INPUT")
self.add_pin("C", "INPUT")
self.add_pin("D", "INPUT")
self.add_pin("Z", "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def create_insts(self):
self.nand_inst = self.add_inst(name="pand4_nand",
mod=self.nand)
self.connect_inst(["A", "B", "C", "D", "zb_int", "vdd", "gnd"])
self.inv_inst = self.add_inst(name="pand4_inv",
mod=self.inv)
self.connect_inst(["zb_int", "Z", "vdd", "gnd"])
def place_insts(self):
# Add NAND to the right
self.nand_inst.place(offset=vector(0, 0))
if self.vertical:
# Add INV above
self.inv_inst.place(offset=vector(self.inv.width,
2 * self.nand.height),
mirror="XY")
else:
# Add INV to the right
self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0))
def route_supply_rails(self):
""" Add vdd/gnd rails to the top, (middle), and bottom. """
self.add_layout_pin_rect_center(text="gnd",
layer=self.route_layer,
offset=vector(0.5 * self.width, 0),
width=self.width)
# Second gnd of the inverter gate
if self.vertical:
self.add_layout_pin_rect_center(text="gnd",
layer=self.route_layer,
offset=vector(0.5 * self.width, self.height),
width=self.width)
if self.vertical:
# Shared between two gates
y_offset = 0.5 * self.height
else:
y_offset = self.height
self.add_layout_pin_rect_center(text="vdd",
layer=self.route_layer,
offset=vector(0.5 * self.width, y_offset),
width=self.width)
def add_wires(self):
# nand Z to inv A
z1_pin = self.nand_inst.get_pin("Z")
a2_pin = self.inv_inst.get_pin("A")
if self.vertical:
route_layer = "m2"
self.add_via_stack_center(offset=z1_pin.center(),
from_layer=z1_pin.layer,
to_layer=route_layer)
self.add_zjog(route_layer,
z1_pin.uc(),
a2_pin.bc(),
"V")
self.add_via_stack_center(offset=a2_pin.center(),
from_layer=a2_pin.layer,
to_layer=route_layer)
else:
route_layer = self.route_layer
mid1_point = vector(z1_pin.cx(), a2_pin.cy())
self.add_path(route_layer,
[z1_pin.center(), mid1_point, a2_pin.center()])
def add_layout_pins(self):
pin = self.inv_inst.get_pin("Z")
self.add_layout_pin_rect_center(text="Z",
layer=pin.layer,
offset=pin.center(),
width=pin.width(),
height=pin.height())
for pin_name in ["A", "B", "C", "D"]:
pin = self.nand_inst.get_pin(pin_name)
self.add_layout_pin_rect_center(text=pin_name,
layer=pin.layer,
offset=pin.center(),
width=pin.width(),
height=pin.height())
def analytical_delay(self, corner, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
nand_delay = self.nand.analytical_delay(corner,
slew=slew,
load=self.inv.input_load())
inv_delay = self.inv.analytical_delay(corner,
slew=nand_delay.slew,
load=load)
return nand_delay + inv_delay

View File

@ -133,7 +133,6 @@ class pnand3(pgate.pgate):
# This is the extra space needed to ensure DRC rules # This is the extra space needed to ensure DRC rules
# to the active contacts # to the active contacts
nmos = factory.create(module_type="ptx", tx_type="nmos") nmos = factory.create(module_type="ptx", tx_type="nmos")
extra_contact_space = max(-nmos.get_pin("D").by(), 0)
def create_ptx(self): def create_ptx(self):
""" """

371
compiler/pgates/pnand4.py Normal file
View File

@ -0,0 +1,371 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import pgate
import debug
from tech import drc, parameter, spice
from vector import vector
import logical_effort
from sram_factory import factory
from globals import OPTS
import contact
class pnand4(pgate.pgate):
"""
This module generates gds of a parametrically sized 4-input nand.
This model use ptx to generate a 4-input nand within a cetrain height.
"""
def __init__(self, name, size=1, height=None, add_wells=True):
""" Creates a cell for a simple 3 input nand """
debug.info(2,
"creating pnand4 structure {0} with size of {1}".format(name,
size))
self.add_comment("size: {}".format(size))
# We have trouble pitch matching a 3x sizes to the bitcell...
# If we relax this, we could size this better.
self.size = size
self.nmos_size = 2 * size
self.pmos_size = parameter["beta"] * size
self.nmos_width = self.nmos_size * drc("minwidth_tx")
self.pmos_width = self.pmos_size * drc("minwidth_tx")
# FIXME: Allow these to be sized
debug.check(size == 1,
"Size 1 pnand4 is only supported now.")
self.tx_mults = 1
if OPTS.tech_name == "sky130":
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
# Creates the netlist and layout
super().__init__(name, height, add_wells)
def add_pins(self):
""" Adds pins for spice netlist """
pin_list = ["A", "B", "C", "D", "Z", "vdd", "gnd"]
dir_list = ["INPUT", "INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
self.add_pin_list(pin_list, dir_list)
def create_netlist(self):
self.add_pins()
self.add_ptx()
self.create_ptx()
def create_layout(self):
""" Calls all functions related to the generation of the layout """
self.setup_layout_constants()
self.place_ptx()
if self.add_wells:
self.add_well_contacts()
self.route_inputs()
self.route_output()
self.determine_width()
self.route_supply_rails()
self.connect_rails()
self.extend_wells()
self.add_boundary()
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos_center = factory.create(module_type="ptx",
width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
add_source_contact="active",
add_drain_contact="active")
self.add_mod(self.nmos_center)
self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
add_source_contact="active",
add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.nmos_left = factory.create(module_type="ptx",
width=self.nmos_width,
mults=self.tx_mults,
tx_type="nmos",
add_source_contact=self.route_layer,
add_drain_contact="active")
self.add_mod(self.nmos_left)
self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_left)
self.pmos_center = factory.create(module_type="ptx",
width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_center)
self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width,
mults=self.tx_mults,
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """
# Compute the overlap of the source and drain pins
self.ptx_offset = self.pmos_left.get_pin("D").center() - self.pmos_left.get_pin("S").center()
# This is the extra space needed to ensure DRC rules
# to the active contacts
nmos = factory.create(module_type="ptx", tx_type="nmos")
def create_ptx(self):
"""
Create the PMOS and NMOS in the netlist.
"""
self.pmos1_inst = self.add_inst(name="pnand4_pmos1",
mod=self.pmos_left)
self.connect_inst(["vdd", "A", "Z", "vdd"])
self.pmos2_inst = self.add_inst(name="pnand4_pmos2",
mod=self.pmos_center)
self.connect_inst(["Z", "B", "vdd", "vdd"])
self.pmos3_inst = self.add_inst(name="pnand4_pmos3",
mod=self.pmos_center)
self.connect_inst(["Z", "C", "vdd", "vdd"])
self.pmos4_inst = self.add_inst(name="pnand4_pmos4",
mod=self.pmos_right)
self.connect_inst(["Z", "D", "vdd", "vdd"])
self.nmos1_inst = self.add_inst(name="pnand4_nmos1",
mod=self.nmos_left)
self.connect_inst(["Z", "D", "net1", "gnd"])
self.nmos2_inst = self.add_inst(name="pnand4_nmos2",
mod=self.nmos_center)
self.connect_inst(["net1", "C", "net2", "gnd"])
self.nmos3_inst = self.add_inst(name="pnand4_nmos3",
mod=self.nmos_center)
self.connect_inst(["net2", "B", "net3", "gnd"])
self.nmos4_inst = self.add_inst(name="pnand4_nmos4",
mod=self.nmos_right)
self.connect_inst(["net3", "A", "gnd", "gnd"])
def place_ptx(self):
"""
Place the PMOS and NMOS in the layout at the upper-most
and lowest position to provide maximum routing in channel
"""
pmos1_pos = vector(self.pmos_left.active_offset.x,
self.height - self.pmos_left.active_height - self.top_bottom_space)
self.pmos1_inst.place(pmos1_pos)
pmos2_pos = pmos1_pos + self.ptx_offset
self.pmos2_inst.place(pmos2_pos)
pmos3_pos = pmos2_pos + self.ptx_offset
self.pmos3_inst.place(pmos3_pos)
self.pmos4_pos = pmos3_pos + self.ptx_offset
self.pmos4_inst.place(self.pmos4_pos)
nmos1_pos = vector(self.pmos_left.active_offset.x,
self.top_bottom_space)
self.nmos1_inst.place(nmos1_pos)
nmos2_pos = nmos1_pos + self.ptx_offset
self.nmos2_inst.place(nmos2_pos)
nmos3_pos = nmos2_pos + self.ptx_offset
self.nmos3_inst.place(nmos3_pos)
self.nmos4_pos = nmos3_pos + self.ptx_offset
self.nmos4_inst.place(self.nmos4_pos)
def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """
self.add_nwell_contact(self.pmos_right,
self.pmos4_pos + vector(self.m1_pitch, 0))
self.add_pwell_contact(self.nmos_right,
self.nmos4_pos + vector(self.m1_pitch, 0))
def connect_rails(self):
""" Connect the nmos and pmos to its respective power rails """
self.connect_pin_to_rail(self.nmos1_inst, "S", "gnd")
self.connect_pin_to_rail(self.pmos1_inst, "S", "vdd")
self.connect_pin_to_rail(self.pmos2_inst, "D", "vdd")
self.connect_pin_to_rail(self.pmos4_inst, "D", "vdd")
def route_inputs(self):
""" Route the A and B and C inputs """
# We can use this pitch because the contacts and overlap won't be adjacent
pmos_drain_bottom = self.pmos1_inst.get_pin("D").by()
self.output_yoffset = pmos_drain_bottom - 0.5 * self.route_layer_width - self.route_layer_space
bottom_pin = self.nmos1_inst.get_pin("D")
# active contact metal to poly contact metal spacing
active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * contact.poly_contact.second_layer_height
# active diffusion to poly contact spacing
# doesn't use nmos uy because that is calculated using offset + poly height
active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width
self.inputA_yoffset = max(active_contact_to_poly_contact,
active_to_poly_contact,
active_to_poly_contact2)
apin = self.route_input_gate(self.pmos1_inst,
self.nmos1_inst,
self.inputA_yoffset,
"A",
position="left")
self.inputB_yoffset = self.inputA_yoffset + self.m1_pitch
bpin = self.route_input_gate(self.pmos2_inst,
self.nmos2_inst,
self.inputB_yoffset,
"B",
position="center")
self.inputC_yoffset = self.inputB_yoffset + self.m1_pitch
cpin = self.route_input_gate(self.pmos3_inst,
self.nmos3_inst,
self.inputC_yoffset,
"C",
position="right")
self.inputD_yoffset = self.inputC_yoffset + self.m1_pitch
dpin = self.route_input_gate(self.pmos4_inst,
self.nmos4_inst,
self.inputD_yoffset,
"D",
position="right")
if OPTS.tech_name == "sky130":
self.add_enclosure([apin, bpin, cpin, dpin], "npc", drc("npc_enclose_poly"))
def route_output(self):
""" Route the Z output """
# PMOS1 drain
pmos1_pin = self.pmos1_inst.get_pin("D")
# PMOS3 drain
pmos3_pin = self.pmos3_inst.get_pin("D")
# NMOS3 drain
nmos4_pin = self.nmos4_inst.get_pin("D")
out_offset = vector(nmos4_pin.cx() + self.route_layer_pitch,
self.output_yoffset)
# 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
# self.add_via_center(layers=self.m1_stack,
# offset=mid_offset)
top_left_pin_offset = pmos1_pin.center()
top_right_pin_offset = pmos3_pin.center()
bottom_pin_offset = nmos4_pin.center()
# PMOS1 to output
self.add_path(self.route_layer, [top_left_pin_offset,
vector(top_left_pin_offset.x, out_offset.y),
out_offset])
# PMOS4 to output
self.add_path(self.route_layer, [top_right_pin_offset,
vector(top_right_pin_offset.x, out_offset.y),
out_offset])
# NMOS4 to output
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
self.add_path(self.route_layer,
[bottom_pin_offset, mid2_offset],
width=nmos4_pin.height())
mid3_offset = vector(out_offset.x, nmos4_pin.by())
self.add_path(self.route_layer, [mid3_offset, out_offset])
self.add_layout_pin_rect_center(text="Z",
layer=self.route_layer,
offset=out_offset)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["nand4_leakage"]
total_power = self.return_power(power_dyn, power_leak)
return total_power
def calculate_effective_capacitance(self, load):
"""Computes effective capacitance. Results in fF"""
c_load = load
# In fF
c_para = spice["min_tx_drain_c"] * (self.nmos_size / parameter["min_tx_size"])
transition_prob = 0.1094
return transition_prob * (c_load + c_para)
def input_load(self):
"""Return the relative input capacitance of a single input"""
return self.nmos_size + self.pmos_size
def get_stage_effort(self, cout, inp_is_rise=True):
"""
Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall.
Input inverted by this stage.
"""
parasitic_delay = 3
return logical_effort.logical_effort(self.name,
self.size,
self.input_load(),
cout,
parasitic_delay,
not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets):
"""
Adds edges based on inputs/outputs.
Overrides base class function.
"""
self.add_graph_edges(graph, port_nets)

View File

@ -79,13 +79,6 @@ class sram():
""" Save all the output files while reporting time to do it as well. """ """ Save all the output files while reporting time to do it as well. """
if not OPTS.netlist_only: if not OPTS.netlist_only:
# Create a LEF physical model
start_time = datetime.datetime.now()
lefname = OPTS.output_path + self.s.name + ".lef"
debug.print_raw("LEF: Writing to {0}".format(lefname))
self.lef_write(lefname)
print_time("LEF", datetime.datetime.now(), start_time)
# Write the layout # Write the layout
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
gdsname = OPTS.output_path + self.s.name + ".gds" gdsname = OPTS.output_path + self.s.name + ".gds"
@ -93,6 +86,13 @@ class sram():
self.gds_write(gdsname) self.gds_write(gdsname)
print_time("GDS", datetime.datetime.now(), start_time) print_time("GDS", datetime.datetime.now(), start_time)
# Create a LEF physical model
start_time = datetime.datetime.now()
lefname = OPTS.output_path + self.s.name + ".lef"
debug.print_raw("LEF: Writing to {0}".format(lefname))
self.lef_write(lefname)
print_time("LEF", datetime.datetime.now(), start_time)
# Save the spice file # Save the spice file
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp" spname = OPTS.output_path + self.s.name + ".sp"

View File

@ -6,15 +6,15 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from math import log,sqrt,ceil from math import log, sqrt, ceil
from importlib import reload
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
class sram_config: class sram_config:
""" This is a structure that is used to hold the SRAM configuration options. """ """ This is a structure that is used to hold the SRAM configuration options. """
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0): def __init__(self, word_size, num_words, write_size=None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0):
self.word_size = word_size self.word_size = word_size
self.num_words = num_words self.num_words = num_words
self.write_size = write_size self.write_size = write_size
@ -25,7 +25,7 @@ class sram_config:
# This will get over-written when we determine the organization # This will get over-written when we determine the organization
self.words_per_row = words_per_row self.words_per_row = words_per_row
self.compute_sizes() self.compute_sizes()
def set_local_config(self, module): def set_local_config(self, module):
""" Copy all of the member variables to the given module for convenience """ """ Copy all of the member variables to the given module for convenience """
@ -34,31 +34,31 @@ class sram_config:
# Copy all the variables to the local module # Copy all the variables to the local module
for member in members: for member in members:
setattr(module,member,getattr(self,member)) setattr(module, member, getattr(self, member))
def compute_sizes(self): def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square.""" """ Computes the organization of the memory using bitcell size by trying to make it square."""
bitcell = factory.create(module_type="bitcell") bitcell = factory.create(module_type="bitcell")
debug.check(self.num_banks in [1, 2, 4],
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") "Valid number of banks are 1 , 2 and 4.")
self.num_words_per_bank = self.num_words/self.num_banks self.num_words_per_bank = self.num_words / self.num_banks
self.num_bits_per_bank = self.word_size*self.num_words_per_bank self.num_bits_per_bank = self.word_size * self.num_words_per_bank
# If this was hard coded, don't dynamically compute it! # If this was hard coded, don't dynamically compute it!
if not self.words_per_row: if not self.words_per_row:
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
self.bank_area = bitcell.width*bitcell.height*self.num_bits_per_bank self.bank_area = bitcell.width * bitcell.height * self.num_bits_per_bank
self.bank_side_length = sqrt(self.bank_area) self.bank_side_length = sqrt(self.bank_area)
# Estimate the words per row given the height of the bitcell and the square side length # Estimate the words per row given the height of the bitcell and the square side length
self.tentative_num_cols = int(self.bank_side_length/bitcell.width) self.tentative_num_cols = int(self.bank_side_length / bitcell.width)
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size) self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
# Estimate the number of rows given the tentative words per row # Estimate the number of rows given the tentative words per row
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size) self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row * self.word_size)
self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
self.recompute_sizes() self.recompute_sizes()
@ -70,57 +70,57 @@ class sram_config:
SRAM for testing. SRAM for testing.
""" """
debug.info(1,"Recomputing with words per row: {}".format(self.words_per_row)) debug.info(1, "Recomputing with words per row: {}".format(self.words_per_row))
# If the banks changed # If the banks changed
self.num_words_per_bank = self.num_words/self.num_banks self.num_words_per_bank = self.num_words / self.num_banks
self.num_bits_per_bank = self.word_size*self.num_words_per_bank self.num_bits_per_bank = self.word_size * self.num_words_per_bank
# Fix the number of columns and rows # Fix the number of columns and rows
self.num_cols = int(self.words_per_row*self.word_size) self.num_cols = int(self.words_per_row * self.word_size)
self.num_rows_temp = int(self.num_words_per_bank/self.words_per_row) self.num_rows_temp = int(self.num_words_per_bank / self.words_per_row)
self.num_rows = self.num_rows_temp + self.num_spare_rows self.num_rows = self.num_rows_temp + self.num_spare_rows
debug.info(1,"Rows: {} Cols: {}".format(self.num_rows_temp,self.num_cols)) debug.info(1, "Rows: {} Cols: {}".format(self.num_rows_temp, self.num_cols))
# Compute the address and bank sizes # Compute the address and bank sizes
self.row_addr_size = ceil(log(self.num_rows, 2)) self.row_addr_size = ceil(log(self.num_rows, 2))
self.col_addr_size = int(log(self.words_per_row, 2)) self.col_addr_size = int(log(self.words_per_row, 2))
self.bank_addr_size = self.col_addr_size + self.row_addr_size self.bank_addr_size = self.col_addr_size + self.row_addr_size
self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2)) self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
debug.info(1,"Row addr size: {}".format(self.row_addr_size) debug.info(1, "Row addr size: {}".format(self.row_addr_size)
+ " Col addr size: {}".format(self.col_addr_size) + " Col addr size: {}".format(self.col_addr_size)
+ " Bank addr size: {}".format(self.bank_addr_size)) + " Bank addr size: {}".format(self.bank_addr_size))
def estimate_words_per_row(self, tentative_num_cols, word_size):
def estimate_words_per_row(self,tentative_num_cols, word_size):
""" """
This provides a heuristic rounded estimate for the number of words This provides a heuristic rounded estimate for the number of words
per row. per row.
""" """
tentative_column_ways = tentative_num_cols / word_size
column_mux_sizes = [1, 2, 4, 8, 16]
# If we are double, we may want a larger column mux
if tentative_column_ways > 2 * column_mux_sizes[-1]:
debug.warning("Extremely large number of columns for 16-way maximum column mux.")
if tentative_num_cols < 1.5*word_size: closest_way = min(column_mux_sizes, key=lambda x: abs(x - tentative_column_ways))
return 1
elif tentative_num_cols < 3*word_size:
return 2
elif tentative_num_cols < 6*word_size:
return 4
else:
if tentative_num_cols > 16*word_size:
debug.warning("Reaching column mux size limit. Consider increasing above 8-way.")
return 8
def amend_words_per_row(self,tentative_num_rows, words_per_row): return closest_way
def amend_words_per_row(self, tentative_num_rows, words_per_row):
""" """
This picks the number of words per row more accurately by limiting This picks the number of words per row more accurately by limiting
it to a minimum and maximum. it to a minimum and maximum.
""" """
# Recompute the words per row given a hard max # Recompute the words per row given a hard max
if(not OPTS.is_unit_test and tentative_num_rows > 512): if(not OPTS.is_unit_test and tentative_num_rows > 512):
debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048") debug.check(tentative_num_rows * words_per_row <= 4096,
return int(words_per_row*tentative_num_rows/512) "Number of words exceeds 2048")
return int(words_per_row * tentative_num_rows / 512)
# Recompute the words per row given a hard min # Recompute the words per row given a hard min
if(not OPTS.is_unit_test and tentative_num_rows < 16): if (not OPTS.is_unit_test and tentative_num_rows < 16):
debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows)) debug.check(tentative_num_rows * words_per_row >= 16,
return int(words_per_row*tentative_num_rows/16) "Minimum number of rows is 16, but given {0}".format(tentative_num_rows))
return int(words_per_row * tentative_num_rows / 16)
return words_per_row return words_per_row

View File

@ -8,7 +8,7 @@
# #
import unittest import unittest
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
@unittest.skip("SKIPPING 04_and4_dec_test") # @unittest.skip("SKIPPING 04_and4_dec_test")
class and4_dec_test(openram_test): class and4_dec_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -8,7 +8,7 @@
# #
import unittest import unittest
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
class single_level_column_mux_1rw_1r_test(openram_test): class column_mux_1rw_1r_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"))
@ -28,11 +28,11 @@ class single_level_column_mux_1rw_1r_test(openram_test):
globals.setup_bitcell() globals.setup_bitcell()
debug.info(2, "Checking column mux port 0") debug.info(2, "Checking column mux port 0")
tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") tx = factory.create(module_type="column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx) self.local_check(tx)
debug.info(2, "Checking column mux port 1") debug.info(2, "Checking column mux port 1")
tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl1", bitcell_br="br1") tx = factory.create(module_type="column_mux", tx_size=8, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -8,16 +8,15 @@
# #
import unittest import unittest
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
#@unittest.skip("SKIPPING 04_driver_test")
class single_level_column_mux_pbitcell_test(openram_test): class column_mux_pbitcell_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"))
@ -31,12 +30,12 @@ class single_level_column_mux_pbitcell_test(openram_test):
factory.reset() factory.reset()
debug.info(2, "Checking column mux for pbitcell (innermost connections)") debug.info(2, "Checking column mux for pbitcell (innermost connections)")
tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") tx = factory.create(module_type="column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx) self.local_check(tx)
factory.reset() factory.reset()
debug.info(2, "Checking column mux for pbitcell (outermost connections)") debug.info(2, "Checking column mux for pbitcell (outermost connections)")
tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2") tx = factory.create(module_type="column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -8,7 +8,7 @@
# #
import unittest import unittest
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
class single_level_column_mux_test(openram_test): class column_mux_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"))
@ -24,7 +24,7 @@ class single_level_column_mux_test(openram_test):
# check single level column mux in single port # check single level column mux in single port
debug.info(2, "Checking column mux") debug.info(2, "Checking column mux")
tx = factory.create(module_type="single_level_column_mux", tx_size=8) tx = factory.create(module_type="column_mux", tx_size=8)
self.local_check(tx) self.local_check(tx)
globals.end_openram() globals.end_openram()

View File

@ -8,13 +8,13 @@
# #
import unittest import unittest
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
from sram_factory import factory
import debug import debug
class pand2_test(openram_test): class pand2_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -8,13 +8,13 @@
# #
import unittest import unittest
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
from sram_factory import factory
import debug import debug
class pand3_test(openram_test): class pand3_test(openram_test):
def runTest(self): def runTest(self):

39
compiler/tests/04_pand4_test.py Executable file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
class pand4_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
global verify
import verify
import pand4
debug.info(2, "Testing pand4 gate 4x")
a = pand4.pand4(name="pand4x4", size=4)
self.local_check(a)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class pnand4_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Checking 4-input nand gate")
tx = factory.create(module_type="pnand4", size=1)
self.local_check(tx)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -8,33 +8,40 @@
# #
import unittest import unittest
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class hierarchical_decoder_test(openram_test): 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)
# Use the 2 port cell since it is usually bigger/easier
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
# Checks 2x4 and 2-input NAND decoder # Checks 2x4 and 2-input NAND decoder
#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", num_outputs=16) a = factory.create(module_type="hierarchical_decoder", num_outputs=16)
#self.local_check(a) self.local_check(a)
# Checks 2x4 and 2-input NAND decoder with non-power-of-two # Checks 2x4 and 2-input NAND decoder with non-power-of-two
#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", num_outputs=17) a = factory.create(module_type="hierarchical_decoder", num_outputs=17)
#self.local_check(a) self.local_check(a)
# Checks 2x4 with 3x8 and 2-input NAND decoder # Checks 2x4 with 3x8 and 2-input NAND decoder
#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", num_outputs=32) a = factory.create(module_type="hierarchical_decoder", num_outputs=32)
#self.local_check(a) self.local_check(a)
# Checks 3 x 2x4 and 3-input NAND decoder # Checks 3 x 2x4 and 3-input NAND decoder
debug.info(1, "Testing 64 row sample for hierarchical_decoder") debug.info(1, "Testing 64 row sample for hierarchical_decoder")
@ -42,18 +49,20 @@ class hierarchical_decoder_test(openram_test):
self.local_check(a) self.local_check(a)
# Checks 2x4 and 2 x 3x8 and 3-input NAND with non-power-of-two # Checks 2x4 and 2 x 3x8 and 3-input NAND with non-power-of-two
#debug.info(1, "Testing 132 row sample for hierarchical_decoder") debug.info(1, "Testing 132 row sample for hierarchical_decoder")
#a = factory.create(module_type="hierarchical_decoder", num_outputs=132) a = factory.create(module_type="hierarchical_decoder", num_outputs=132)
#self.local_check(a)
# Checks 3 x 3x8 and 3-input NAND decoder
#debug.info(1, "Testing 512 row sample for hierarchical_decoder")
#a = factory.create(module_type="hierarchical_decoder", num_outputs=512)
#self.local_check(a)
self.local_check(a) self.local_check(a)
# Checks 3 x 3x8 and 3-input NAND decoder
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", num_outputs=512)
self.local_check(a)
# Checks 3 x 4x16 and 4-input NAND decoder
debug.info(1, "Testing 4096 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", num_outputs=4096)
self.local_check(a)
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -8,14 +8,15 @@
# #
import unittest import unittest
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
@unittest.skip("SKIPPING hierarchical_predecode4x16_test")
# @unittest.skip("SKIPPING hierarchical_predecode4x16_test")
class hierarchical_predecode4x16_test(openram_test): class hierarchical_predecode4x16_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -14,7 +14,8 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class single_level_column_mux_test(openram_test):
class column_mux_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"))
@ -26,27 +27,27 @@ class single_level_column_mux_test(openram_test):
globals.setup_bitcell() globals.setup_bitcell()
debug.info(1, "Testing sample for 2-way column_mux_array port 0") debug.info(1, "Testing sample for 2-way column_mux_array port 0")
a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=4, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="column_mux_array", columns=8, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 2-way column_mux_array port 1") debug.info(1, "Testing sample for 2-way column_mux_array port 1")
a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=4, bitcell_bl="bl1", bitcell_br="br1") a = factory.create(module_type="column_mux_array", columns=8, word_size=4, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array port 0") debug.info(1, "Testing sample for 4-way column_mux_array port 0")
a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=2, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="column_mux_array", columns=8, word_size=2, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array port 1") debug.info(1, "Testing sample for 4-way column_mux_array port 1")
a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=2, bitcell_bl="bl1", bitcell_br="br1") a = factory.create(module_type="column_mux_array", columns=8, word_size=2, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array port 0") debug.info(1, "Testing sample for 8-way column_mux_array port 0")
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=2, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="column_mux_array", columns=16, word_size=2, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array port 1") debug.info(1, "Testing sample for 8-way column_mux_array port 1")
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=2, bitcell_bl="bl1", bitcell_br="br1") a = factory.create(module_type="column_mux_array", columns=16, word_size=2, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -7,19 +7,19 @@
# All rights reserved. # All rights reserved.
# #
from testutils import * from testutils import *
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class single_level_column_mux_pbitcell_test(openram_test):
class column_mux_pbitcell_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)
import single_level_column_mux_array
# check single level column mux array in multi-port # check single level column mux array in multi-port
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
@ -29,19 +29,19 @@ class single_level_column_mux_pbitcell_test(openram_test):
factory.reset() factory.reset()
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") debug.info(1, "Testing sample for 4-way column_mux_array in multi-port")
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)")
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)")
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2", column_offset=3) a = factory.create(module_type="column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2", column_offset=3)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -14,22 +14,23 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class single_level_column_mux_test(openram_test):
class column_mux_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)
debug.info(1, "Testing sample for 2-way column_mux_array") debug.info(1, "Testing sample for 2-way column_mux_array")
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8) a = factory.create(module_type="column_mux_array", columns=16, word_size=8)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array") debug.info(1, "Testing sample for 4-way column_mux_array")
a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4) a = factory.create(module_type="column_mux_array", columns=16, word_size=4)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array") debug.info(1, "Testing sample for 8-way column_mux_array")
a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4) a = factory.create(module_type="column_mux_array", columns=32, word_size=4)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -16,6 +16,7 @@ from sram_factory import factory
import debug import debug
@unittest.skip("SKIPPING 26_sram_pex_test")
class sram_pex_test(openram_test): class sram_pex_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -9,7 +9,7 @@
import re import re
import unittest import unittest
import sys,os import sys, os
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
import globals import globals
@ -47,12 +47,12 @@ suite = unittest.TestSuite()
load = unittest.defaultTestLoader.loadTestsFromModule load = unittest.defaultTestLoader.loadTestsFromModule
suite.addTests(map(load, modules)) suite.addTests(map(load, modules))
test_runner = unittest.TextTestRunner(verbosity=2,stream=sys.stderr) test_runner = unittest.TextTestRunner(verbosity=2, stream=sys.stderr)
test_result = test_runner.run(suite) test_result = test_runner.run(suite)
import verify import verify
verify.print_drc_stats() verify.print_drc_stats()
verify.print_lvs_stats() verify.print_lvs_stats()
verify.print_pex_stats() verify.print_pex_stats()
sys.exit(not test_result.wasSuccessful()) sys.exit(not test_result.wasSuccessful())