Fixed merge conflict, moved control logic mod instantiation, removed some commented out code.

This commit is contained in:
Hunter Nichols 2018-11-14 13:53:27 -08:00
commit e9f6566e59
18 changed files with 745 additions and 491 deletions

View File

@ -69,31 +69,31 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
"""Checks both DRC and LVS for a module"""
# Unit tests will check themselves.
# Do not run if disabled in options.
if not OPTS.is_unit_test and OPTS.check_lvsdrc:
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempspice = OPTS.openram_temp + "/temp.sp"
tempgds = OPTS.openram_temp + "/temp.gds"
self.sp_write(tempspice)
self.gds_write(tempgds)
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
debug.check(verify.run_drc(self.name, tempgds, final_verification) == 0,"DRC failed for {0}".format(self.name))
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
os.remove(tempspice)
os.remove(tempgds)
def DRC(self):
def DRC(self, final_verification=False):
"""Checks DRC for a module"""
# Unit tests will check themselves.
# Do not run if disabled in options.
if not OPTS.is_unit_test and OPTS.check_lvsdrc:
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempgds = OPTS.openram_temp + "/temp.gds"
self.gds_write(tempgds)
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
debug.check(verify.run_drc(self.name, tempgds, final_verification) == 0,"DRC failed for {0}".format(self.name))
os.remove(tempgds)
def LVS(self, final_verification=False):
"""Checks LVS for a module"""
# Unit tests will check themselves.
# Do not run if disabled in options.
if not OPTS.is_unit_test and OPTS.check_lvsdrc:
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempspice = OPTS.openram_temp + "/temp.sp"
tempgds = OPTS.openram_temp + "/temp.gds"
self.sp_write(tempspice)

View File

@ -30,8 +30,10 @@ def parse_args():
help="Base output file name(s) prefix", metavar="FILE"),
optparse.make_option("-p", "--outpath", dest="output_path",
help="Output file(s) location"),
optparse.make_option("-i", "--inlinecheck", action="store_true",
help="Enable inline LVS/DRC checks", dest="inline_lvsdrc"),
optparse.make_option("-n", "--nocheck", action="store_false",
help="Disable inline LVS/DRC checks", dest="check_lvsdrc"),
help="Disable all LVS/DRC checks", dest="check_lvsdrc"),
optparse.make_option("-v", "--verbose", action="count", dest="debug_level",
help="Increase the verbosity level"),
optparse.make_option("-t", "--tech", dest="tech_name",
@ -387,10 +389,10 @@ def import_tech():
def print_time(name, now_time, last_time=None):
""" Print a statement about the time delta. """
if last_time:
time = round((now_time-last_time).total_seconds(),1)
time = str(round((now_time-last_time).total_seconds(),1)) + " seconds"
else:
time = now_time
print("** {0}: {1} seconds".format(name,time))
time = now_time.strftime('%m/%d/%Y %H:%M:%S')
print("** {0}: {1}".format(name,time))
def report_status():
@ -413,6 +415,9 @@ def report_status():
if OPTS.netlist_only:
print("Netlist only mode (no physical design is being done).")
if not OPTS.inline_lvsdrc:
print("DRC/LVS/PEX is only run on the top-level design.")
if not OPTS.check_lvsdrc:
print("DRC/LVS/PEX checking is disabled.")
print("DRC/LVS/PEX is completely disabled.")

File diff suppressed because it is too large Load Diff

View File

@ -27,12 +27,12 @@ class bank_select(design.design):
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_modules()
self.create_instances()
def create_layout(self):
self.calculate_module_offsets()
self.place_modules()
self.route_modules()
self.place_instances()
self.route_instances()
self.DRC_LVS()
@ -99,7 +99,7 @@ class bank_select(design.design):
self.height = self.yoffset_maxpoint + 2*self.m1_pitch
self.width = self.xoffset_inv + self.inv4x.width
def create_modules(self):
def create_instances(self):
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv_sel)
@ -152,7 +152,7 @@ class bank_select(design.design):
"vdd",
"gnd"])
def place_modules(self):
def place_instances(self):
# bank select inverter
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
@ -195,7 +195,7 @@ class bank_select(design.design):
mirror=mirror)
def route_modules(self):
def route_instances(self):
# bank_sel is vertical wire
bank_sel_inv_pin = self.bank_sel_inv.get_pin("A")

View File

