mirror of https://github.com/VLSIDA/OpenRAM.git
Initial pex sram test.
This commit is contained in:
parent
b32c123dab
commit
1e24b780bb
|
|
@ -56,8 +56,14 @@ class delay(simulation):
|
||||||
""" Create measurement names. The names themselves currently define the type of measurement """
|
""" Create measurement names. The names themselves currently define the type of measurement """
|
||||||
|
|
||||||
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
||||||
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power",
|
self.power_meas_names = ["read0_power",
|
||||||
"disabled_read0_power", "disabled_read1_power", "disabled_write0_power", "disabled_write1_power"]
|
"read1_power",
|
||||||
|
"write0_power",
|
||||||
|
"write1_power",
|
||||||
|
"disabled_read0_power",
|
||||||
|
"disabled_read1_power",
|
||||||
|
"disabled_write0_power",
|
||||||
|
"disabled_write1_power"]
|
||||||
# self.voltage_when_names = ["volt_bl", "volt_br"]
|
# self.voltage_when_names = ["volt_bl", "volt_br"]
|
||||||
# self.bitline_delay_names = ["delay_bl", "delay_br"]
|
# self.bitline_delay_names = ["delay_bl", "delay_br"]
|
||||||
|
|
||||||
|
|
@ -279,12 +285,8 @@ class delay(simulation):
|
||||||
|
|
||||||
# instantiate the sram
|
# instantiate the sram
|
||||||
self.sf.write("\n* Instantiation of the SRAM\n")
|
self.sf.write("\n* Instantiation of the SRAM\n")
|
||||||
if not OPTS.use_pex:
|
|
||||||
self.stim.inst_model(pins=self.pins,
|
self.stim.inst_model(pins=self.pins,
|
||||||
model_name=self.sram.name)
|
model_name=self.sram.name)
|
||||||
else:
|
|
||||||
self.stim.inst_sram_pex(pins=self.pins,
|
|
||||||
model_name=self.sram.name)
|
|
||||||
|
|
||||||
self.sf.write("\n* SRAM output loads\n")
|
self.sf.write("\n* SRAM output loads\n")
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
|
|
@ -320,7 +322,6 @@ class delay(simulation):
|
||||||
self.gen_data()
|
self.gen_data()
|
||||||
self.gen_addr()
|
self.gen_addr()
|
||||||
|
|
||||||
|
|
||||||
# generate control signals
|
# generate control signals
|
||||||
self.sf.write("\n* Generation of control signals\n")
|
self.sf.write("\n* Generation of control signals\n")
|
||||||
self.gen_control()
|
self.gen_control()
|
||||||
|
|
@ -465,7 +466,7 @@ class delay(simulation):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Only checking 0 value reads for now.
|
# Only checking 0 value reads for now.
|
||||||
t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]]
|
t_trig = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]]
|
||||||
|
|
||||||
return (t_trig, self.vdd_voltage, port)
|
return (t_trig, self.vdd_voltage, port)
|
||||||
|
|
||||||
|
|
@ -480,7 +481,6 @@ class delay(simulation):
|
||||||
measure_variant_inp_tuple = self.get_measure_variants(port, measure, "read")
|
measure_variant_inp_tuple = self.get_measure_variants(port, measure, "read")
|
||||||
measure.write_measure(self.stim, measure_variant_inp_tuple)
|
measure.write_measure(self.stim, measure_variant_inp_tuple)
|
||||||
|
|
||||||
|
|
||||||
def write_delay_measures_write_port(self, port):
|
def write_delay_measures_write_port(self, port):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the power results for a write port.
|
Write the measure statements to quantify the power results for a write port.
|
||||||
|
|
@ -513,7 +513,6 @@ class delay(simulation):
|
||||||
self.sf.write("* Write ports {}\n".format(write_port))
|
self.sf.write("* Write ports {}\n".format(write_port))
|
||||||
self.write_delay_measures_write_port(write_port)
|
self.write_delay_measures_write_port(write_port)
|
||||||
|
|
||||||
|
|
||||||
def write_power_measures(self):
|
def write_power_measures(self):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the leakage power only.
|
Write the measure statements to quantify the leakage power only.
|
||||||
|
|
@ -589,7 +588,6 @@ class delay(simulation):
|
||||||
feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0])
|
feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0])
|
||||||
previous_period = self.period
|
previous_period = self.period
|
||||||
|
|
||||||
|
|
||||||
# Loops through all the ports checks if the feasible period works. Everything restarts it if does not.
|
# Loops through all the ports checks if the feasible period works. Everything restarts it if does not.
|
||||||
# Write ports do not produce delays which is why they are not included here.
|
# Write ports do not produce delays which is why they are not included here.
|
||||||
i = 1
|
i = 1
|
||||||
|
|
@ -641,7 +639,6 @@ class delay(simulation):
|
||||||
debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict), 1)
|
debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict), 1)
|
||||||
result[port].update(write_port_dict)
|
result[port].update(write_port_dict)
|
||||||
|
|
||||||
|
|
||||||
for port in self.targ_read_ports:
|
for port in self.targ_read_ports:
|
||||||
# First, check that the memory has the right values at the right times
|
# First, check that the memory has the right values at the right times
|
||||||
if not self.check_bit_measures(self.read_bit_meas, port):
|
if not self.check_bit_measures(self.read_bit_meas, port):
|
||||||
|
|
@ -681,7 +678,6 @@ class delay(simulation):
|
||||||
max_delay = self.period
|
max_delay = self.period
|
||||||
return not (type(sen_val) != float or sen_val > max_delay)
|
return not (type(sen_val) != float or sen_val > max_delay)
|
||||||
|
|
||||||
|
|
||||||
def check_read_debug_measures(self, port):
|
def check_read_debug_measures(self, port):
|
||||||
"""Debug measures that indicate special conditions."""
|
"""Debug measures that indicate special conditions."""
|
||||||
|
|
||||||
|
|
@ -722,7 +718,6 @@ class delay(simulation):
|
||||||
|
|
||||||
return dout_success
|
return dout_success
|
||||||
|
|
||||||
|
|
||||||
def check_bit_measures(self, bit_measures, port):
|
def check_bit_measures(self, bit_measures, port):
|
||||||
"""
|
"""
|
||||||
Checks the measurements which represent the internal storage voltages
|
Checks the measurements which represent the internal storage voltages
|
||||||
|
|
@ -815,7 +810,8 @@ class delay(simulation):
|
||||||
|
|
||||||
delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh)
|
delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh)
|
||||||
slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl, slew_lh)
|
slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl, slew_lh)
|
||||||
half_period = self.period/2 # high-to-low delays start at neg. clk edge, so they need to be less than half_period
|
# high-to-low delays start at neg. clk edge, so they need to be less than half_period
|
||||||
|
half_period = self.period / 2
|
||||||
if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \
|
if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \
|
||||||
or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0:
|
or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0:
|
||||||
debug.info(2, "UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str,
|
debug.info(2, "UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str,
|
||||||
|
|
@ -1077,7 +1073,6 @@ class delay(simulation):
|
||||||
data_ones = "1" * self.word_size
|
data_ones = "1" * self.word_size
|
||||||
data_zeros = "0" * self.word_size
|
data_zeros = "0" * self.word_size
|
||||||
wmask_ones = "1" * self.num_wmasks
|
wmask_ones = "1" * self.num_wmasks
|
||||||
wmask_zeroes = "0" * self.num_wmasks
|
|
||||||
|
|
||||||
if self.t_current == 0:
|
if self.t_current == 0:
|
||||||
self.add_noop_all_ports("Idle cycle (no positive clock edge)")
|
self.add_noop_all_ports("Idle cycle (no positive clock edge)")
|
||||||
|
|
@ -1132,7 +1127,6 @@ class delay(simulation):
|
||||||
self.add_noop_clock_one_port(read_port)
|
self.add_noop_clock_one_port(read_port)
|
||||||
self.measure_cycles[read_port]["disabled_read1"] = len(self.cycle_times) - 1
|
self.measure_cycles[read_port]["disabled_read1"] = len(self.cycle_times) - 1
|
||||||
|
|
||||||
|
|
||||||
# This also ensures we will have a L->H transition on the next read
|
# This also ensures we will have a L->H transition on the next read
|
||||||
self.add_read("R data 0 address {} to clear dout caps".format(inverse_address),
|
self.add_read("R data 0 address {} to clear dout caps".format(inverse_address),
|
||||||
inverse_address,
|
inverse_address,
|
||||||
|
|
@ -1173,8 +1167,10 @@ class delay(simulation):
|
||||||
# Get any available read/write port in case only a single write or read ports is being characterized.
|
# Get any available read/write port in case only a single write or read ports is being characterized.
|
||||||
cur_read_port = self.get_available_port(get_read_port=True)
|
cur_read_port = self.get_available_port(get_read_port=True)
|
||||||
cur_write_port = self.get_available_port(get_read_port=False)
|
cur_write_port = self.get_available_port(get_read_port=False)
|
||||||
debug.check(cur_read_port != None, "Characterizer requires at least 1 read port")
|
debug.check(cur_read_port != None,
|
||||||
debug.check(cur_write_port != None, "Characterizer requires at least 1 write port")
|
"Characterizer requires at least 1 read port")
|
||||||
|
debug.check(cur_write_port != None,
|
||||||
|
"Characterizer requires at least 1 write port")
|
||||||
|
|
||||||
# Create test cycles for specified target ports.
|
# Create test cycles for specified target ports.
|
||||||
write_pos = 0
|
write_pos = 0
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import tech
|
||||||
import debug
|
import debug
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
||||||
|
|
@ -40,24 +39,18 @@ class stimuli():
|
||||||
debug.info(2, "Not using spice library")
|
debug.info(2, "Not using spice library")
|
||||||
self.device_models = tech.spice["fet_models"][self.process]
|
self.device_models = tech.spice["fet_models"][self.process]
|
||||||
|
|
||||||
self.sram_name = "Xsram"
|
|
||||||
|
|
||||||
def inst_sram(self, pins, inst_name):
|
|
||||||
""" Function to instatiate an SRAM subckt. """
|
|
||||||
|
|
||||||
self.sf.write("{} ".format(self.sram_name))
|
|
||||||
for pin in self.sram_pins:
|
|
||||||
self.sf.write("{0} ".format(pin))
|
|
||||||
self.sf.write("{0}\n".format(inst_name))
|
|
||||||
|
|
||||||
def inst_model(self, pins, model_name):
|
def inst_model(self, pins, model_name):
|
||||||
""" Function to instantiate a generic model with a set of pins """
|
""" Function to instantiate a generic model with a set of pins """
|
||||||
|
|
||||||
|
if OPTS.use_pex:
|
||||||
|
self.inst_pex_model(pins, model_name)
|
||||||
|
else:
|
||||||
self.sf.write("X{0} ".format(model_name))
|
self.sf.write("X{0} ".format(model_name))
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
self.sf.write("{0} ".format(pin))
|
self.sf.write("{0} ".format(pin))
|
||||||
self.sf.write("{0}\n".format(model_name))
|
self.sf.write("{0}\n".format(model_name))
|
||||||
|
|
||||||
def inst_sram_pex(self, pins, model_name):
|
def inst_pex_model(self, pins, model_name):
|
||||||
self.sf.write("X{0} ".format(model_name))
|
self.sf.write("X{0} ".format(model_name))
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
self.sf.write("{0} ".format(pin))
|
self.sf.write("{0} ".format(pin))
|
||||||
|
|
@ -77,7 +70,6 @@ class stimuli():
|
||||||
self.sf.write("bl{0}_{1} ".format(port, col))
|
self.sf.write("bl{0}_{1} ".format(port, col))
|
||||||
self.sf.write("br{0}_{1} ".format(port, col))
|
self.sf.write("br{0}_{1} ".format(port, col))
|
||||||
|
|
||||||
|
|
||||||
self.sf.write("s_en{0} ".format(bank))
|
self.sf.write("s_en{0} ".format(bank))
|
||||||
self.sf.write("{0}\n".format(model_name))
|
self.sf.write("{0}\n".format(model_name))
|
||||||
|
|
||||||
|
|
@ -94,7 +86,6 @@ class stimuli():
|
||||||
self.tx_length))
|
self.tx_length))
|
||||||
self.sf.write(".ENDS test_inv\n")
|
self.sf.write(".ENDS test_inv\n")
|
||||||
|
|
||||||
|
|
||||||
def create_buffer(self, buffer_name, size=[1, 3], beta=2.5):
|
def create_buffer(self, buffer_name, size=[1, 3], beta=2.5):
|
||||||
"""
|
"""
|
||||||
Generates buffer for top level signals (only for sim
|
Generates buffer for top level signals (only for sim
|
||||||
|
|
@ -122,8 +113,6 @@ class stimuli():
|
||||||
self.tx_length))
|
self.tx_length))
|
||||||
self.sf.write(".ENDS test_{0}\n\n".format(buffer_name))
|
self.sf.write(".ENDS test_{0}\n\n".format(buffer_name))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def gen_pulse(self, sig_name, v1, v2, offset, period, t_rise, t_fall):
|
def gen_pulse(self, sig_name, v1, v2, offset, period, t_rise, t_fall):
|
||||||
"""
|
"""
|
||||||
Generates a periodic signal with 50% duty cycle and slew rates. Period is measured
|
Generates a periodic signal with 50% duty cycle and slew rates. Period is measured
|
||||||
|
|
@ -140,7 +129,6 @@ class stimuli():
|
||||||
0.5*period-0.5*t_rise-0.5*t_fall,
|
0.5*period-0.5*t_rise-0.5*t_fall,
|
||||||
period))
|
period))
|
||||||
|
|
||||||
|
|
||||||
def gen_pwl(self, sig_name, clk_times, data_values, period, slew, setup):
|
def gen_pwl(self, sig_name, clk_times, data_values, period, slew, setup):
|
||||||
"""
|
"""
|
||||||
Generate a PWL stimulus given a signal name and data values at each period.
|
Generate a PWL stimulus given a signal name and data values at each period.
|
||||||
|
|
@ -149,7 +137,11 @@ class stimuli():
|
||||||
to the initial value.
|
to the initial value.
|
||||||
"""
|
"""
|
||||||
# the initial value is not a clock time
|
# the initial value is not a clock time
|
||||||
debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match. {0} clock values, {1} data values for {2}".format(len(clk_times), len(data_values), sig_name))
|
str = "Clock and data value lengths don't match. {0} clock values, {1} data values for {2}"
|
||||||
|
debug.check(len(clk_times)==len(data_values),
|
||||||
|
str.format(len(clk_times),
|
||||||
|
len(data_values),
|
||||||
|
sig_name))
|
||||||
|
|
||||||
# shift signal times earlier for setup time
|
# shift signal times earlier for setup time
|
||||||
times = np.array(clk_times) - setup * period
|
times = np.array(clk_times) - setup * period
|
||||||
|
|
@ -184,7 +176,6 @@ class stimuli():
|
||||||
else:
|
else:
|
||||||
debug.error("Invalid value to get an inverse of: {0}".format(value))
|
debug.error("Invalid value to get an inverse of: {0}".format(value))
|
||||||
|
|
||||||
|
|
||||||
def gen_meas_delay(self, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td):
|
def gen_meas_delay(self, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td):
|
||||||
""" Creates the .meas statement for the measurement of delay """
|
""" Creates the .meas statement for the measurement of delay """
|
||||||
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n"
|
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n"
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class sram_base(design, verilog, lef):
|
||||||
# add pex labels for bitcells
|
# add pex labels for bitcells
|
||||||
for bank_num in range(len(self.bank_insts)):
|
for bank_num in range(len(self.bank_insts)):
|
||||||
bank = self.bank_insts[bank_num]
|
bank = self.bank_insts[bank_num]
|
||||||
pex_data = bank.reverse_transformation_bitcell(bank.mod.bitcell.name)
|
pex_data = bank.reverse_transformation_bitcell(self.bitcell.name)
|
||||||
|
|
||||||
bank_offset = pex_data[0] # offset bank relative to sram
|
bank_offset = pex_data[0] # offset bank relative to sram
|
||||||
Q_offset = pex_data[1] # offset of storage relative to bank
|
Q_offset = pex_data[1] # offset of storage relative to bank
|
||||||
|
|
@ -107,7 +107,7 @@ class sram_base(design, verilog, lef):
|
||||||
bl = []
|
bl = []
|
||||||
br = []
|
br = []
|
||||||
|
|
||||||
storage_layer_name = self.bitcell.get_pin("Q").layer
|
storage_layer_name = "m1"
|
||||||
bitline_layer_name = self.bitcell.get_pin("bl").layer
|
bitline_layer_name = self.bitcell.get_pin("bl").layer
|
||||||
|
|
||||||
for cell in range(len(bank_offset)):
|
for cell in range(len(bank_offset)):
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ class openram_test(unittest.TestCase):
|
||||||
tempspice = "{0}{1}.sp".format(OPTS.openram_temp, a.name)
|
tempspice = "{0}{1}.sp".format(OPTS.openram_temp, a.name)
|
||||||
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, a.name)
|
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, a.name)
|
||||||
|
|
||||||
|
a.gds_write(tempgds)
|
||||||
|
|
||||||
import verify
|
import verify
|
||||||
result=verify.run_pex(a.name, tempgds, tempspice, output=output, final_verification=False)
|
result=verify.run_pex(a.name, tempgds, tempspice, output=output, final_verification=False)
|
||||||
if result != 0:
|
if result != 0:
|
||||||
|
|
|
||||||
|
|
@ -406,6 +406,10 @@ def write_script_pex_rule(gds_name, cell_name, output):
|
||||||
else:
|
else:
|
||||||
pre = ""
|
pre = ""
|
||||||
f.write(pre + "extract\n")
|
f.write(pre + "extract\n")
|
||||||
|
f.write(pre + "ext2sim labels on\n")
|
||||||
|
f.write(pre + "ext2sim\n")
|
||||||
|
f.write(pre + "extresist simplify off\n")
|
||||||
|
f.write(pre + "extresist all\n")
|
||||||
f.write(pre + "ext2spice hierarchy off\n")
|
f.write(pre + "ext2spice hierarchy off\n")
|
||||||
f.write(pre + "ext2spice format ngspice\n")
|
f.write(pre + "ext2spice format ngspice\n")
|
||||||
f.write(pre + "ext2spice renumber off\n")
|
f.write(pre + "ext2spice renumber off\n")
|
||||||
|
|
@ -413,6 +417,7 @@ def write_script_pex_rule(gds_name, cell_name, output):
|
||||||
f.write(pre + "ext2spice blackbox on\n")
|
f.write(pre + "ext2spice blackbox on\n")
|
||||||
f.write(pre + "ext2spice subcircuit top on\n")
|
f.write(pre + "ext2spice subcircuit top on\n")
|
||||||
f.write(pre + "ext2spice global off\n")
|
f.write(pre + "ext2spice global off\n")
|
||||||
|
f.write(pre + "ext2spice extresist on\n")
|
||||||
f.write(pre + "ext2spice {}\n".format(cell_name))
|
f.write(pre + "ext2spice {}\n".format(cell_name))
|
||||||
f.write("quit -noprompt\n")
|
f.write("quit -noprompt\n")
|
||||||
f.write("eof\n")
|
f.write("eof\n")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue