Merge remote-tracking branch 'origin/dev' into rbl_revamp

This commit is contained in:
mrg
2019-07-12 11:10:07 -07:00
20 changed files with 772 additions and 143 deletions
@@ -34,19 +34,19 @@ class control_logic_test(openram_test):
OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="rw")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, write_size=8, port_type="rw")
self.local_check(a)
# OPTS.num_rw_ports = 0
# OPTS.num_w_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="w")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, write_size=8, port_type="w")
self.local_check(a)
# OPTS.num_w_ports = 0
# OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="r")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, write_size=8, port_type="r")
self.local_check(a)
globals.end_openram()
+1 -1
View File
@@ -24,7 +24,7 @@ class control_logic_test(openram_test):
# check control logic for single port
debug.info(1, "Testing sample for control_logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32)
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32, write_size=32)
self.local_check(a)
# run the test from the command line
+135
View File
@@ -0,0 +1,135 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California
# All rights reserved.
#
"""
Run regression tests/pex test on an extracted pinv to ensure pex functionality
with HSPICE.
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class hspice_pex_pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import pinv
# load the hspice
OPTS.spice_name="hspice"
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
# generate the pinv
prev_purge_value = OPTS.purge_temp
OPTS.purge_temp = False # force set purge to false to save the sp file
debug.info(2, "Checking 1x size inverter")
tx = pinv.pinv(name="pinv", size=1)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name)
tx.gds_write(tempgds)
tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name)
tx.sp_write(tempsp)
# make sure that the library simulation is successful\
sp_delay = self.simulate_delay(test_module = tempsp,
top_level_name = tx.name)
if sp_delay is "Failed":
self.fail('Library Spice module did not behave as expected')
# now generate its pex file
pex_file = self.run_pex(tx)
OPTS.purge_temp = prev_purge_value # restore the old purge value
# generate simulation for pex, make sure the simulation is successful
pex_delay = self.simulate_delay(test_module = pex_file,
top_level_name = tx.name)
# make sure the extracted spice simulated
if pex_delay is "Failed":
self.fail('Pex file did not behave as expected')
# if pex data is bigger than original spice file then result is ok
# However this may not always be true depending on the netlist provided
# comment out for now
#debug.info(2,"pex_delay: {0}".format(pex_delay))
#debug.info(2,"sp_delay: {0}".format(sp_delay))
#assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\
#.format(pex_delay,sp_delay)
globals.end_openram()
def simulate_delay(self, test_module, top_level_name):
from characterizer import charutils
from charutils import parse_spice_list
# setup simulation
sim_file = OPTS.openram_temp + "stim.sp"
log_file_name = "timing"
test_sim = self.write_simulation(sim_file, test_module, top_level_name)
test_sim.run_sim()
delay = parse_spice_list(log_file_name, "pinv_delay")
return delay
def write_simulation(self, sim_file, cir_file, top_module_name):
""" write pex spice simulation for a pinv test"""
import tech
from characterizer import measurements, stimuli
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
sim_file = open(sim_file, "w")
simulation = stimuli(sim_file,corner)
# library files
simulation.write_include(cir_file)
# supply voltages
simulation.gen_constant(sig_name ="vdd",
v_val = tech.spice["nom_supply_voltage"])
simulation.gen_constant(sig_name = "gnd",
v_val = "0v")
run_time = tech.spice["feasible_period"] * 4
# input voltage
clk_period = tech.spice["feasible_period"]
simulation.gen_pwl(sig_name ="input",
clk_times = [clk_period,clk_period],
data_values = [1,0],
period = clk_period,
slew = 0.001*tech.spice["feasible_period"],
setup = 0)
# instantiation of simulated pinv
simulation.inst_model(pins = ["input", "output", "vdd", "gnd"],
model_name = top_module_name)
# delay measurement
delay_measure = measurements.delay_measure(measure_name = "pinv_delay",
trig_name = "input",
targ_name = "output",
trig_dir_str = "FALL",
targ_dir_str = "RISE",
has_port = False)
trig_td = trag_td = 0.01 * run_time
rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"]
delay_measure.write_measure(simulation, rest_info)
simulation.write_control(end_time = run_time)
sim_file.close()
return simulation
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
+137
View File
@@ -0,0 +1,137 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California
# All rights reserved.
#
"""
Run regression tests/pex test on an extracted pinv to ensure pex functionality
with Ngspice.
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class ngspice_pex_pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import pinv
# load the ngspice
OPTS.spice_name="ngspice"
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
# generate the pinv module
prev_purge_value = OPTS.purge_temp
OPTS.purge_temp = False # force set purge to false to save the sp file
debug.info(2, "Checking 1x size inverter")
tx = pinv.pinv(name="pinv", size=1)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name)
tx.gds_write(tempgds)
tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name)
tx.sp_write(tempsp)
# make sure that the library simulation is successful
sp_delay = self.simulate_delay(test_module = tempsp,
top_level_name = tx.name)
if sp_delay is "Failed":
self.fail('Library Spice module did not behave as expected')
# now generate its pex file
pex_file = self.run_pex(tx)
OPTS.purge_temp = prev_purge_value # restore the old purge value
# generate simulation for pex, make sure the simulation is successful
pex_delay = self.simulate_delay(test_module = pex_file,
top_level_name = tx.name)
# make sure the extracted spice simulated
if pex_delay is "Failed":
self.fail('Pex file did not behave as expected')
# if pex data is bigger than original spice file then result is ok
# However this may not always be true depending on the netlist provided
# comment out for now
#debug.info(2,"pex_delay: {0}".format(pex_delay))
#debug.info(2,"sp_delay: {0}".format(sp_delay))
#assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\
#.format(pex_delay,sp_delay)
globals.end_openram()
def simulate_delay(self, test_module, top_level_name):
from characterizer import charutils
from charutils import parse_spice_list
# setup simulation
sim_file = OPTS.openram_temp + "stim.sp"
log_file_name = "timing"
test_sim = self.write_simulation(sim_file, test_module, top_level_name)
test_sim.run_sim()
delay = parse_spice_list(log_file_name, "pinv_delay")
return delay
def write_simulation(self, sim_file, cir_file, top_module_name):
""" write pex spice simulation for a pinv test"""
import tech
from characterizer import measurements, stimuli
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
sim_file = open(sim_file, "w")
simulation = stimuli(sim_file,corner)
# library files
simulation.write_include(cir_file)
# supply voltages
simulation.gen_constant(sig_name ="vdd",
v_val = tech.spice["nom_supply_voltage"])
# The scn4m_subm and ngspice combination will have a gnd source error:
# "Fatal error: instance vgnd is a shorted VSRC"
# However, remove gnd power for all techa pass for this test
# simulation.gen_constant(sig_name = "gnd",
# v_val = "0v")
run_time = tech.spice["feasible_period"] * 4
# input voltage
clk_period = tech.spice["feasible_period"]
simulation.gen_pwl(sig_name ="input",
clk_times = [clk_period,clk_period],
data_values = [1,0],
period = clk_period,
slew = 0.001*tech.spice["feasible_period"],
setup = 0)
# instantiation of simulated pinv
simulation.inst_model(pins = ["input", "output", "vdd", "gnd"],
model_name = top_module_name)
# delay measurement
delay_measure = measurements.delay_measure(measure_name = "pinv_delay",
trig_name = "input",
targ_name = "output",
trig_dir_str = "FALL",
targ_dir_str = "RISE",
has_port = False)
trig_td = trag_td = 0.01 * run_time
rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"]
delay_measure.write_measure(simulation, rest_info)
simulation.write_control(end_time = run_time)
sim_file.close()
return simulation
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
+110
View File
@@ -0,0 +1,110 @@
`define assert(signal, value) \
if (!(signal === value)) begin \
$display("ASSERTION FAILED in %m: signal != value"); \
$finish;\
end
module sram_1rw_wmask_tb;
reg clk;
reg [3:0] addr0;
reg [1:0] din0;
reg csb0;
reg web0;
reg [1:0] wmask0;
wire [1:0] dout0;
sram_2b_16_1rw_freepdk45 U0 (.DIN0(din0),
.DOUT0(dout0),
.ADDR0(addr0),
.csb0(csb0),
.web0(web0),
.wmask0(wmask0),
.clk0(clk)
);
initial
begin
//$monitor("%g addr0=%b din0=%b dout0=%b",
// $time, addr0, din0, dout0);
clk = 1;
csb0 = 1;
web0 = 1;
wmask0 = 2'b01;
addr0 = 0;
din0 = 0;
// write
#10 din0=2'b10;
addr0=4'h1;
web0 = 0;
csb0 = 0;
wmask0 = 2'b10;
// read
#10 din0=2'b11;
addr0=4'h1;
web0 = 1;
csb0 = 0;
#10 `assert(dout0, 2'b1x)
// write another
#10 din0=2'b01;
addr0=4'hC;
web0 = 0;
csb0 = 0;
wmask0 = 2'b01;
// read undefined
#10 din0=2'b11;
addr0=4'h0;
web0 = 1;
csb0 = 0;
wmask0 = 2'b01;
#10 `assert(dout0, 2'bxx)
// read defined
din0=2'b11;
addr0=4'hC;
web0 = 1;
csb0 = 0;
wmask0 = 2'b01;
#10 `assert(dout0, 2'bx1)
// write another
din0=2'b01;
addr0=4'h1;
web0 = 0;
csb0 = 0;
// read defined
#10 din0=2'b11;
addr0=4'h1;
web0 = 1;
csb0 = 0;
#10 `assert(dout0, 2'b11)
// read undefined
din0=2'b11;
addr0=4'h0;
web0 = 1;
csb0 = 0;
#10 `assert(dout0, 2'bxx)
#10 $finish;
end
always
#5 clk = !clk;
endmodule
+38 -25
View File
@@ -16,7 +16,7 @@ import debug
class openram_test(unittest.TestCase):
""" Base unit test that we have some shared classes in. """
def local_drc_check(self, w):
self.reset()
@@ -31,11 +31,11 @@ class openram_test(unittest.TestCase):
if OPTS.purge_temp:
self.cleanup()
def local_check(self, a, final_verification=False):
self.reset()
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name)
@@ -52,7 +52,7 @@ class openram_test(unittest.TestCase):
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
self.fail("DRC failed: {}".format(a.name))
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification)
if result != 0:
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
@@ -64,7 +64,18 @@ class openram_test(unittest.TestCase):
#import pdb; pdb.set_trace()
if OPTS.purge_temp:
self.cleanup()
def run_pex(self, a, output=None):
if output == None:
output = OPTS.openram_temp + a.name + ".pex.netlist"
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name)
import verify
result=verify.run_pex(a.name, tempgds, tempspice, output=output, final_verification=False)
if result != 0:
self.fail("PEX ERROR: {}".format(a.name))
return output
def find_feasible_test_period(self, delay_obj, sram, load, slew):
"""Creates a delay simulation to determine a feasible period for the functional tests to run.
@@ -74,19 +85,19 @@ class openram_test(unittest.TestCase):
delay_obj.set_load_slew(load, slew)
test_port = delay_obj.read_ports[0] #Only test one port, assumes other ports have similar period.
delay_obj.analysis_init(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1))
delay_obj.find_feasible_period_one_port(test_port)
return delay_obj.period
delay_obj.find_feasible_period_one_port(test_port)
return delay_obj.period
def cleanup(self):
""" Reset the duplicate checker and cleanup files. """
files = glob.glob(OPTS.openram_temp + '*')
for f in files:
# Only remove the files
if os.path.isfile(f):
os.remove(f)
os.remove(f)
def reset(self):
"""
"""
Reset everything after each test.
"""
# Reset the static duplicate name checker for unit tests.
@@ -115,7 +126,7 @@ class openram_test(unittest.TestCase):
data_string=pprint.pformat(data)
debug.error("Results exceeded {:.1f}% tolerance compared to golden results:\n".format(error_tolerance*100)+data_string)
return data_matches
def isclose(self,key,value,actual_value,error_tolerance=1e-2):
@@ -131,7 +142,7 @@ class openram_test(unittest.TestCase):
return False
def relative_diff(self, value1, value2):
""" Compute the relative difference of two values and normalize to the largest.
""" Compute the relative difference of two values and normalize to the largest.
If largest value is 0, just return the difference."""
# Edge case to avoid divide by zero
@@ -147,7 +158,7 @@ class openram_test(unittest.TestCase):
# Edge case where greater is a zero
if norm_value == 0:
min_value = abs(min(value1, value2))
return abs(value1 - value2) / norm_value
@@ -161,15 +172,15 @@ class openram_test(unittest.TestCase):
"""Compare two files.
Arguments:
filename1 -- First file name
filename2 -- Second file name
Return value:
True if the files are the same, False otherwise.
"""
import re
import debug
@@ -202,7 +213,7 @@ class openram_test(unittest.TestCase):
debug.info(3,"line1_floats: "+str(line1_floats))
debug.info(3,"line2_floats: "+str(line2_floats))
# 2. Remove the floats from the string
for f in line1_floats:
line1=line1.replace(f,"",1)
@@ -214,10 +225,10 @@ class openram_test(unittest.TestCase):
# 3. Convert to floats rather than strings
line1_floats = [float(x) for x in line1_floats]
line2_floats = [float(x) for x in line1_floats]
# 4. Check if remaining string matches
if line1 != line2:
#Uncomment if you want to see all the individual chars of the two lines
#Uncomment if you want to see all the individual chars of the two lines
#print(str([i for i in line1]))
#print(str([i for i in line2]))
if mismatches==0:
@@ -280,13 +291,13 @@ class openram_test(unittest.TestCase):
debug.info(2,"MATCH {0} {1}".format(filename1,filename2))
return True
def header(filename, technology):
# Skip the header for gitlab regression
import getpass
if getpass.getuser() == "gitlab-runner":
return
tst = "Running Test for:"
print("\n")
print(" ______________________________________________________________________________ ")
@@ -300,16 +311,18 @@ def header(filename, technology):
def debugTestRunner(post_mortem=None):
"""unittest runner doing post mortem debugging on failing tests"""
if post_mortem is None:
if post_mortem is None and not OPTS.purge_temp:
post_mortem = pdb.post_mortem
class DebugTestResult(unittest.TextTestResult):
def addError(self, test, err):
# called before tearDown()
traceback.print_exception(*err)
post_mortem(err[2])
if post_mortem:
post_mortem(err[2])
super(DebugTestResult, self).addError(test, err)
def addFailure(self, test, err):
traceback.print_exception(*err)
post_mortem(err[2])
if post_mortem:
post_mortem(err[2])
super(DebugTestResult, self).addFailure(test, err)
return unittest.TextTestRunner(resultclass=DebugTestResult)