@ -34,7 +34,7 @@ class bitcell_array(design.design):
""" Create and connect the netlist """
self.add_modules()
self.add_pins()
self.create_modules()
self.create_instances()
def create_layout(self):
@ -85,7 +85,7 @@ class bitcell_array(design.design):
self.cell = self.mod_bitcell()
self.add_mod(self.cell)
def create_modules(self):
def create_instances(self):
""" Create the module instances used in this design """
self.cell_inst = {}
for col in range(self.column_size):

View File

@ -48,12 +48,12 @@ class control_logic(design.design):
self.setup_signal_busses()
self.add_pins()
self.add_modules()
self.create_modules()
self.create_instances()
def create_layout(self):
""" Create layout and route between modules """
self.route_rails()
self.place_modules()
self.place_instances()
self.route_all()
#self.add_lvs_correspondence_points()
@ -197,8 +197,8 @@ class control_logic(design.design):
self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height)
def create_modules(self):
""" Create all the modules """
def create_instances(self):
""" Create all the instances """
self.create_dffs()
self.create_clk_row()
if (self.port_type == "rw") or (self.port_type == "w"):
@ -209,8 +209,8 @@ class control_logic(design.design):
self.create_rbl()
def place_modules(self):
""" Place all the modules """
def place_instances(self):
""" Place all the instances """
# Keep track of all right-most instances to determine row boundary
# and add the vdd/gnd pins
self.row_end_inst = []

View File

@ -36,13 +36,13 @@ class dff_buf(design.design):
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_modules()
self.create_instances()
def create_layout(self):
self.width = self.dff.width + self.inv1.width + self.inv2.width
self.height = self.dff.height
self.place_modules()
self.place_instances()
self.route_wires()
self.add_layout_pins()
self.DRC_LVS()
@ -70,7 +70,7 @@ class dff_buf(design.design):
self.add_pin("vdd")
self.add_pin("gnd")
def create_modules(self):
def create_instances(self):
self.dff_inst=self.add_inst(name="dff_buf_dff",
mod=self.dff)
self.connect_inst(["D", "qint", "clk", "vdd", "gnd"])
@ -83,7 +83,7 @@ class dff_buf(design.design):
mod=self.inv2)
self.connect_inst(["Qb", "Q", "vdd", "gnd"])
def place_modules(self):
def place_instances(self):
# Add the DFF
self.dff_inst.place(vector(0,0))

View File

@ -31,8 +31,8 @@ class hierarchical_predecode(design.design):
self.add_pin("vdd")
self.add_pin("gnd")
def create_modules(self):
""" Create the INV and NAND gate """
def add_modules(self):
""" Add the INV and NAND gate modules """
self.inv = pinv()
self.add_mod(self.inv)

View File

