mirror of https://github.com/VLSIDA/OpenRAM.git
Merged with dev, addressed conflict in port data
This commit is contained in:
commit
294ccf602e
|
|
@ -45,7 +45,8 @@ class _hierarchical_predecode:
|
||||||
bus_space_factor,
|
bus_space_factor,
|
||||||
input_layer,
|
input_layer,
|
||||||
output_layer,
|
output_layer,
|
||||||
vertical_supply):
|
vertical_supply,
|
||||||
|
force_horizontal_input_contact):
|
||||||
# hierarchical_predecode
|
# hierarchical_predecode
|
||||||
# bus_layer, bus_directions, bus_pitch, bus_space, input_layer, output_layer, output_layer_pitch
|
# bus_layer, bus_directions, bus_pitch, bus_space, input_layer, output_layer, output_layer_pitch
|
||||||
# m2, pref, m2_pitch, m2_space, m1, m1, m1_pitch
|
# m2, pref, m2_pitch, m2_space, m1, m1, m1_pitch
|
||||||
|
|
@ -59,6 +60,7 @@ class _hierarchical_predecode:
|
||||||
self.input_layer = input_layer
|
self.input_layer = input_layer
|
||||||
self.output_layer = output_layer
|
self.output_layer = output_layer
|
||||||
self.vertical_supply = vertical_supply
|
self.vertical_supply = vertical_supply
|
||||||
|
self.force_horizontal_input_contact = force_horizontal_input_contact
|
||||||
|
|
||||||
|
|
||||||
class _column_mux_array:
|
class _column_mux_array:
|
||||||
|
|
@ -152,7 +154,8 @@ class layer_properties():
|
||||||
bus_space_factor=1,
|
bus_space_factor=1,
|
||||||
input_layer="m1",
|
input_layer="m1",
|
||||||
output_layer="m1",
|
output_layer="m1",
|
||||||
vertical_supply=False)
|
vertical_supply=False,
|
||||||
|
force_horizontal_input_contact=False)
|
||||||
|
|
||||||
self._column_mux_array = _column_mux_array(select_layer="m1",
|
self._column_mux_array = _column_mux_array(select_layer="m1",
|
||||||
select_pitch="m2_pitch",
|
select_pitch="m2_pitch",
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ class spice():
|
||||||
# This gets set in both spice and layout so either can be called first.
|
# This gets set in both spice and layout so either can be called first.
|
||||||
self.name = name
|
self.name = name
|
||||||
self.cell_name = cell_name
|
self.cell_name = cell_name
|
||||||
|
|
||||||
self.sp_file = OPTS.openram_tech + "sp_lib/" + cell_name + ".sp"
|
self.sp_file = OPTS.openram_tech + "sp_lib/" + cell_name + ".sp"
|
||||||
|
|
||||||
# If we have a separate lvs directory, then all the lvs files
|
# If we have a separate lvs directory, then all the lvs files
|
||||||
|
|
@ -570,6 +569,7 @@ class spice():
|
||||||
net = net.lower()
|
net = net.lower()
|
||||||
int_net = self.name_dict[net]['int_net']
|
int_net = self.name_dict[net]['int_net']
|
||||||
int_mod = self.name_dict[net]['mod']
|
int_mod = self.name_dict[net]['mod']
|
||||||
|
|
||||||
if int_mod.is_net_alias(int_net, alias, alias_mod, exclusion_set):
|
if int_mod.is_net_alias(int_net, alias, alias_mod, exclusion_set):
|
||||||
aliases.append(net)
|
aliases.append(net)
|
||||||
return aliases
|
return aliases
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,13 @@ class verilog:
|
||||||
self.gnd_name = spice["ground"]
|
self.gnd_name = spice["ground"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.gnd_name = "gnd"
|
self.gnd_name = "gnd"
|
||||||
|
|
||||||
self.vf.write("module {0}(\n".format(self.name))
|
self.vf.write("module {0}(\n".format(self.name))
|
||||||
self.vf.write("`ifdef USE_POWER_PINS\n")
|
self.vf.write("`ifdef USE_POWER_PINS\n")
|
||||||
self.vf.write(" {},\n".format(self.vdd_name))
|
self.vf.write(" {},\n".format(self.vdd_name))
|
||||||
self.vf.write(" {},\n".format(self.gnd_name))
|
self.vf.write(" {},\n".format(self.gnd_name))
|
||||||
self.vf.write("`endif\n")
|
self.vf.write("`endif\n")
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
if port in self.readwrite_ports:
|
if port in self.readwrite_ports:
|
||||||
self.vf.write("// Port {0}: RW\n".format(port))
|
self.vf.write("// Port {0}: RW\n".format(port))
|
||||||
|
|
@ -55,11 +55,15 @@ class verilog:
|
||||||
self.vf.write(" clk{0},csb{0},web{0},".format(port))
|
self.vf.write(" clk{0},csb{0},web{0},".format(port))
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
self.vf.write("wmask{},".format(port))
|
self.vf.write("wmask{},".format(port))
|
||||||
|
if self.num_spare_cols > 0:
|
||||||
|
self.vf.write("spare_wen{0},".format(port))
|
||||||
self.vf.write("addr{0},din{0},dout{0}".format(port))
|
self.vf.write("addr{0},din{0},dout{0}".format(port))
|
||||||
elif port in self.write_ports:
|
elif port in self.write_ports:
|
||||||
self.vf.write(" clk{0},csb{0},".format(port))
|
self.vf.write(" clk{0},csb{0},".format(port))
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
self.vf.write("wmask{},".format(port))
|
self.vf.write("wmask{},".format(port))
|
||||||
|
if self.num_spare_cols > 0:
|
||||||
|
self.vf.write("spare_wen{0},".format(port))
|
||||||
self.vf.write("addr{0},din{0}".format(port))
|
self.vf.write("addr{0},din{0}".format(port))
|
||||||
elif port in self.read_ports:
|
elif port in self.read_ports:
|
||||||
self.vf.write(" clk{0},csb{0},addr{0},dout{0}".format(port))
|
self.vf.write(" clk{0},csb{0},addr{0},dout{0}".format(port))
|
||||||
|
|
@ -71,7 +75,7 @@ class verilog:
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
|
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
|
||||||
self.vf.write(" parameter NUM_WMASKS = {0} ;\n".format(self.num_wmasks))
|
self.vf.write(" parameter NUM_WMASKS = {0} ;\n".format(self.num_wmasks))
|
||||||
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
|
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size + self.num_spare_cols))
|
||||||
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
|
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
|
||||||
self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n")
|
self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n")
|
||||||
self.vf.write(" // FIXME: This delay is arbitrary.\n")
|
self.vf.write(" // FIXME: This delay is arbitrary.\n")
|
||||||
|
|
@ -84,7 +88,7 @@ class verilog:
|
||||||
self.vf.write(" inout {};\n".format(self.vdd_name))
|
self.vf.write(" inout {};\n".format(self.vdd_name))
|
||||||
self.vf.write(" inout {};\n".format(self.gnd_name))
|
self.vf.write(" inout {};\n".format(self.gnd_name))
|
||||||
self.vf.write("`endif\n")
|
self.vf.write("`endif\n")
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.add_inputs_outputs(port)
|
self.add_inputs_outputs(port)
|
||||||
|
|
||||||
|
|
@ -123,6 +127,10 @@ class verilog:
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
self.vf.write(" reg [NUM_WMASKS-1:0] wmask{0}_reg;\n".format(port))
|
self.vf.write(" reg [NUM_WMASKS-1:0] wmask{0}_reg;\n".format(port))
|
||||||
|
if self.num_spare_cols > 1:
|
||||||
|
self.vf.write(" reg [{1}:0] spare_wen{0}_reg;".format(port, self.num_spare_cols - 1))
|
||||||
|
elif self.num_spare_cols == 1:
|
||||||
|
self.vf.write(" reg spare_wen{0}_reg;\n".format(port))
|
||||||
self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port))
|
self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port))
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
self.vf.write(" reg [DATA_WIDTH-1:0] din{0}_reg;\n".format(port))
|
self.vf.write(" reg [DATA_WIDTH-1:0] din{0}_reg;\n".format(port))
|
||||||
|
|
@ -143,7 +151,9 @@ class verilog:
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
self.vf.write(" wmask{0}_reg = wmask{0};\n".format(port))
|
self.vf.write(" wmask{0}_reg = wmask{0};\n".format(port))
|
||||||
self.vf.write(" addr{0}_reg = addr{0};\n".format(port))
|
if self.num_spare_cols:
|
||||||
|
self.vf.write(" spare_wen{0}_reg = spare_wen{0};\n".format(port))
|
||||||
|
self.vf.write(" addr{0}_reg = addr{0};\n".format(port))
|
||||||
if port in self.read_ports:
|
if port in self.read_ports:
|
||||||
self.add_write_read_checks(port)
|
self.add_write_read_checks(port)
|
||||||
|
|
||||||
|
|
@ -182,6 +192,11 @@ class verilog:
|
||||||
self.vf.write(" input web{0}; // active low write control\n".format(port))
|
self.vf.write(" input web{0}; // active low write control\n".format(port))
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
self.vf.write(" input [NUM_WMASKS-1:0] wmask{0}; // write mask\n".format(port))
|
self.vf.write(" input [NUM_WMASKS-1:0] wmask{0}; // write mask\n".format(port))
|
||||||
|
if self.num_spare_cols == 1:
|
||||||
|
self.vf.write(" input spare_wen{0}; // spare mask\n".format(port))
|
||||||
|
elif self.num_spare_cols > 1:
|
||||||
|
self.vf.write(" input [{1}:0] spare_wen{0}; // spare mask\n".format(port, self.num_spare_cols-1))
|
||||||
|
|
||||||
self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port))
|
self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port))
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
self.vf.write(" input [DATA_WIDTH-1:0] din{0};\n".format(port))
|
self.vf.write(" input [DATA_WIDTH-1:0] din{0};\n".format(port))
|
||||||
|
|
@ -199,29 +214,29 @@ class verilog:
|
||||||
self.vf.write(" always @ (negedge clk{0})\n".format(port))
|
self.vf.write(" always @ (negedge clk{0})\n".format(port))
|
||||||
self.vf.write(" begin : MEM_WRITE{0}\n".format(port))
|
self.vf.write(" begin : MEM_WRITE{0}\n".format(port))
|
||||||
if port in self.readwrite_ports:
|
if port in self.readwrite_ports:
|
||||||
if self.write_size:
|
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg ) begin\n".format(port))
|
||||||
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg ) begin\n".format(port))
|
|
||||||
else:
|
|
||||||
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
|
|
||||||
else:
|
else:
|
||||||
if self.write_size:
|
self.vf.write(" if (!csb{0}_reg) begin\n".format(port))
|
||||||
self.vf.write(" if (!csb{0}_reg) begin\n".format(port))
|
|
||||||
else:
|
|
||||||
self.vf.write(" if (!csb{0}_reg)\n".format(port))
|
|
||||||
|
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
remainder_bits = self.word_size % self.write_size
|
|
||||||
for mask in range(0, self.num_wmasks):
|
for mask in range(0, self.num_wmasks):
|
||||||
lower = mask * self.write_size
|
lower = mask * self.write_size
|
||||||
if (remainder_bits and mask == self.num_wmasks - 1):
|
upper = lower + self.write_size - 1
|
||||||
upper = lower + remainder_bits - 1
|
|
||||||
else:
|
|
||||||
upper = lower + self.write_size - 1
|
|
||||||
self.vf.write(" if (wmask{0}_reg[{1}])\n".format(port, mask))
|
self.vf.write(" if (wmask{0}_reg[{1}])\n".format(port, mask))
|
||||||
self.vf.write(" mem[addr{0}_reg][{1}:{2}] = din{0}_reg[{1}:{2}];\n".format(port, upper, lower))
|
self.vf.write(" mem[addr{0}_reg][{1}:{2}] = din{0}_reg[{1}:{2}];\n".format(port, upper, lower))
|
||||||
self.vf.write(" end\n")
|
|
||||||
else:
|
else:
|
||||||
self.vf.write(" mem[addr{0}_reg] = din{0}_reg;\n".format(port))
|
upper = self.word_size - self.num_spare_cols - 1
|
||||||
|
self.vf.write(" mem[addr{0}_reg][{1}:0] = din{0}_reg[{1}:0];\n".format(port, upper))
|
||||||
|
|
||||||
|
if self.num_spare_cols == 1:
|
||||||
|
self.vf.write(" if (spare_wen{0}_reg)\n".format(port))
|
||||||
|
self.vf.write(" mem[addr{0}_reg][{1}] = din{0}_reg[{1}];\n".format(port, self.word_size))
|
||||||
|
else:
|
||||||
|
for num in range(self.num_spare_cols):
|
||||||
|
self.vf.write(" if (spare_wen{0}_reg[{1}])\n".format(port, num))
|
||||||
|
self.vf.write(" mem[addr{0}_reg][{1}] = din{0}_reg[{1}];\n".format(port, self.word_size + num))
|
||||||
|
|
||||||
|
self.vf.write(" end\n")
|
||||||
self.vf.write(" end\n")
|
self.vf.write(" end\n")
|
||||||
|
|
||||||
def add_read_block(self, port):
|
def add_read_block(self, port):
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ class bitcell_base(design.design):
|
||||||
self.nets_match = self.do_nets_exist(prop.storage_nets)
|
self.nets_match = self.do_nets_exist(prop.storage_nets)
|
||||||
self.mirror = prop.mirror
|
self.mirror = prop.mirror
|
||||||
self.end_caps = prop.end_caps
|
self.end_caps = prop.end_caps
|
||||||
|
|
||||||
def get_stage_effort(self, load):
|
def get_stage_effort(self, load):
|
||||||
parasitic_delay = 1
|
parasitic_delay = 1
|
||||||
# This accounts for bitline being drained
|
# This accounts for bitline being drained
|
||||||
|
|
@ -84,7 +83,7 @@ class bitcell_base(design.design):
|
||||||
return self.storage_nets
|
return self.storage_nets
|
||||||
else:
|
else:
|
||||||
fmt_str = "Storage nodes={} not found in spice file."
|
fmt_str = "Storage nodes={} not found in spice file."
|
||||||
debug.info(1, fmt_str.format(self.storage_nets))
|
debug.warning(fmt_str.format(self.storage_nets))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_storage_net_offset(self):
|
def get_storage_net_offset(self):
|
||||||
|
|
|
||||||
|
|
@ -481,7 +481,7 @@ class simulation():
|
||||||
debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.")
|
debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.")
|
||||||
|
|
||||||
debug.info(2, "s_en name = {}".format(self.sen_name))
|
debug.info(2, "s_en name = {}".format(self.sen_name))
|
||||||
|
|
||||||
column_addr = self.get_column_addr()
|
column_addr = self.get_column_addr()
|
||||||
bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port)
|
bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port)
|
||||||
port_pos = -1 - len(str(column_addr)) - len(str(port))
|
port_pos = -1 - len(str(column_addr)) - len(str(port))
|
||||||
|
|
@ -575,7 +575,11 @@ class simulation():
|
||||||
"""
|
"""
|
||||||
Gets the signal name associated with the bitlines in the bank.
|
Gets the signal name associated with the bitlines in the bank.
|
||||||
"""
|
"""
|
||||||
cell_mod = factory.create(module_type=OPTS.bitcell)
|
# FIXME: change to a solution that does not depend on the technology
|
||||||
|
if OPTS.tech_name == "sky130" and len(self.all_ports) == 1:
|
||||||
|
cell_mod = factory.create(module_type=OPTS.bitcell, version="opt1")
|
||||||
|
else:
|
||||||
|
cell_mod = factory.create(module_type=OPTS.bitcell)
|
||||||
cell_bl = cell_mod.get_bl_name(port)
|
cell_bl = cell_mod.get_bl_name(port)
|
||||||
cell_br = cell_mod.get_br_name(port)
|
cell_br = cell_mod.get_br_name(port)
|
||||||
|
|
||||||
|
|
@ -587,14 +591,14 @@ class simulation():
|
||||||
for i in range(len(bl_names)):
|
for i in range(len(bl_names)):
|
||||||
bl_names[i] = bl_names[i].split(OPTS.hier_seperator)[-1]
|
bl_names[i] = bl_names[i].split(OPTS.hier_seperator)[-1]
|
||||||
return bl_names[0], bl_names[1]
|
return bl_names[0], bl_names[1]
|
||||||
|
|
||||||
def get_empty_measure_data_dict(self):
|
def get_empty_measure_data_dict(self):
|
||||||
"""Make a dict of lists for each type of delay and power measurement to append results to"""
|
"""Make a dict of lists for each type of delay and power measurement to append results to"""
|
||||||
|
|
||||||
measure_names = self.delay_meas_names + self.power_meas_names
|
measure_names = self.delay_meas_names + self.power_meas_names
|
||||||
# Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
|
# Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
|
||||||
measure_data = [{mname: [] for mname in measure_names} for i in self.all_ports]
|
measure_data = [{mname: [] for mname in measure_names} for i in self.all_ports]
|
||||||
return measure_data
|
return measure_data
|
||||||
|
|
||||||
def sum_delays(self, delays):
|
def sum_delays(self, delays):
|
||||||
"""Adds the delays (delay_data objects) so the correct slew is maintained"""
|
"""Adds the delays (delay_data objects) so the correct slew is maintained"""
|
||||||
|
|
@ -603,5 +607,3 @@ class simulation():
|
||||||
for i in range(1, len(delays)):
|
for i in range(1, len(delays)):
|
||||||
delay+=delays[i]
|
delay+=delays[i]
|
||||||
return delay
|
return delay
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ from globals import OPTS
|
||||||
class stimuli():
|
class stimuli():
|
||||||
""" Class for providing stimuli functions """
|
""" Class for providing stimuli functions """
|
||||||
|
|
||||||
def __init__(self, stim_file, corner):
|
def __init__(self, stim_file, corner):
|
||||||
self.vdd_name = "vdd"
|
self.vdd_name = "vdd"
|
||||||
self.gnd_name = "gnd"
|
self.gnd_name = "gnd"
|
||||||
self.pmos_name = tech.spice["pmos"]
|
self.pmos_name = tech.spice["pmos"]
|
||||||
|
|
@ -169,7 +169,7 @@ class stimuli():
|
||||||
def gen_constant(self, sig_name, v_val):
|
def gen_constant(self, sig_name, v_val):
|
||||||
""" Generates a constant signal with reference voltage and the voltage value """
|
""" Generates a constant signal with reference voltage and the voltage value """
|
||||||
self.sf.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val))
|
self.sf.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val))
|
||||||
|
|
||||||
def get_voltage(self, value):
|
def get_voltage(self, value):
|
||||||
if value == "0" or value == 0:
|
if value == "0" or value == 0:
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -299,19 +299,27 @@ class stimuli():
|
||||||
|
|
||||||
self.sf.write("* {} process corner\n".format(self.process))
|
self.sf.write("* {} process corner\n".format(self.process))
|
||||||
for item in self.device_libraries:
|
for item in self.device_libraries:
|
||||||
|
if OPTS.spice_name:
|
||||||
|
item[0] = item[0].replace("SIMULATOR", OPTS.spice_name.lower())
|
||||||
|
else:
|
||||||
|
item[0] = item[0].replace("SIMULATOR", "ngspice")
|
||||||
if os.path.isfile(item[0]):
|
if os.path.isfile(item[0]):
|
||||||
self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1]))
|
self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1]))
|
||||||
else:
|
else:
|
||||||
debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0]))
|
debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0]), -1)
|
||||||
|
|
||||||
includes = self.device_models + [circuit]
|
includes = self.device_models + [circuit]
|
||||||
|
|
||||||
for item in list(includes):
|
for item in list(includes):
|
||||||
|
if OPTS.spice_name:
|
||||||
|
item = item.replace("SIMULATOR", OPTS.spice_name.lower())
|
||||||
|
else:
|
||||||
|
item = item.replace("SIMULATOR", "ngspice")
|
||||||
self.sf.write(".include \"{0}\"\n".format(item))
|
self.sf.write(".include \"{0}\"\n".format(item))
|
||||||
|
|
||||||
def add_comment(self, msg):
|
def add_comment(self, msg):
|
||||||
self.sf.write(msg + "\n")
|
self.sf.write(msg + "\n")
|
||||||
|
|
||||||
def write_supply(self):
|
def write_supply(self):
|
||||||
""" Writes supply voltage statements """
|
""" Writes supply voltage statements """
|
||||||
gnd_node_name = "0"
|
gnd_node_name = "0"
|
||||||
|
|
@ -403,5 +411,3 @@ class stimuli():
|
||||||
end_time = datetime.datetime.now()
|
end_time = datetime.datetime.now()
|
||||||
delta_time = round((end_time - start_time).total_seconds(), 1)
|
delta_time = round((end_time - start_time).total_seconds(), 1)
|
||||||
debug.info(2, "*** Spice: {} seconds".format(delta_time))
|
debug.info(2, "*** Spice: {} seconds".format(delta_time))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -392,14 +392,12 @@ class bank(design.design):
|
||||||
cols=self.num_cols + self.num_spare_cols,
|
cols=self.num_cols + self.num_spare_cols,
|
||||||
rows=self.num_rows)
|
rows=self.num_rows)
|
||||||
self.add_mod(self.bitcell_array)
|
self.add_mod(self.bitcell_array)
|
||||||
if self.num_spare_cols == 0:
|
|
||||||
self.num_spare_cols = (self.bitcell_array.column_size % (self.word_size *self.words_per_row))
|
|
||||||
|
|
||||||
self.port_address = []
|
self.port_address = []
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.port_address.append(factory.create(module_type="port_address",
|
self.port_address.append(factory.create(module_type="port_address",
|
||||||
cols=self.bitcell_array.column_size,
|
cols=self.num_cols + self.num_spare_cols,
|
||||||
rows=self.bitcell_array.row_size,
|
rows=self.num_rows,
|
||||||
port=port))
|
port=port))
|
||||||
self.add_mod(self.port_address[port])
|
self.add_mod(self.port_address[port])
|
||||||
|
|
||||||
|
|
@ -408,10 +406,6 @@ class bank(design.design):
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
temp_pre = factory.create(module_type="port_data",
|
temp_pre = factory.create(module_type="port_data",
|
||||||
sram_config=self.sram_config,
|
sram_config=self.sram_config,
|
||||||
dimension_override=True,
|
|
||||||
cols=self.bitcell_array.column_size - self.num_spare_cols,
|
|
||||||
rows=self.bitcell_array.row_size,
|
|
||||||
num_spare_cols=self.num_spare_cols,
|
|
||||||
port=port,
|
port=port,
|
||||||
bit_offsets=self.bit_offsets)
|
bit_offsets=self.bit_offsets)
|
||||||
self.port_data.append(temp_pre)
|
self.port_data.append(temp_pre)
|
||||||
|
|
@ -500,7 +494,7 @@ class bank(design.design):
|
||||||
mod=self.port_address[port])
|
mod=self.port_address[port])
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
for bit in range(ceil(log(self.bitcell_array.row_size, 2))):
|
for bit in range(self.row_addr_size):
|
||||||
temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size))
|
temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size))
|
||||||
temp.append("wl_en{}".format(port))
|
temp.append("wl_en{}".format(port))
|
||||||
wordline_names = self.bitcell_array.get_wordline_names(port)
|
wordline_names = self.bitcell_array.get_wordline_names(port)
|
||||||
|
|
@ -626,7 +620,7 @@ class bank(design.design):
|
||||||
self.copy_power_pins(inst, "gnd", add_vias=False)
|
self.copy_power_pins(inst, "gnd", add_vias=False)
|
||||||
|
|
||||||
if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins:
|
if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins:
|
||||||
for pin_name, supply_name in zip(['vpb','vnb'],['vdd','gnd']):
|
for pin_name, supply_name in zip(['vpb','vnb'],['gnd','vdd']):
|
||||||
self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name)
|
self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name)
|
||||||
|
|
||||||
# If we use the pinvbuf as the decoder, we need to add power pins.
|
# If we use the pinvbuf as the decoder, we need to add power pins.
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ import math
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
from tech import layer_indices
|
||||||
|
from tech import layer_stacks
|
||||||
from tech import layer_properties as layer_props
|
from tech import layer_properties as layer_props
|
||||||
|
from tech import drc
|
||||||
|
|
||||||
class hierarchical_decoder(design.design):
|
class hierarchical_decoder(design.design):
|
||||||
"""
|
"""
|
||||||
|
|
@ -29,7 +31,7 @@ class hierarchical_decoder(design.design):
|
||||||
|
|
||||||
b = factory.create(module_type=OPTS.bitcell)
|
b = factory.create(module_type=OPTS.bitcell)
|
||||||
self.cell_height = b.height
|
self.cell_height = b.height
|
||||||
|
self.predecode_bus_rail_pos = []
|
||||||
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.no_of_pre4x16)=self.determine_predecodes(self.num_inputs)
|
(self.no_of_pre2x4, self.no_of_pre3x8, self.no_of_pre4x16)=self.determine_predecodes(self.num_inputs)
|
||||||
|
|
@ -504,9 +506,9 @@ class hierarchical_decoder(design.design):
|
||||||
offset=vector(self.bus_pitch, 0),
|
offset=vector(self.bus_pitch, 0),
|
||||||
names=input_bus_names,
|
names=input_bus_names,
|
||||||
length=self.height)
|
length=self.height)
|
||||||
|
|
||||||
self.route_predecodes_to_bus()
|
|
||||||
self.route_bus_to_decoder()
|
self.route_bus_to_decoder()
|
||||||
|
self.route_predecodes_to_bus()
|
||||||
|
|
||||||
|
|
||||||
def route_predecodes_to_bus(self):
|
def route_predecodes_to_bus(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -521,7 +523,7 @@ class hierarchical_decoder(design.design):
|
||||||
pin = self.pre2x4_inst[pre_num].get_pin(out_name)
|
pin = self.pre2x4_inst[pre_num].get_pin(out_name)
|
||||||
x_offset = self.pre2x4_inst[pre_num].rx() + self.output_layer_pitch
|
x_offset = self.pre2x4_inst[pre_num].rx() + self.output_layer_pitch
|
||||||
y_offset = self.pre2x4_inst[pre_num].by() + i * self.cell_height
|
y_offset = self.pre2x4_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, "pre2x4")
|
||||||
|
|
||||||
# FIXME: convert to connect_bus
|
# FIXME: convert to connect_bus
|
||||||
for pre_num in range(self.no_of_pre3x8):
|
for pre_num in range(self.no_of_pre3x8):
|
||||||
|
|
@ -531,7 +533,7 @@ class hierarchical_decoder(design.design):
|
||||||
pin = self.pre3x8_inst[pre_num].get_pin(out_name)
|
pin = self.pre3x8_inst[pre_num].get_pin(out_name)
|
||||||
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, "pre3x8")
|
||||||
|
|
||||||
# FIXME: convert to connect_bus
|
# FIXME: convert to connect_bus
|
||||||
for pre_num in range(self.no_of_pre4x16):
|
for pre_num in range(self.no_of_pre4x16):
|
||||||
|
|
@ -541,7 +543,7 @@ class hierarchical_decoder(design.design):
|
||||||
pin = self.pre4x16_inst[pre_num].get_pin(out_name)
|
pin = self.pre4x16_inst[pre_num].get_pin(out_name)
|
||||||
x_offset = self.pre4x16_inst[pre_num].rx() + self.output_layer_pitch
|
x_offset = self.pre4x16_inst[pre_num].rx() + self.output_layer_pitch
|
||||||
y_offset = self.pre4x16_inst[pre_num].by() + i * self.cell_height
|
y_offset = self.pre4x16_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, "pre4x16")
|
||||||
|
|
||||||
def route_bus_to_decoder(self):
|
def route_bus_to_decoder(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -649,8 +651,9 @@ class hierarchical_decoder(design.design):
|
||||||
to_layer=self.input_layer,
|
to_layer=self.input_layer,
|
||||||
offset=pin_pos,
|
offset=pin_pos,
|
||||||
directions=("H", "H"))
|
directions=("H", "H"))
|
||||||
|
self.predecode_bus_rail_pos.append(rail_pos)
|
||||||
|
|
||||||
def route_predecode_bus_inputs(self, rail_name, pin, x_offset, y_offset):
|
def route_predecode_bus_inputs(self, rail_name, pin, x_offset, y_offset, predecode_type):
|
||||||
"""
|
"""
|
||||||
Connect the routing rail to the given metal1 pin using a jog
|
Connect the routing rail to the given metal1 pin using a jog
|
||||||
to the right of the cell at the given x_offset.
|
to the right of the cell at the given x_offset.
|
||||||
|
|
@ -661,14 +664,58 @@ class hierarchical_decoder(design.design):
|
||||||
mid_point1 = vector(x_offset, pin_pos.y)
|
mid_point1 = vector(x_offset, pin_pos.y)
|
||||||
mid_point2 = vector(x_offset, y_offset)
|
mid_point2 = vector(x_offset, y_offset)
|
||||||
rail_pos = vector(self.predecode_bus[rail_name].cx(), mid_point2.y)
|
rail_pos = vector(self.predecode_bus[rail_name].cx(), mid_point2.y)
|
||||||
self.add_path(self.output_layer, [pin_pos, mid_point1, mid_point2, rail_pos])
|
#self.add_path(self.output_layer, [pin_pos, mid_point1, mid_point2, rail_pos])
|
||||||
if layer_props.hierarchical_decoder.vertical_supply:
|
#if layer_props.hierarchical_decoder.vertical_supply:
|
||||||
above_rail = vector(self.predecode_bus[rail_name].cx(), mid_point2.y + (self.cell_height / 2))
|
# above_rail = vector(self.predecode_bus[rail_name].cx(), mid_point2.y + (self.cell_height / 2))
|
||||||
self.add_path(self.bus_layer, [rail_pos, above_rail], width=self.li_width + self.m1_enclose_mcon * 2)
|
# self.add_path(self.bus_layer, [rail_pos, above_rail], width=self.li_width + self.m1_enclose_mcon * 2)
|
||||||
|
|
||||||
|
#pin_pos = pin.center()
|
||||||
|
#rail_pos = vector(self.predecode_bus[rail_name].cx(), pin_pos.y)
|
||||||
|
#self.add_path(self.output_layer, [pin_pos, rail_pos])
|
||||||
|
|
||||||
|
# create via for dimensions
|
||||||
|
from_layer = self.output_layer
|
||||||
|
to_layer = self.bus_layer
|
||||||
|
|
||||||
|
cur_layer = from_layer
|
||||||
|
from_id = layer_indices[cur_layer]
|
||||||
|
to_id = layer_indices[to_layer]
|
||||||
|
|
||||||
|
if from_id < to_id: # grow the stack up
|
||||||
|
search_id = 0
|
||||||
|
next_id = 2
|
||||||
|
else: # grow the stack down
|
||||||
|
search_id = 2
|
||||||
|
next_id = 0
|
||||||
|
curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None)
|
||||||
|
via = factory.create(module_type="contact",
|
||||||
|
layer_stack=curr_stack,
|
||||||
|
dimensions=[1, 1],
|
||||||
|
directions=self.bus_directions)
|
||||||
|
overlapping_pin_space = getattr(self, "{}_space".format(self.output_layer))
|
||||||
|
total_buffer_space = (overlapping_pin_space + via.height)
|
||||||
|
while(True):
|
||||||
|
drc_error = 0
|
||||||
|
for and_input in self.predecode_bus_rail_pos:
|
||||||
|
if and_input.x == rail_pos.x:
|
||||||
|
if (abs(y_offset - and_input.y) < total_buffer_space) or (abs(y_offset - and_input.y) < via.height):
|
||||||
|
drc_error = 1
|
||||||
|
if drc_error == 0:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
y_offset += drc["grid"]
|
||||||
|
rail_pos.y = y_offset
|
||||||
|
|
||||||
|
if predecode_type == "pre2x4":
|
||||||
|
right_pos = pin_pos
|
||||||
|
elif predecode_type =="pre3x8":
|
||||||
|
right_pos = pin_pos
|
||||||
|
elif predecode_type == "pre4x16":
|
||||||
|
right_pos = pin_pos
|
||||||
|
# else:
|
||||||
|
# error("invalid predcoder type {}".format(predecode_type))
|
||||||
|
self.add_path(self.output_layer, [pin_pos, right_pos, vector(right_pos.x, y_offset), rail_pos])
|
||||||
|
|
||||||
# pin_pos = pin.center()
|
|
||||||
# rail_pos = vector(self.predecode_bus[rail_name].cx(), pin_pos.y)
|
|
||||||
# self.add_path(self.output_layer, [pin_pos, rail_pos])
|
|
||||||
self.add_via_stack_center(from_layer=pin.layer,
|
self.add_via_stack_center(from_layer=pin.layer,
|
||||||
to_layer=self.output_layer,
|
to_layer=self.output_layer,
|
||||||
offset=pin_pos)
|
offset=pin_pos)
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ class hierarchical_predecode(design.design):
|
||||||
self.input_rails = self.create_vertical_bus(layer=self.bus_layer,
|
self.input_rails = self.create_vertical_bus(layer=self.bus_layer,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
names=input_names,
|
names=input_names,
|
||||||
length=self.height - 2 * self.bus_pitch,
|
length=self.height - self.bus_pitch,
|
||||||
pitch=self.bus_pitch)
|
pitch=self.bus_pitch)
|
||||||
|
|
||||||
invert_names = ["Abar_{}".format(x) for x in range(self.number_of_inputs)]
|
invert_names = ["Abar_{}".format(x) for x in range(self.number_of_inputs)]
|
||||||
|
|
@ -132,7 +132,7 @@ class hierarchical_predecode(design.design):
|
||||||
self.decode_rails = self.create_vertical_bus(layer=self.bus_layer,
|
self.decode_rails = self.create_vertical_bus(layer=self.bus_layer,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
names=decode_names,
|
names=decode_names,
|
||||||
length=self.height - 2 * self.bus_pitch,
|
length=self.height - self.bus_pitch,
|
||||||
pitch=self.bus_pitch)
|
pitch=self.bus_pitch)
|
||||||
|
|
||||||
def create_input_inverters(self):
|
def create_input_inverters(self):
|
||||||
|
|
@ -195,7 +195,7 @@ class hierarchical_predecode(design.design):
|
||||||
|
|
||||||
def route_inputs_to_rails(self):
|
def route_inputs_to_rails(self):
|
||||||
""" Route the uninverted inputs to the second set of rails """
|
""" Route the uninverted inputs to the second set of rails """
|
||||||
|
|
||||||
top_and_gate = self.and_inst[-1]
|
top_and_gate = self.and_inst[-1]
|
||||||
for num in range(self.number_of_inputs):
|
for num in range(self.number_of_inputs):
|
||||||
if num == 0:
|
if num == 0:
|
||||||
|
|
@ -215,13 +215,25 @@ class hierarchical_predecode(design.design):
|
||||||
in_pos = vector(self.input_rails[in_pin].cx(), y_offset)
|
in_pos = vector(self.input_rails[in_pin].cx(), y_offset)
|
||||||
a_pos = vector(self.decode_rails[a_pin].cx(), y_offset)
|
a_pos = vector(self.decode_rails[a_pin].cx(), y_offset)
|
||||||
self.add_path(self.input_layer, [in_pos, a_pos])
|
self.add_path(self.input_layer, [in_pos, a_pos])
|
||||||
self.add_via_stack_center(from_layer=self.input_layer,
|
|
||||||
to_layer=self.bus_layer,
|
|
||||||
offset=[self.input_rails[in_pin].cx(), y_offset])
|
|
||||||
self.add_via_stack_center(from_layer=self.input_layer,
|
|
||||||
to_layer=self.bus_layer,
|
|
||||||
offset=[self.decode_rails[a_pin].cx(), y_offset])
|
|
||||||
|
|
||||||
|
if(layer_props.hierarchical_predecode.force_horizontal_input_contact):
|
||||||
|
self.add_via_stack_center(from_layer=self.input_layer,
|
||||||
|
to_layer=self.bus_layer,
|
||||||
|
offset=[self.input_rails[in_pin].cx(), y_offset],
|
||||||
|
directions= ("H", "H"))
|
||||||
|
|
||||||
|
self.add_via_stack_center(from_layer=self.input_layer,
|
||||||
|
to_layer=self.bus_layer,
|
||||||
|
offset=[self.decode_rails[a_pin].cx(), y_offset],
|
||||||
|
directions=("H", "H"))
|
||||||
|
else:
|
||||||
|
self.add_via_stack_center(from_layer=self.input_layer,
|
||||||
|
to_layer=self.bus_layer,
|
||||||
|
offset=[self.input_rails[in_pin].cx(), y_offset])
|
||||||
|
|
||||||
|
self.add_via_stack_center(from_layer=self.input_layer,
|
||||||
|
to_layer=self.bus_layer,
|
||||||
|
offset=[self.decode_rails[a_pin].cx(), y_offset])
|
||||||
def route_output_ands(self):
|
def route_output_ands(self):
|
||||||
"""
|
"""
|
||||||
Route all conections of the outputs and gates
|
Route all conections of the outputs and gates
|
||||||
|
|
@ -317,7 +329,6 @@ class hierarchical_predecode(design.design):
|
||||||
y_offset += drc["grid"]
|
y_offset += drc["grid"]
|
||||||
rail_pos.y = y_offset
|
rail_pos.y = y_offset
|
||||||
right_pos = inv_out_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(), 0)
|
right_pos = inv_out_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(), 0)
|
||||||
|
|
||||||
self.add_path(self.output_layer, [inv_out_pos, right_pos, vector(right_pos.x, y_offset), rail_pos])
|
self.add_path(self.output_layer, [inv_out_pos, right_pos, vector(right_pos.x, y_offset), rail_pos])
|
||||||
|
|
||||||
self.add_via_stack_center(from_layer=inv_out_pin.layer,
|
self.add_via_stack_center(from_layer=inv_out_pin.layer,
|
||||||
|
|
@ -332,7 +343,7 @@ class hierarchical_predecode(design.design):
|
||||||
"""
|
"""
|
||||||
Route the different permutations of the NAND/AND decocer cells.
|
Route the different permutations of the NAND/AND decocer cells.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This 2D array defines the connection mapping
|
# This 2D array defines the connection mapping
|
||||||
and_input_line_combination = self.get_and_input_line_combination()
|
and_input_line_combination = self.get_and_input_line_combination()
|
||||||
for k in range(self.number_of_outputs):
|
for k in range(self.number_of_outputs):
|
||||||
|
|
|
||||||
|
|
@ -21,24 +21,19 @@ class port_data(design.design):
|
||||||
Port 0 always has the RBL on the left while port 1 is on the right.
|
Port 0 always has the RBL on the left while port 1 is on the right.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, sram_config, port, num_spare_cols=None, bit_offsets=None, name="", rows=None, cols=None, dimension_override=False):
|
def __init__(self, sram_config, port, num_spare_cols=None, bit_offsets=None, name="",):
|
||||||
sram_config.set_local_config(self)
|
|
||||||
if dimension_override:
|
|
||||||
self.num_rows = rows
|
|
||||||
self.num_cols = cols
|
|
||||||
self.word_size = sram_config.word_size
|
|
||||||
|
|
||||||
|
sram_config.set_local_config(self)
|
||||||
self.port = port
|
self.port = port
|
||||||
if self.write_size is not None:
|
if self.write_size is not None:
|
||||||
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
|
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
|
||||||
else:
|
else:
|
||||||
self.num_wmasks = 0
|
self.num_wmasks = 0
|
||||||
|
|
||||||
if num_spare_cols:
|
if num_spare_cols is not None:
|
||||||
self.num_spare_cols = num_spare_cols
|
self.num_spare_cols = num_spare_cols + self.num_spare_cols
|
||||||
elif self.num_spare_cols is None:
|
if self.num_spare_cols is None:
|
||||||
self.num_spare_cols = 0
|
self.num_spare_cols = 0
|
||||||
|
|
||||||
if not bit_offsets:
|
if not bit_offsets:
|
||||||
bitcell = factory.create(module_type=OPTS.bitcell)
|
bitcell = factory.create(module_type=OPTS.bitcell)
|
||||||
if(cell_properties.use_strap == True and OPTS.num_ports == 1):
|
if(cell_properties.use_strap == True and OPTS.num_ports == 1):
|
||||||
|
|
@ -869,4 +864,4 @@ class port_data(design.design):
|
||||||
Clear mux exclusions to allow different bit tests.
|
Clear mux exclusions to allow different bit tests.
|
||||||
"""
|
"""
|
||||||
if self.column_mux_array:
|
if self.column_mux_array:
|
||||||
self.column_mux_array.init_graph_params()
|
self.column_mux_array.init_graph_params()
|
||||||
|
|
|
||||||
|
|
@ -238,5 +238,4 @@ class replica_column(bitcell_base_array):
|
||||||
for row, cell in enumerate(self.cell_inst):
|
for row, cell in enumerate(self.cell_inst):
|
||||||
if row != self.replica_bit:
|
if row != self.replica_bit:
|
||||||
self.graph_inst_exclude.add(cell)
|
self.graph_inst_exclude.add(cell)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,9 @@ class sram():
|
||||||
debug.print_raw("SP: Writing to {0}".format(spname))
|
debug.print_raw("SP: Writing to {0}".format(spname))
|
||||||
self.sp_write(spname)
|
self.sp_write(spname)
|
||||||
functional(self.s,
|
functional(self.s,
|
||||||
os.path.basename(spname),
|
os.path.basename(spname),
|
||||||
cycles=200,
|
cycles=200,
|
||||||
output_path=OPTS.output_path)
|
output_path=OPTS.output_path)
|
||||||
print_time("Spice writing", datetime.datetime.now(), start_time)
|
print_time("Spice writing", datetime.datetime.now(), start_time)
|
||||||
|
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ class sram_1bank(sram_base):
|
||||||
|
|
||||||
# Place with an initial wide channel (from above)
|
# Place with an initial wide channel (from above)
|
||||||
self.place_dffs()
|
self.place_dffs()
|
||||||
|
|
||||||
# Route the channel and set to the new data bus size
|
# Route the channel and set to the new data bus size
|
||||||
# We need to temporarily add some pins for the x offsets
|
# We need to temporarily add some pins for the x offsets
|
||||||
# but we'll remove them so that they have the right y
|
# but we'll remove them so that they have the right y
|
||||||
|
|
@ -110,7 +110,7 @@ class sram_1bank(sram_base):
|
||||||
self.add_layout_pins(add_vias=False)
|
self.add_layout_pins(add_vias=False)
|
||||||
self.route_dffs(add_routes=False)
|
self.route_dffs(add_routes=False)
|
||||||
self.remove_layout_pins()
|
self.remove_layout_pins()
|
||||||
|
|
||||||
# Re-place with the new channel size
|
# Re-place with the new channel size
|
||||||
self.place_dffs()
|
self.place_dffs()
|
||||||
|
|
||||||
|
|
@ -270,7 +270,7 @@ class sram_1bank(sram_base):
|
||||||
signal,
|
signal,
|
||||||
signal + "{}".format(port),
|
signal + "{}".format(port),
|
||||||
start_layer=pin_layer)
|
start_layer=pin_layer)
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
self.add_io_pin(self.data_dff_insts[port],
|
self.add_io_pin(self.data_dff_insts[port],
|
||||||
|
|
@ -303,15 +303,21 @@ class sram_1bank(sram_base):
|
||||||
self.add_io_pin(self.wmask_dff_insts[port],
|
self.add_io_pin(self.wmask_dff_insts[port],
|
||||||
"din_{}".format(bit),
|
"din_{}".format(bit),
|
||||||
"wmask{0}[{1}]".format(port, bit),
|
"wmask{0}[{1}]".format(port, bit),
|
||||||
start_layer=pin_layer)
|
start_layer=pin_layer)
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
for bit in range(self.num_spare_cols):
|
if self.num_spare_cols == 1:
|
||||||
self.add_io_pin(self.spare_wen_dff_insts[port],
|
self.add_io_pin(self.spare_wen_dff_insts[port],
|
||||||
"din_{}".format(bit),
|
"din_{}".format(0),
|
||||||
"spare_wen{0}[{1}]".format(port, bit),
|
"spare_wen{0}".format(port),
|
||||||
start_layer=pin_layer)
|
start_layer=pin_layer)
|
||||||
|
else:
|
||||||
|
for bit in range(self.num_spare_cols):
|
||||||
|
self.add_io_pin(self.spare_wen_dff_insts[port],
|
||||||
|
"din_{}".format(bit),
|
||||||
|
"spare_wen{0}[{1}]".format(port, bit),
|
||||||
|
start_layer=pin_layer)
|
||||||
|
|
||||||
def route_layout(self):
|
def route_layout(self):
|
||||||
""" Route a single bank SRAM """
|
""" Route a single bank SRAM """
|
||||||
|
|
||||||
|
|
@ -351,11 +357,11 @@ class sram_1bank(sram_base):
|
||||||
big_margin=big_margin,
|
big_margin=big_margin,
|
||||||
little_margin=little_margin)
|
little_margin=little_margin)
|
||||||
self.route_escape_pins(bbox)
|
self.route_escape_pins(bbox)
|
||||||
|
|
||||||
# Route the supplies first since the MST is not blockage aware
|
# Route the supplies first since the MST is not blockage aware
|
||||||
# and signals can route to anywhere on sides (it is flexible)
|
# and signals can route to anywhere on sides (it is flexible)
|
||||||
self.route_supplies(pre_bbox)
|
self.route_supplies(pre_bbox)
|
||||||
|
|
||||||
def route_dffs(self, add_routes=True):
|
def route_dffs(self, add_routes=True):
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
|
|
@ -371,7 +377,7 @@ class sram_1bank(sram_base):
|
||||||
self.route_data_dffs(port, add_routes)
|
self.route_data_dffs(port, add_routes)
|
||||||
|
|
||||||
def route_col_addr_dffs(self, port):
|
def route_col_addr_dffs(self, port):
|
||||||
|
|
||||||
route_map = []
|
route_map = []
|
||||||
|
|
||||||
# column mux dff is routed on it's own since it is to the far end
|
# column mux dff is routed on it's own since it is to the far end
|
||||||
|
|
@ -412,10 +418,10 @@ class sram_1bank(sram_base):
|
||||||
self.add_inst(cr.name, cr)
|
self.add_inst(cr.name, cr)
|
||||||
self.connect_inst([])
|
self.connect_inst([])
|
||||||
# self.add_flat_inst(cr.name, cr)
|
# self.add_flat_inst(cr.name, cr)
|
||||||
|
|
||||||
def route_data_dffs(self, port, add_routes):
|
def route_data_dffs(self, port, add_routes):
|
||||||
route_map = []
|
route_map = []
|
||||||
|
|
||||||
# wmask dff
|
# wmask dff
|
||||||
if self.num_wmasks > 0 and port in self.write_ports:
|
if self.num_wmasks > 0 and port in self.write_ports:
|
||||||
dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)]
|
dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)]
|
||||||
|
|
@ -450,7 +456,7 @@ class sram_1bank(sram_base):
|
||||||
y_bottom = min(0, self.control_logic_insts[port].get_pin("s_en").by())
|
y_bottom = min(0, self.control_logic_insts[port].get_pin("s_en").by())
|
||||||
else:
|
else:
|
||||||
y_bottom = 0
|
y_bottom = 0
|
||||||
|
|
||||||
y_offset = y_bottom - self.data_bus_size[port] + 2 * self.m3_pitch
|
y_offset = y_bottom - self.data_bus_size[port] + 2 * self.m3_pitch
|
||||||
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
|
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
|
||||||
y_offset)
|
y_offset)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ from design import design
|
||||||
from verilog import verilog
|
from verilog import verilog
|
||||||
from lef import lef
|
from lef import lef
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from tech import spice, layer
|
from tech import spice
|
||||||
|
|
||||||
|
|
||||||
class sram_base(design, verilog, lef):
|
class sram_base(design, verilog, lef):
|
||||||
|
|
@ -84,8 +84,11 @@ class sram_base(design, verilog, lef):
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
for bit in range(self.num_wmasks):
|
for bit in range(self.num_wmasks):
|
||||||
self.add_pin("wmask{0}[{1}]".format(port, bit), "INPUT")
|
self.add_pin("wmask{0}[{1}]".format(port, bit), "INPUT")
|
||||||
for bit in range(self.num_spare_cols):
|
if self.num_spare_cols == 1:
|
||||||
self.add_pin("spare_wen{0}[{1}]".format(port, bit), "INPUT")
|
self.add_pin("spare_wen{0}".format(port), "INPUT")
|
||||||
|
else:
|
||||||
|
for bit in range(self.num_spare_cols):
|
||||||
|
self.add_pin("spare_wen{0}[{1}]".format(port, bit), "INPUT")
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT")
|
self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT")
|
||||||
|
|
@ -246,7 +249,7 @@ class sram_base(design, verilog, lef):
|
||||||
for pin_name in ["vdd", "gnd"]:
|
for pin_name in ["vdd", "gnd"]:
|
||||||
for inst in self.insts:
|
for inst in self.insts:
|
||||||
self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name])
|
self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name])
|
||||||
|
|
||||||
if not OPTS.route_supplies:
|
if not OPTS.route_supplies:
|
||||||
# Do not route the power supply (leave as must-connect pins)
|
# Do not route the power supply (leave as must-connect pins)
|
||||||
return
|
return
|
||||||
|
|
@ -282,11 +285,11 @@ class sram_base(design, verilog, lef):
|
||||||
pin.ll(),
|
pin.ll(),
|
||||||
pin.width(),
|
pin.width(),
|
||||||
pin.height())
|
pin.height())
|
||||||
|
|
||||||
elif OPTS.route_supplies and OPTS.supply_pin_type == "single":
|
elif OPTS.route_supplies and OPTS.supply_pin_type == "single":
|
||||||
# Update these as we may have routed outside the region (perimeter pins)
|
# Update these as we may have routed outside the region (perimeter pins)
|
||||||
lowest_coord = self.find_lowest_coords()
|
lowest_coord = self.find_lowest_coords()
|
||||||
|
|
||||||
# Find the lowest leftest pin for vdd and gnd
|
# Find the lowest leftest pin for vdd and gnd
|
||||||
for pin_name in ["vdd", "gnd"]:
|
for pin_name in ["vdd", "gnd"]:
|
||||||
# Copy the pin shape(s) to rectangles
|
# Copy the pin shape(s) to rectangles
|
||||||
|
|
@ -337,7 +340,7 @@ class sram_base(design, verilog, lef):
|
||||||
pins_to_route.append("{0}{1}".format(signal, port))
|
pins_to_route.append("{0}{1}".format(signal, port))
|
||||||
else:
|
else:
|
||||||
pins_to_route.append("{0}{1}".format(signal, port))
|
pins_to_route.append("{0}{1}".format(signal, port))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
pins_to_route.append("din{0}[{1}]".format(port, bit))
|
pins_to_route.append("din{0}[{1}]".format(port, bit))
|
||||||
|
|
@ -358,8 +361,11 @@ class sram_base(design, verilog, lef):
|
||||||
pins_to_route.append("wmask{0}[{1}]".format(port, bit))
|
pins_to_route.append("wmask{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
for bit in range(self.num_spare_cols):
|
if self.num_spare_cols == 1:
|
||||||
pins_to_route.append("spare_wen{0}[{1}]".format(port, bit))
|
pins_to_route.append("spare_wen{0}".format(port))
|
||||||
|
else:
|
||||||
|
for bit in range(self.num_spare_cols):
|
||||||
|
pins_to_route.append("spare_wen{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
from signal_escape_router import signal_escape_router as router
|
from signal_escape_router import signal_escape_router as router
|
||||||
rtr=router(layers=self.m3_stack,
|
rtr=router(layers=self.m3_stack,
|
||||||
|
|
@ -547,13 +553,13 @@ class sram_base(design, verilog, lef):
|
||||||
temp.append("rbl_bl{0}".format(port))
|
temp.append("rbl_bl{0}".format(port))
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
temp.append("bank_din{0}[{1}]".format(port, bit))
|
temp.append("bank_din{0}_{1}".format(port, bit))
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
for bit in range(self.bank_addr_size):
|
for bit in range(self.bank_addr_size):
|
||||||
temp.append("a{0}[{1}]".format(port, bit))
|
temp.append("a{0}_{1}".format(port, bit))
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
temp.append("bank_sel{0}[{1}]".format(port, bank_num))
|
temp.append("bank_sel{0}_{1}".format(port, bank_num))
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
temp.append("s_en{0}".format(port))
|
temp.append("s_en{0}".format(port))
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
|
|
@ -561,9 +567,9 @@ class sram_base(design, verilog, lef):
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
temp.append("w_en{0}".format(port))
|
temp.append("w_en{0}".format(port))
|
||||||
for bit in range(self.num_wmasks):
|
for bit in range(self.num_wmasks):
|
||||||
temp.append("bank_wmask{}[{}]".format(port, bit))
|
temp.append("bank_wmask{0}_{1}".format(port, bit))
|
||||||
for bit in range(self.num_spare_cols):
|
for bit in range(self.num_spare_cols):
|
||||||
temp.append("bank_spare_wen{0}[{1}]".format(port, bit))
|
temp.append("bank_spare_wen{0}_{1}".format(port, bit))
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
temp.append("wl_en{0}".format(port))
|
temp.append("wl_en{0}".format(port))
|
||||||
temp.extend(self.ext_supplies)
|
temp.extend(self.ext_supplies)
|
||||||
|
|
@ -613,7 +619,7 @@ class sram_base(design, verilog, lef):
|
||||||
outputs = []
|
outputs = []
|
||||||
for bit in range(self.row_addr_size):
|
for bit in range(self.row_addr_size):
|
||||||
inputs.append("addr{}[{}]".format(port, bit + self.col_addr_size))
|
inputs.append("addr{}[{}]".format(port, bit + self.col_addr_size))
|
||||||
outputs.append("a{}[{}]".format(port, bit + self.col_addr_size))
|
outputs.append("a{}_{}".format(port, bit + self.col_addr_size))
|
||||||
|
|
||||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||||
|
|
||||||
|
|
@ -631,7 +637,7 @@ class sram_base(design, verilog, lef):
|
||||||
outputs = []
|
outputs = []
|
||||||
for bit in range(self.col_addr_size):
|
for bit in range(self.col_addr_size):
|
||||||
inputs.append("addr{}[{}]".format(port, bit))
|
inputs.append("addr{}[{}]".format(port, bit))
|
||||||
outputs.append("a{}[{}]".format(port, bit))
|
outputs.append("a{}_{}".format(port, bit))
|
||||||
|
|
||||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||||
|
|
||||||
|
|
@ -653,7 +659,7 @@ class sram_base(design, verilog, lef):
|
||||||
outputs = []
|
outputs = []
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
inputs.append("din{}[{}]".format(port, bit))
|
inputs.append("din{}[{}]".format(port, bit))
|
||||||
outputs.append("bank_din{}[{}]".format(port, bit))
|
outputs.append("bank_din{}_{}".format(port, bit))
|
||||||
|
|
||||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||||
|
|
||||||
|
|
@ -675,7 +681,7 @@ class sram_base(design, verilog, lef):
|
||||||
outputs = []
|
outputs = []
|
||||||
for bit in range(self.num_wmasks):
|
for bit in range(self.num_wmasks):
|
||||||
inputs.append("wmask{}[{}]".format(port, bit))
|
inputs.append("wmask{}[{}]".format(port, bit))
|
||||||
outputs.append("bank_wmask{}[{}]".format(port, bit))
|
outputs.append("bank_wmask{}_{}".format(port, bit))
|
||||||
|
|
||||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||||
|
|
||||||
|
|
@ -695,9 +701,13 @@ class sram_base(design, verilog, lef):
|
||||||
# inputs, outputs/output/bar
|
# inputs, outputs/output/bar
|
||||||
inputs = []
|
inputs = []
|
||||||
outputs = []
|
outputs = []
|
||||||
for bit in range(self.num_spare_cols):
|
if self.num_spare_cols == 1:
|
||||||
inputs.append("spare_wen{}[{}]".format(port, bit))
|
inputs.append("spare_wen{}".format(port))
|
||||||
outputs.append("bank_spare_wen{}[{}]".format(port, bit))
|
outputs.append("bank_spare_wen{}".format(port))
|
||||||
|
else:
|
||||||
|
for bit in range(self.num_spare_cols):
|
||||||
|
inputs.append("spare_wen{}[{}]".format(port, bit))
|
||||||
|
outputs.append("bank_spare_wen{}_{}".format(port, bit))
|
||||||
|
|
||||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import debug
|
||||||
from math import log, sqrt, ceil
|
from math import log, sqrt, ceil
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
from tech import array_row_multiple
|
||||||
|
from tech import array_col_multiple
|
||||||
|
|
||||||
|
|
||||||
class sram_config:
|
class sram_config:
|
||||||
|
|
@ -63,11 +65,11 @@ class sram_config:
|
||||||
|
|
||||||
self.recompute_sizes()
|
self.recompute_sizes()
|
||||||
|
|
||||||
# Set word_per_row in OPTS
|
# Set word_per_row in OPTS
|
||||||
OPTS.words_per_row = self.words_per_row
|
OPTS.words_per_row = self.words_per_row
|
||||||
debug.info(1, "Set SRAM Words Per Row={}".format(OPTS.words_per_row))
|
debug.info(1, "Set SRAM Words Per Row={}".format(OPTS.words_per_row))
|
||||||
|
|
||||||
|
|
||||||
def recompute_sizes(self):
|
def recompute_sizes(self):
|
||||||
"""
|
"""
|
||||||
Calculate the auxiliary values assuming fixed number of words per row.
|
Calculate the auxiliary values assuming fixed number of words per row.
|
||||||
|
|
@ -96,6 +98,14 @@ class sram_config:
|
||||||
+ " 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))
|
||||||
|
|
||||||
|
num_ports = OPTS.num_rw_ports + OPTS.num_r_ports + OPTS.num_w_ports
|
||||||
|
if num_ports == 1:
|
||||||
|
if ((self.num_cols + num_ports + self.num_spare_cols) % array_col_multiple != 0):
|
||||||
|
debug.error("Invalid number of cols including rbl(s): {}. Total cols must be divisible by {}".format(self.num_cols + num_ports + self.num_spare_cols, array_col_multiple), -1)
|
||||||
|
|
||||||
|
if ((self.num_rows + num_ports) % array_row_multiple != 0):
|
||||||
|
debug.error("invalid number of rows including dummy row(s): {}. Total cols must be divisible by {}".format(self.num_rows + num_ports, array_row_multiple), -1)
|
||||||
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ class hierarchical_decoder_test(openram_test):
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# Checks 3 x 4x16 and 4-input NAND decoder
|
# Checks 3 x 4x16 and 4-input NAND decoder
|
||||||
# debug.info(1, "Testing 4096 row sample for hierarchical_decoder")
|
#debug.info(1, "Testing 4096 row sample for hierarchical_decoder")
|
||||||
# a = factory.create(module_type="hierarchical_decoder", num_outputs=4096)
|
#a = factory.create(module_type="hierarchical_decoder", num_outputs=4096)
|
||||||
# self.local_check(a)
|
#self.local_check(a)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ from sram_factory import factory
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
|
|
||||||
@unittest.skip("SKIPPING 50_riscv_func_test")
|
# @unittest.skip("SKIPPING 50_riscv_func_test")
|
||||||
class riscv_func_test(openram_test):
|
class riscv_func_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
|
@ -24,7 +24,6 @@ class riscv_func_test(openram_test):
|
||||||
globals.init_openram(config_file)
|
globals.init_openram(config_file)
|
||||||
OPTS.analytical_delay = False
|
OPTS.analytical_delay = False
|
||||||
OPTS.netlist_only = True
|
OPTS.netlist_only = True
|
||||||
OPTS.local_array_size = 16
|
|
||||||
OPTS.num_rw_ports = 1
|
OPTS.num_rw_ports = 1
|
||||||
OPTS.num_w_ports = 0
|
OPTS.num_w_ports = 0
|
||||||
OPTS.num_r_ports = 1
|
OPTS.num_r_ports = 1
|
||||||
|
|
@ -38,7 +37,7 @@ class riscv_func_test(openram_test):
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=32,
|
c = sram_config(word_size=32,
|
||||||
write_size=8,
|
write_size=8,
|
||||||
num_words=256,
|
num_words=32,
|
||||||
num_banks=1)
|
num_banks=1)
|
||||||
c.words_per_row=1
|
c.words_per_row=1
|
||||||
c.recompute_sizes()
|
c.recompute_sizes()
|
||||||
|
|
@ -49,7 +48,7 @@ class riscv_func_test(openram_test):
|
||||||
c.num_banks))
|
c.num_banks))
|
||||||
s = factory.create(module_type="sram", sram_config=c)
|
s = factory.create(module_type="sram", sram_config=c)
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, corner=corner)
|
f = functional(s.s, corner=corner, cycles=50)
|
||||||
(fail, error) = f.run()
|
(fail, error) = f.run()
|
||||||
self.assertTrue(fail, error)
|
self.assertTrue(fail, error)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2021 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
|
||||||
|
|
||||||
|
|
||||||
|
# @unittest.skip("SKIPPING 50_riscv_func_test")
|
||||||
|
class riscv_func_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
OPTS.analytical_delay = False
|
||||||
|
OPTS.netlist_only = True
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
globals.setup_bitcell()
|
||||||
|
|
||||||
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
|
from importlib import reload
|
||||||
|
import characterizer
|
||||||
|
reload(characterizer)
|
||||||
|
from characterizer import functional
|
||||||
|
from sram_config import sram_config
|
||||||
|
c = sram_config(word_size=32,
|
||||||
|
write_size=8,
|
||||||
|
num_words=32,
|
||||||
|
num_banks=1)
|
||||||
|
c.words_per_row=1
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Functional test RISC-V memory"
|
||||||
|
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
||||||
|
c.num_words,
|
||||||
|
c.words_per_row,
|
||||||
|
c.num_banks))
|
||||||
|
s = factory.create(module_type="sram", sram_config=c)
|
||||||
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
|
f = functional(s.s, corner=corner, cycles=50)
|
||||||
|
(fail, error) = f.run()
|
||||||
|
self.assertTrue(fail, error)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# instantiate a copy 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())
|
||||||
|
|
@ -56,8 +56,9 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
|
||||||
// Write Operation : When web0 = 0, csb0 = 0
|
// Write Operation : When web0 = 0, csb0 = 0
|
||||||
always @ (negedge clk0)
|
always @ (negedge clk0)
|
||||||
begin : MEM_WRITE0
|
begin : MEM_WRITE0
|
||||||
if ( !csb0_reg && !web0_reg )
|
if ( !csb0_reg && !web0_reg ) begin
|
||||||
mem[addr0_reg] = din0_reg;
|
mem[addr0_reg][1:0] = din0_reg[1:0];
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// Memory Read Block Port 0
|
// Memory Read Block Port 0
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,9 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
|
||||||
// Write Operation : When web0 = 0, csb0 = 0
|
// Write Operation : When web0 = 0, csb0 = 0
|
||||||
always @ (negedge clk0)
|
always @ (negedge clk0)
|
||||||
begin : MEM_WRITE0
|
begin : MEM_WRITE0
|
||||||
if ( !csb0_reg && !web0_reg )
|
if ( !csb0_reg && !web0_reg ) begin
|
||||||
mem[addr0_reg] = din0_reg;
|
mem[addr0_reg][1:0] = din0_reg[1:0];
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// Memory Read Block Port 0
|
// Memory Read Block Port 0
|
||||||
|
|
|
||||||
|
|
@ -465,3 +465,6 @@ lvs_name = "calibre"
|
||||||
pex_name = "calibre"
|
pex_name = "calibre"
|
||||||
|
|
||||||
blackbox_bitcell = False
|
blackbox_bitcell = False
|
||||||
|
|
||||||
|
array_row_multiple = 1
|
||||||
|
array_col_multiple = 1
|
||||||
|
|
@ -305,3 +305,5 @@ pex_name = "magic"
|
||||||
###################################################
|
###################################################
|
||||||
##END Technology Tool Preferences
|
##END Technology Tool Preferences
|
||||||
###################################################
|
###################################################
|
||||||
|
array_row_multiple = 1
|
||||||
|
array_col_multiple = 1
|
||||||
|
|
@ -412,3 +412,6 @@ lvs_name = "netgen"
|
||||||
pex_name = "magic"
|
pex_name = "magic"
|
||||||
|
|
||||||
blackbox_bitcell = False
|
blackbox_bitcell = False
|
||||||
|
|
||||||
|
array_row_multiple = 1
|
||||||
|
array_col_multiple = 1
|
||||||
Loading…
Reference in New Issue