mirror of https://github.com/VLSIDA/OpenRAM.git
standalone char and func
This commit is contained in:
parent
c6485277f3
commit
db85e8ecd6
|
|
@ -59,6 +59,7 @@ class delay(simulation):
|
|||
self.set_corner(corner)
|
||||
self.create_signal_names()
|
||||
self.add_graph_exclusions()
|
||||
self.meas_id = 0
|
||||
|
||||
def create_measurement_objects(self):
|
||||
""" Create the measurements used for read and write ports """
|
||||
|
|
@ -167,7 +168,9 @@ class delay(simulation):
|
|||
|
||||
write_measures = []
|
||||
write_measures.append(self.write_lib_meas)
|
||||
write_measures.append(self.create_write_bit_measures())
|
||||
if OPTS.top_process != "memchar":
|
||||
write_measures.append(self.create_write_bit_measures())
|
||||
|
||||
return write_measures
|
||||
|
||||
def create_debug_measurement_objects(self):
|
||||
|
|
@ -265,8 +268,8 @@ class delay(simulation):
|
|||
bitline_path = bl_paths[0]
|
||||
|
||||
# Get the measures
|
||||
self.sen_path_meas = self.create_delay_path_measures(sen_path)
|
||||
self.bl_path_meas = self.create_delay_path_measures(bitline_path)
|
||||
self.sen_path_meas = self.create_delay_path_measures(sen_path, "sen")
|
||||
self.bl_path_meas = self.create_delay_path_measures(bitline_path, "bl")
|
||||
all_meas = self.sen_path_meas + self.bl_path_meas
|
||||
|
||||
# Paths could have duplicate measurements, remove them before they go to the stim file
|
||||
|
|
@ -288,7 +291,7 @@ class delay(simulation):
|
|||
|
||||
return unique_measures
|
||||
|
||||
def create_delay_path_measures(self, path):
|
||||
def create_delay_path_measures(self, path, process):
|
||||
"""Creates measurements for each net along given path."""
|
||||
|
||||
# Determine the directions (RISE/FALL) of signals
|
||||
|
|
@ -300,6 +303,8 @@ class delay(simulation):
|
|||
cur_net, next_net = path[i], path[i + 1]
|
||||
cur_dir, next_dir = path_dirs[i], path_dirs[i + 1]
|
||||
meas_name = "delay_{0}_to_{1}".format(cur_net, next_net)
|
||||
meas_name += "_" + process + "_id" + str(self.meas_id)
|
||||
self.meas_id += 1
|
||||
if i + 1 != len(path) - 1:
|
||||
path_meas.append(delay_measure(meas_name, cur_net, next_net, cur_dir, next_dir, measure_scale=1e9, has_port=False))
|
||||
else: # Make the last measurement always measure on FALL because is a read 0
|
||||
|
|
@ -1163,15 +1168,17 @@ class delay(simulation):
|
|||
loc = 0
|
||||
port_name = ''
|
||||
for port in port_iter:
|
||||
port_measure_lines.append((port_name, measure_txt[loc:port.end(0)]))
|
||||
port_measure_lines.append((port_name, measure_text[loc:port.end(0)]))
|
||||
loc = port.start(0)
|
||||
port_name = port.group(1) + port.group(2)
|
||||
|
||||
mf.close()
|
||||
# Cycle comments, not sure if i need this
|
||||
cycle_lines = port_measure_lines.pop(0)[1]
|
||||
# cycle_lines = port_measure_lines.pop(0)[1]
|
||||
# For now just recover the bit_measures and sen_and_bitline_path_measures
|
||||
self.read_meas_lists.append([])
|
||||
self.read_bit_meas = {bit_polarity.NONINVERTING: [], bit_polarity.INVERTING: []}
|
||||
self.write_bit_meas = {bit_polarity.NONINVERTING: [], bit_polarity.INVERTING: []}
|
||||
bit_measure_rule = re.compile(r"\.meas tran (v_q_a\d+_b\d+_(read|write)_(zero|one)\d+) FIND v\((.*)\) AT=(\d+(\.\d+)?)n")
|
||||
for measures in port_measure_lines:
|
||||
port_name = measures[0]
|
||||
|
|
@ -1180,43 +1187,52 @@ class delay(simulation):
|
|||
for bit_measure in bit_measure_iter:
|
||||
meas_name = bit_measure.group(1)
|
||||
read = bit_measure.group(2) == "read"
|
||||
cycle = bit_measure.group(3)
|
||||
probe = bit_measure.group(4)
|
||||
polarity = bit_polarity.NONINVERTING
|
||||
if "q_bar" in meas_name:
|
||||
polarity = bit_polarity.INVERTING
|
||||
meas = voltage_at_measure(meas_name, probe)
|
||||
if read:
|
||||
if cycle == "one":
|
||||
meas.meta_str = sram_op.READ_ONE
|
||||
else:
|
||||
meas.meta_str = sram_op.READ_ZERO
|
||||
self.read_bit_meas[polarity].append(meas)
|
||||
self.read_meas_lists[-1].append(meas)
|
||||
else:
|
||||
if cycle == "one":
|
||||
meas.meta_str = sram_op.WRITE_ONE
|
||||
else:
|
||||
meas.meta_str = sram_op.WRITE_ZERO
|
||||
self.write_bit_meas[polarity].append(meas)
|
||||
self.write_meas_lists[-1].append(meas)
|
||||
|
||||
delay_path_rule = re.compile(r"\.meas tran delay_(.*)_to_(.*) TRIG v\((.*)\) VAL=(\d+(\.\d+)?) (RISE|FALL)=(\d+) TD=(\d+(\.\d+)?)n TARG v\((.*)\) VAL=(\d+(\.\d+)?) (RISE|FALL)=(\d+) TD=(\d+(\.\d+)?)n")
|
||||
delay_path_rule = re.compile(r"\.meas tran delay_(.*)_to_(.*)_(sen|bl)_(id\d*) TRIG v\((.*)\) VAL=(\d+(\.\d+)?) (RISE|FALL)=(\d+) TD=(\d+(\.\d+)?)n TARG v\((.*)\) VAL=(\d+(\.\d+)?) (RISE|FALL)=(\d+) TD=(\d+(\.\d+)?)n")
|
||||
port = self.read_ports[0]
|
||||
sen_and_port = self.sen_name + str(port)
|
||||
bl_and_port = self.bl_name.format(port) # bl_name contains a '{}' for the port
|
||||
meas_buff = []
|
||||
self.sen_path_meas = []
|
||||
self.bl_path_meas = []
|
||||
for measures in port_measure_lines:
|
||||
port_name = measures[0]
|
||||
text = measures[1]
|
||||
delay_path_iter = delay_path_rule.finditer(text)
|
||||
for delay_path_measure in delay_path_iter:
|
||||
from_ = delay_path_measure.group(1)
|
||||
to_ = delay_path_measure.group(2)
|
||||
trig_rise = delay_path_measure.group(5)
|
||||
targ_rise = delay_path_measure.group(10)
|
||||
meas_name = "delay_{0}_to_{1}".format(from_, to_)
|
||||
path_ = delay_path_measure.group(3)
|
||||
id_ = delay_path_measure.group(4)
|
||||
trig_rise = delay_path_measure.group(8)
|
||||
targ_rise = delay_path_measure.group(15)
|
||||
meas_name = "delay_{0}_to_{1}_{2}_{3}".format(from_, to_, path_, id_)
|
||||
meas = delay_measure(meas_name, from_, to_, trig_rise, targ_rise, measure_scale=1e9, has_port=False)
|
||||
meas.meta_str = sram_op.READ_ZERO
|
||||
meas.meta_add_delay = True
|
||||
meas_buff.append(meas)
|
||||
# TODO: we are losing duplicate measures here
|
||||
if from_ == sen_and_port:
|
||||
if path_ == "sen":
|
||||
self.sen_path_meas.extend(meas_buff.copy())
|
||||
meas_buff.clear()
|
||||
elif from_ == bl_and_port:
|
||||
self.bl_path_meas.extend(meas_buff)
|
||||
elif path_ == "bl":
|
||||
self.bl_path_meas.extend(meas_buff.copy())
|
||||
meas_buff.clear()
|
||||
self.read_meas_lists.append(self.sen_path_meas + self.bl_path_meas)
|
||||
|
||||
|
|
@ -1229,9 +1245,9 @@ class delay(simulation):
|
|||
self.prepare_netlist()
|
||||
if OPTS.top_process == "memchar":
|
||||
# TODO: fix
|
||||
self.bl_name = "xsram.xbank0.bl_0_{}"
|
||||
self.br_name = "xsram.xbank0.br_0_{}"
|
||||
self.sen_name = "xsram.s_en"
|
||||
self.bl_name = "xsram:xbank0:bl_0_{}"
|
||||
self.br_name = "xsram:xbank0:br_0_{}"
|
||||
self.sen_name = "xsram:s_en"
|
||||
self.create_measurement_objects()
|
||||
self.recover_measurment_objects()
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from .stimuli import *
|
|||
from .charutils import *
|
||||
from globals import OPTS
|
||||
from .simulation import simulation
|
||||
from .measurements import voltage_at_measure
|
||||
|
||||
|
||||
class functional(simulation):
|
||||
|
|
@ -78,9 +79,12 @@ class functional(simulation):
|
|||
self.wordline_row = 0
|
||||
self.bitline_column = 0
|
||||
self.create_signal_names()
|
||||
self.add_graph_exclusions()
|
||||
self.create_graph()
|
||||
self.set_internal_spice_names()
|
||||
#self.add_graph_exclusions()
|
||||
#self.create_graph()
|
||||
#self.set_internal_spice_names()
|
||||
self.bl_name = "xsram:xbank0:bl_0_{}"
|
||||
self.br_name = "xsram:xbank0:br_0_{}"
|
||||
self.sen_name = "xsram:s_en"
|
||||
self.q_name, self.qbar_name = self.get_bit_name()
|
||||
debug.info(2, "q:\t\t{0}".format(self.q_name))
|
||||
debug.info(2, "qbar:\t{0}".format(self.qbar_name))
|
||||
|
|
@ -275,7 +279,8 @@ class functional(simulation):
|
|||
sp_read_value = ""
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
measure_name = "v{0}_{1}ck{2}".format(dout_port.lower(), bit, cycle)
|
||||
value = parse_spice_list("timing", measure_name)
|
||||
# value = parse_spice_list("timing", measure_name)
|
||||
value = self.measures[measure_name].retrieve_measure(port=0)
|
||||
# FIXME: Ignore the spare columns for now
|
||||
if bit >= self.word_size:
|
||||
value = 0
|
||||
|
|
@ -473,6 +478,7 @@ class functional(simulation):
|
|||
|
||||
# Generate dout value measurements
|
||||
self.sf.write("\n * Generation of dout measurements\n")
|
||||
self.measures = {}
|
||||
|
||||
for (word, dout_port, eo_period, cycle) in self.read_check:
|
||||
t_initial = eo_period
|
||||
|
|
@ -480,7 +486,7 @@ class functional(simulation):
|
|||
num_bits = self.word_size + self.num_spare_cols
|
||||
for bit in range(num_bits):
|
||||
signal_name = "{0}_{1}".format(dout_port, bit)
|
||||
measure_name = "V{0}ck{1}".format(signal_name, cycle)
|
||||
measure_name = "v{0}ck{1}".format(signal_name, cycle)
|
||||
voltage_value = self.stim.get_voltage(word[num_bits - bit - 1])
|
||||
|
||||
self.stim.add_comment("* CHECK {0} {1} = {2} time = {3}".format(signal_name,
|
||||
|
|
@ -488,10 +494,13 @@ class functional(simulation):
|
|||
voltage_value,
|
||||
eo_period))
|
||||
# TODO: Convert to measurement statement instead of stimuli
|
||||
self.stim.gen_meas_value(meas_name=measure_name,
|
||||
dout=signal_name,
|
||||
t_initial=t_initial,
|
||||
t_final=t_final)
|
||||
meas = voltage_at_measure(measure_name, signal_name)
|
||||
self.measures[measure_name] = meas
|
||||
meas.write_measure(self.stim, ((t_initial + t_final) / 2, 0))
|
||||
# self.stim.gen_meas_value(meas_name=measure_name,
|
||||
# dout=signal_name,
|
||||
# t_initial=t_initial,
|
||||
# t_final=t_final)
|
||||
|
||||
self.stim.write_control(self.cycle_times[-1] + self.period)
|
||||
self.sf.close()
|
||||
|
|
@ -499,10 +508,13 @@ class functional(simulation):
|
|||
# FIXME: Similar function to delay.py, refactor this
|
||||
def get_bit_name(self):
|
||||
""" Get a bit cell name """
|
||||
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0)
|
||||
storage_names = cell_inst.mod.get_storage_net_names()
|
||||
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
|
||||
"supported for characterization. Storage nets={0}").format(storage_names))
|
||||
# TODO: Find a way to get the cell_name and storage_names statically
|
||||
# (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0)
|
||||
# storage_names = cell_inst.mod.get_storage_net_names()
|
||||
# debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
|
||||
# "supported for characterization. Storage nets={0}").format(storage_names))
|
||||
cell_name = "xsram:xbank0:xbitcell_array:xbitcell_array:xbit_r0_c0"
|
||||
storage_names = ("Q", "Q_bar")
|
||||
q_name = cell_name + OPTS.hier_seperator + str(storage_names[0])
|
||||
qbar_name = cell_name + OPTS.hier_seperator + str(storage_names[1])
|
||||
|
||||
|
|
|
|||
|
|
@ -173,9 +173,14 @@ class sram():
|
|||
|
||||
# Characterize the design
|
||||
start_time = datetime.datetime.now()
|
||||
from characterizer import lib
|
||||
debug.print_raw("LIB: Characterizing... ")
|
||||
lib(out_dir=OPTS.output_path, sram=self.s, sp_file=self.get_sp_name())
|
||||
from characterizer import delay
|
||||
debug.print_raw("LIB: Writing Analysis File... ")
|
||||
d = delay(self, self.get_sp_name(), ("TT", 5, 25))
|
||||
if (self.sram.num_spare_rows == 0):
|
||||
probe_address = "1" * self.sram.addr_size
|
||||
else:
|
||||
probe_address = "0" + "1" * (self.sram.addr_size - 1)
|
||||
d.analysis_init(probe_address, probe_data)
|
||||
print_time("Characterization", datetime.datetime.now(), start_time)
|
||||
|
||||
# Write the config file
|
||||
|
|
|
|||
|
|
@ -39,11 +39,6 @@ class sram_config:
|
|||
except ImportError:
|
||||
self.array_col_multiple = 1
|
||||
|
||||
if self.write_size:
|
||||
self.num_wmasks = int(ceil(self.word_size / self.write_size))
|
||||
else:
|
||||
self.num_wmasks = 0
|
||||
|
||||
if not self.num_spare_cols:
|
||||
self.num_spare_cols = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -44,27 +44,29 @@ init_openram(config_file=config_file, is_unit_test=False)
|
|||
print_banner()
|
||||
|
||||
# Configure the SRAM organization (duplicated from openram.py)
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
write_size=OPTS.write_size,
|
||||
num_banks=OPTS.num_banks,
|
||||
words_per_row=OPTS.words_per_row,
|
||||
num_spare_rows=OPTS.num_spare_rows,
|
||||
num_spare_cols=OPTS.num_spare_cols)
|
||||
#from sram_config import sram_config
|
||||
from characterizer.fake_sram import fake_sram
|
||||
s = fake_sram(name=OPTS.output_name,
|
||||
word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
write_size=OPTS.write_size,
|
||||
num_banks=OPTS.num_banks,
|
||||
words_per_row=OPTS.words_per_row,
|
||||
num_spare_rows=OPTS.num_spare_rows,
|
||||
num_spare_cols=OPTS.num_spare_cols)
|
||||
|
||||
s.parse_html(OPTS.output_path + "sram.html")
|
||||
s.generate_pins()
|
||||
s.setup_multiport_constants()
|
||||
|
||||
OPTS.netlist_only = True
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
# Initialize and create the sram object
|
||||
from sram import sram
|
||||
s = sram(name=OPTS.output_name, sram_config=c)
|
||||
|
||||
# Generate stimulus and run functional simulation on the design
|
||||
start_time = datetime.datetime.now()
|
||||
from characterizer import functional
|
||||
debug.print_raw("Functional simulation... ")
|
||||
f = functional(s.s, cycles=cycles, spfile=s.get_sp_name(), period=period, output_path=OPTS.openram_temp)
|
||||
f = functional(s, cycles=cycles, spfile=OPTS.output_path + OPTS.output_name + ".sp", period=period, output_path=OPTS.openram_temp)
|
||||
(fail, error) = f.run()
|
||||
debug.print_raw(error)
|
||||
print_time("Functional simulation", datetime.datetime.now(), start_time)
|
||||
Loading…
Reference in New Issue