@ -18,7 +18,7 @@ class hierarchical_predecode2x4(hierarchical_predecode):
def create_netlist(self):
self.add_pins()
self.create_modules()
self.add_modules()
self.create_input_inverters()
self.create_output_inverters()
connections =[["inbar_0", "inbar_1", "Z_0", "vdd", "gnd"],

View File

@ -18,7 +18,7 @@ class hierarchical_predecode3x8(hierarchical_predecode):
def create_netlist(self):
self.add_pins()
self.create_modules()
self.add_modules()
self.create_input_inverters()
self.create_output_inverters()
connections=[["inbar_0", "inbar_1", "inbar_2", "Z_0", "vdd", "gnd"],

View File

@ -54,8 +54,8 @@ class multibank(design.design):
self.compute_sizes()
self.add_pins()
self.create_modules()
self.add_modules()
self.create_instances()
self.setup_layout_constraints()
# FIXME: Move this to the add modules function
@ -111,7 +111,7 @@ class multibank(design.design):
self.route_supplies()
def add_modules(self):
def create_instances(self):
""" Add modules. The order should not matter! """
# Above the bitcell array
@ -175,8 +175,8 @@ class multibank(design.design):
def create_modules(self):
""" Create all the modules using the class loader """
def add_modules(self):
""" Add all the modules using the class loader """
self.tri = self.mod_tri_gate()
self.bitcell = self.mod_bitcell()

View File

@ -29,11 +29,11 @@ class replica_bitline(design.design):
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_modules()
self.create_instances()
def create_layout(self):
self.calculate_module_offsets()
self.place_modules()
self.place_instances()
self.route()
self.add_layout_pins()
@ -104,7 +104,7 @@ class replica_bitline(design.design):
self.access_tx = ptx(tx_type="pmos")
self.add_mod(self.access_tx)
def create_modules(self):
def create_instances(self):
""" Create all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL
@ -152,7 +152,7 @@ class replica_bitline(design.design):
self.wl_list = self.rbl.cell.list_all_wl_names()
self.bl_list = self.rbl.cell.list_all_bl_names()
def place_modules(self):
def place_instances(self):
""" Add all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL

View File

@ -129,16 +129,15 @@ class wordline_driver(design.design):
nand2_xoffset = inv1_xoffset + self.inv.width
inv2_xoffset = nand2_xoffset + self.nand2.width
self.width = inv2_xoffset + self.inv.height
driver_height = self.inv.height
self.width = inv2_xoffset + self.inv.width
self.height = self.inv.height * self.rows
for row in range(self.rows):
if (row % 2):
y_offset = driver_height*(row + 1)
y_offset = self.inv.height*(row + 1)
inst_mirror = "MX"
else:
y_offset = driver_height*row
y_offset = self.inv.height*row
inst_mirror = "R0"
inv1_offset = [inv1_xoffset, y_offset]

View File

@ -20,8 +20,10 @@ class options(optparse.Values):
debug_level = 0
# When enabled, layout is not generated (and no DRC or LVS are performed)
netlist_only = False
# This determines whether LVS and DRC is checked for each submodule.
# This determines whether LVS and DRC is checked at all.
check_lvsdrc = True
# This determines whether LVS and DRC is checked for every submodule.
inline_lvsdrc = False
# Variable to select the variant of spice
spice_name = ""
# The spice executable being used which is derived from the user PATH.

View File

@ -653,63 +653,32 @@ class router(router_tech):
debug.info(2,"Analyzing pin groups for {}.".format(pin_name))
pin_set = self.pins[pin_name]
local_debug = False
# Put each pin in an equivalence class of it's own
equiv_classes = [set([x]) for x in pin_set]
if local_debug:
debug.info(0,"INITIAL\n",equiv_classes)
def compare_classes(class1, class2):
"""
Determine if two classes should be combined and if so return
the combined set. Otherwise, return None.
"""
if local_debug:
debug.info(0,"CLASS1:\n",class1)
debug.info(0,"CLASS2:\n",class2)
# Compare each pin in each class,
# and if any overlap, return the combined the class
for p1 in class1:
for p2 in class2:
if p1.overlaps(p2):
combined_class = class1 | class2
if local_debug:
debug.info(0,"COMBINE:",pformat(combined_class))
return combined_class
if local_debug:
debug.info(0,"NO COMBINE")
return None
def combine_classes(equiv_classes):
""" Recursive function to combine classes. """
local_debug = False
if local_debug:
debug.info(0,"\nRECURSE:\n",pformat(equiv_classes))
if len(equiv_classes)==1:
return(equiv_classes)
for class1 in equiv_classes:
for class2 in equiv_classes:
if class1 == class2:
continue
class3 = compare_classes(class1, class2)
if class3:
new_classes = equiv_classes
new_classes.remove(class1)
new_classes.remove(class2)
new_classes.append(class3)
return(combine_classes(new_classes))
else:
return(equiv_classes)
# Compare each pin in each class,
# and if any overlap, update equiv_classes to include the combined the class
for p1 in class1:
for p2 in class2:
if p1.overlaps(p2):
combined_class = class1 | class2
equiv_classes.remove(class1)
equiv_classes.remove(class2)
equiv_classes.append(combined_class)
return(equiv_classes)
return(equiv_classes)
reduced_classes = combine_classes(equiv_classes)
if local_debug:
debug.info(0,"FINAL ",reduced_classes)
self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_set=x, router=self) for x in reduced_classes]
old_length = math.inf
while (len(equiv_classes)<old_length):
old_length = len(equiv_classes)
equiv_classes = combine_classes(equiv_classes)
self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_set=x, router=self) for x in equiv_classes]
def convert_pins(self, pin_name):
"""

View File

@ -34,14 +34,14 @@ class sram_1bank(sram_base):
self.bank_inst=self.create_bank(0)
self.control_logic_inst = self.create_control_logic()
self.control_logic_insts = self.create_control_logic()
self.row_addr_dff_inst = self.create_row_addr_dff()
self.row_addr_dff_insts = self.create_row_addr_dff()
if self.col_addr_dff:
self.col_addr_dff_inst = self.create_col_addr_dff()
self.col_addr_dff_insts = self.create_col_addr_dff()
self.data_dff_inst = self.create_data_dff()
self.data_dff_insts = self.create_data_dff()
def place_modules(self):
"""
@ -58,14 +58,14 @@ class sram_1bank(sram_base):
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
# up to the row address DFFs.
for port in self.all_ports:
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
self.control_logic_inst[port].place(control_pos)
control_pos = vector(-self.control_logic_rw.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic_rw.control_logic_center.y)
self.control_logic_insts[port].place(control_pos)
# The row address bits are placed above the control logic aligned on the right.
row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width,
self.control_logic_inst[0].uy())
self.row_addr_dff_inst[port].place(row_addr_pos)
row_addr_pos = vector(self.control_logic_insts[0].rx() - self.row_addr_dff.width,
self.control_logic_insts[0].uy())
self.row_addr_dff_insts[port].place(row_addr_pos)
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
data_gap = -self.m2_pitch*(self.word_size+1)
@ -75,7 +75,7 @@ class sram_1bank(sram_base):
if self.col_addr_dff:
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
data_gap - self.col_addr_dff.height)
self.col_addr_dff_inst[port].place(col_addr_pos)
self.col_addr_dff_insts[port].place(col_addr_pos)
# Add the data flops below the bank to the right of the center of bank:
# This relies on the center point of the bank:
@ -84,7 +84,7 @@ class sram_1bank(sram_base):
# sense amps.
data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height)
self.data_dff_inst[port].place(data_pos)
self.data_dff_insts[port].place(data_pos)
# two supply rails are already included in the bank, so just 2 here.
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
@ -97,7 +97,7 @@ class sram_1bank(sram_base):
for port in self.all_ports:
# Connect the control pins as inputs
for signal in self.control_logic_inputs[port] + ["clk"]:
self.copy_layout_pin(self.control_logic_inst[port], signal, signal+"{}".format(port))
self.copy_layout_pin(self.control_logic_insts[port], signal, signal+"{}".format(port))
if port in self.read_ports:
for bit in range(self.word_size):
@ -105,14 +105,14 @@ class sram_1bank(sram_base):
# Lower address bits
for bit in range(self.col_addr_size):
self.copy_layout_pin(self.col_addr_dff_inst[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit))
self.copy_layout_pin(self.col_addr_dff_insts[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit))
# Upper address bits
for bit in range(self.row_addr_size):
self.copy_layout_pin(self.row_addr_dff_inst[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size))
self.copy_layout_pin(self.row_addr_dff_insts[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size))
if port in self.write_ports:
for bit in range(self.word_size):
self.copy_layout_pin(self.data_dff_inst[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit))
self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit))
def route(self):
""" Route a single bank SRAM """
@ -135,7 +135,7 @@ class sram_1bank(sram_base):
# This is the actual input to the SRAM
for port in self.all_ports:
self.copy_layout_pin(self.control_logic_inst[port], "clk", "clk{}".format(port))
self.copy_layout_pin(self.control_logic_insts[port], "clk", "clk{}".format(port))
# Connect all of these clock pins to the clock in the central bus
# This is something like a "spine" clock distribution. The two spines
@ -147,23 +147,23 @@ class sram_1bank(sram_base):
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_inst[port].get_pin("clk")
dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk")
dff_clk_pos = dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos])
data_dff_clk_pin = self.data_dff_inst[port].get_pin("clk")
data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos])
# This uses a metal2 track to the right of the control/row addr DFF
# to route vertically.
control_clk_buf_pin = self.control_logic_inst[port].get_pin("clk_buf")
control_clk_buf_pin = self.control_logic_insts[port].get_pin("clk_buf")
control_clk_buf_pos = control_clk_buf_pin.rc()
row_addr_clk_pin = self.row_addr_dff_inst[port].get_pin("clk")
row_addr_clk_pin = self.row_addr_dff_insts[port].get_pin("clk")
row_addr_clk_pos = row_addr_clk_pin.rc()
mid1_pos = vector(self.row_addr_dff_inst[port].rx() + self.m2_pitch,
mid1_pos = vector(self.row_addr_dff_insts[port].rx() + self.m2_pitch,
row_addr_clk_pos.y)
mid2_pos = vector(mid1_pos.x,
control_clk_buf_pos.y)
@ -176,7 +176,7 @@ class sram_1bank(sram_base):
""" Route the outputs from the control logic module """
for port in self.all_ports:
for signal in self.control_logic_outputs[port]:
src_pin = self.control_logic_inst[port].get_pin(signal)
src_pin = self.control_logic_insts[port].get_pin(signal)
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"),
@ -190,7 +190,7 @@ class sram_1bank(sram_base):
for bit in range(self.row_addr_size):
flop_name = "dout_{}".format(bit)
bank_name = "addr{0}_{1}".format(port,bit+self.col_addr_size)
flop_pin = self.row_addr_dff_inst[port].get_pin(flop_name)
flop_pin = self.row_addr_dff_insts[port].get_pin(flop_name)
bank_pin = self.bank_inst.get_pin(bank_name)
flop_pos = flop_pin.center()
bank_pos = bank_pin.center()
@ -206,13 +206,13 @@ class sram_1bank(sram_base):
bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.col_addr_dff_inst[port].ul() + vector(0, self.m1_pitch),
offset=self.col_addr_dff_insts[port].ul() + vector(0, self.m1_pitch),
names=bus_names,
length=self.col_addr_dff_inst[port].width)
length=self.col_addr_dff_insts[port].width)
dff_names = ["dout_{}".format(x) for x in range(self.col_addr_size)]
data_dff_map = zip(dff_names, bus_names)
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst[port], col_addr_bus_offsets)
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_insts[port], col_addr_bus_offsets)
bank_names = ["addr{0}_{1}".format(port,x) for x in range(self.col_addr_size)]
data_bank_map = zip(bank_names, bus_names)
@ -223,13 +223,13 @@ class sram_1bank(sram_base):
""" Connect the output of the data flops to the write driver """
# This is where the channel will start (y-dimension at least)
for port in self.write_ports:
offset = self.data_dff_inst[port].ul() + vector(0, 2*self.m1_pitch)
offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
dff_names = ["dout_{}".format(x) for x in range(self.word_size)]
bank_names = ["din{0}_{1}".format(port,x) for x in range(self.word_size)]
route_map = list(zip(bank_names, dff_names))
dff_pins = {key: self.data_dff_inst[port].get_pin(key) for key in dff_names }
dff_pins = {key: self.data_dff_insts[port].get_pin(key) for key in dff_names }
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
# Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**dff_pins, **bank_pins}
@ -245,7 +245,7 @@ class sram_1bank(sram_base):
"""
for n in self.control_logic_outputs[0]:
pin = self.control_logic_inst[0].get_pin(n)
pin = self.control_logic_insts[0].get_pin(n)
self.add_label(text=n,
layer=pin.layer,
offset=pin.center())

View File

@ -216,6 +216,29 @@ class sram_base(design):
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
# <<<<<<< HEAD
# =======
# c = reload(__import__(OPTS.control_logic))
# self.mod_control_logic = getattr(c, OPTS.control_logic)
# # Create the control logic module for each port type
# if len(self.readwrite_ports)>0:
# self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
# words_per_row=self.words_per_row,
# port_type="rw")
# self.add_mod(self.control_logic_rw)
# if len(self.write_ports)>0:
# self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
# words_per_row=self.words_per_row,
# port_type="w")
# self.add_mod(self.control_logic_w)
# if len(self.read_ports)>0:
# self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
# words_per_row=self.words_per_row,
# port_type="r")
# self.add_mod(self.control_logic_r)
# >>>>>>> dev
# Create the address and control flops (but not the clk)
from dff_array import dff_array
@ -249,18 +272,27 @@ class sram_base(design):
#The control logic can resize itself based on the other modules. Requires all other modules added before control logic.
self.all_mods_except_control_done = True
#c = reload(__import__(OPTS.control_logic))
#self.mod_control_logic = getattr(c, OPTS.control_logic)
from control_logic import control_logic
c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.control_logic)
# Create the control logic module for each port type
if OPTS.num_rw_ports>0:
self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row,sram=self, port_type="rw")
if len(self.readwrite_ports)>0:
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
sram=self,
port_type="rw")
self.add_mod(self.control_logic_rw)
if OPTS.num_w_ports>0:
self.control_logic_w = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row,sram=self, port_type="w")
if len(self.write_ports)>0:
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
sram=self,
port_type="w")
self.add_mod(self.control_logic_w)
if OPTS.num_r_ports>0:
self.control_logic_r = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row,sram=self, port_type="r")
if len(self.read_ports)>0:
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
sram=self,
port_type="r")
self.add_mod(self.control_logic_r)
def create_bank(self,bank_num):
@ -383,7 +415,8 @@ class sram_base(design):
def create_control_logic(self):
""" Add and place control logic """
""" Add control logic instances """
insts = []
for port in self.all_ports:
if port in self.readwrite_ports:
@ -393,8 +426,7 @@ class sram_base(design):
else:
mod = self.control_logic_r
insts.append(self.add_inst(name="control{}".format(port),
mod=mod))
insts.append(self.add_inst(name="control{}".format(port), mod=mod))
temp = ["csb{}".format(port)]
if port in self.readwrite_ports:
@ -455,25 +487,10 @@ class sram_base(design):
def analytical_delay(self, vdd, slew,load):
""" LH and HL are the same in analytical model. """
return self.bank.analytical_delay(vdd,slew,load)
# def get_delay_to_wl(self):
# """Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
# debug.check(self.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
# stage_efforts = self.determine_wordline_stage_efforts()
# clk_to_wl_delay = logical_effort.calculate_relative_delay(stage_efforts, self.pinv)
# debug.info(1, "Clock to wordline delay is {} delay units".format(clk_to_wl_delay))
# return clk_to_wl_delay
def determine_wordline_stage_efforts(self):
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
#clk
stage_effort_list = []
# clk_buf_cout = self.get_clk_cin()
# #Assume rw only. There are important differences with multiport that will need to be accounted for.
# if self.control_logic_rw != None:
# stage_effort_list += self.control_logic_rw.determine_wordline_stage_efforts(clk_buf_cout)
# else:
# stage_effort_list += self.control_logic_r.determine_wordline_stage_efforts(clk_buf_cout)
#Clk_buf originates from the control logic so only the bank is related to the wordline path
external_wordline_cout = 0 #No loading on the wordline other than in the bank.
@ -491,30 +508,7 @@ class sram_base(design):
col_addr_clk_cin = self.col_addr_dff.get_clk_cin()
bank_clk_cin = self.bank.get_clk_cin()
return row_addr_clk_cin + data_clk_cin + col_addr_clk_cin + bank_clk_cin
# def get_delay_to_sen(self):
# """Get the delay (in delay units) of the clk to a sense amp enable.
# This does not incorporate the delay of the replica bitline.
# """
# debug.check(self.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
# stage_efforts = self.determine_sa_enable_stage_efforts()
# clk_to_sen_delay = logical_effort.calculate_relative_delay(stage_efforts, self.pinv)
# debug.info(1, "Clock to s_en delay is {} delay units".format(clk_to_sen_delay))
# return clk_to_sen_delay
# def determine_sa_enable_stage_efforts(self):
# """Get the all the stage efforts for each stage in the path from clk to a sense amp enable"""
# stage_effort_list = []
# clk_buf_bar_cout = self.get_clk_bar_cin()
# clk_sen_cout = self.get_sen_cin()
# #Assume rw only. There are important differences with multiport that will need to be accounted for.
# if self.control_logic_rw != None:
# stage_effort_list += self.control_logic_rw.determine_sa_enable_stage_efforts(clk_buf_bar_cout, clk_sen_cout)
# else:
# stage_effort_list += self.control_logic_r.determine_sa_enable_stage_efforts(clk_buf_bar_cout, clk_sen_cout)
# return stage_effort_list
return row_addr_clk_cin + data_clk_cin + col_addr_clk_cin + bank_clk_cin
def get_clk_bar_cin(self):
"""Gets the capacitive load the of clock (clk_buf_bar) for the sram"""

View File

@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""
Run a regression test on 1rw 1r sram bank
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class single_bank_1rw_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from bank import bank
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16)
c.words_per_row=1
debug.info(1, "No column mux")
a = bank(c, name="bank1_single")
self.local_check(a)
c.num_words=32
c.words_per_row=2
debug.info(1, "Two way column mux")
a = bank(c, name="bank2_single")
self.local_check(a)
c.num_words=64
c.words_per_row=4
debug.info(1, "Four way column mux")
a = bank(c, name="bank3_single")
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Eight way column mux")
a = bank(c, name="bank4_single")
self.local_check(a)
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()