Commit f2d02647 authored by Martin Jeřábek's avatar Martin Jeřábek

allow for test randomization

parent eb13decc
...@@ -315,6 +315,8 @@ entity tb_feature is ...@@ -315,6 +315,8 @@ entity tb_feature is
-- Timeout in simulation time. 0 means no limit -- Timeout in simulation time. 0 means no limit
timeout : string := "0 ms"; timeout : string := "0 ms";
seed : natural := 0;
hw_reset_on_new_test : boolean := true; hw_reset_on_new_test : boolean := true;
test_name : string test_name : string
...@@ -360,7 +362,7 @@ architecture tb of tb_feature is ...@@ -360,7 +362,7 @@ architecture tb of tb_feature is
signal bl_force : boolean := false; signal bl_force : boolean := false;
-- test internal signals -- test internal signals
signal iteration_done : boolean; signal iteration_done : boolean := false;
signal mem_bus : mem_bus_arr_t := (OTHERS => mem_bus_init); signal mem_bus : mem_bus_arr_t := (OTHERS => mem_bus_init);
...@@ -409,10 +411,14 @@ begin ...@@ -409,10 +411,14 @@ begin
variable o : feature_outputs_t; variable o : feature_outputs_t;
begin begin
test_runner_setup(runner, runner_cfg); test_runner_setup(runner, runner_cfg);
--Set the process to run and wait until it comes out of reset --Set the process to run and wait until it comes out of reset
iteration_done <= false; iteration_done <= false;
run <= true; run <= true;
error_ctr <= 0; error_ctr <= 0;
apply_rand_seed(seed, 0, rand_ctr);
report "Restarting mem_bus(1)"; report "Restarting mem_bus(1)";
restart_mem_bus(mem_bus(1)); restart_mem_bus(mem_bus(1));
report "Restarting mem_bus(1)"; report "Restarting mem_bus(1)";
......
...@@ -73,6 +73,9 @@ use work.CAN_FD_register_map.all; ...@@ -73,6 +73,9 @@ use work.CAN_FD_register_map.all;
use work.CAN_FD_frame_format.all; use work.CAN_FD_frame_format.all;
entity sanity_test is entity sanity_test is
generic (
seed : natural := 0
);
port ( port (
-- Input trigger, test starts running when true -- Input trigger, test starts running when true
...@@ -503,15 +506,13 @@ begin ...@@ -503,15 +506,13 @@ begin
-- Clock generation -- Clock generation
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
clock_generic : for i in 1 to NODE_COUNT generate clock_generic : for i in 1 to NODE_COUNT generate
clock_gen_1 : process clock_gen_1:process
constant period : natural := f100_Mhz;
constant duty : natural := 50;
variable epsilon : natural;
begin begin
epsilon := epsilon_v(i); wait for 0 ns;
generate_clock(period, duty, epsilon, mem_aux_clk(i)); report "Epsilon:" & natural'image(epsilon_v(i));
timestamp_v(i) <= std_logic_vector(unsigned(timestamp_v(i)) + 1); clock_gen_proc(f100_mhz, 50, epsilon_v(i), mem_aux_clk(i));
end process; end process;
timestamp_gen_proc(mem_aux_clk(i), timestamp_v(i));
end generate clock_generic; end generate clock_generic;
...@@ -550,6 +551,7 @@ begin ...@@ -550,6 +551,7 @@ begin
-- 500 ps equals approximately 10 cm of conductor! This is coarse estimate, -- 500 ps equals approximately 10 cm of conductor! This is coarse estimate,
-- however purpose of this simulation is not to examine exact propagation -- however purpose of this simulation is not to examine exact propagation
-- delays via different physical channels! This simple estimate is enough. -- delays via different physical channels! This simple estimate is enough.
-- TODO: may be optimized by eschewing bus_clk and delaying the signals directly
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
bus_clk_proc : process bus_clk_proc : process
begin begin
...@@ -617,35 +619,36 @@ begin ...@@ -617,35 +619,36 @@ begin
variable gaus_par : rand_distribution_par_type; variable gaus_par : rand_distribution_par_type;
variable exp_par : rand_distribution_par_type; variable exp_par : rand_distribution_par_type;
begin begin
if (do_noise) then apply_rand_seed(seed, 0, rand_ctr);
loop
-- Generate noise pulse with gauss distribution if (do_noise) then
gaus_par(GAUSS_iterations) := real(iter_am); -- Generate noise pulse with gauss distribution
gaus_par(GAUSS_mean) := nw_mean; gaus_par(GAUSS_iterations) := real(iter_am);
gaus_par(GAUSS_variance) := nw_var; gaus_par(GAUSS_mean) := nw_mean;
rand_real_distr_v(rand_ctr, noise_time, GAUSS, gaus_par); gaus_par(GAUSS_variance) := nw_var;
rand_real_distr_v(rand_ctr, noise_time, GAUSS, gaus_par);
-- Generate noise pulse gap with exponential distribution
exp_par(EXPONENTIAL_mean) := ng_mean; -- Generate noise pulse gap with exponential distribution
rand_real_distr_v(rand_ctr, noise_gap, EXPONENTIAL, exp_par); exp_par(EXPONENTIAL_mean) := ng_mean;
rand_real_distr_v(rand_ctr, noise_gap, EXPONENTIAL, exp_par);
noise_force <= (OTHERS => '0');
wait for integer(noise_gap) * 1 ns; noise_force <= (OTHERS => '0');
wait for integer(noise_gap) * 1 ns;
--Generate noise polarity and info whether noise
-- should be forced to the node --Generate noise polarity and info whether noise
-- We cant put noise to all. That would be global -- should be forced to the node
-- error at all times -- We cant put noise to all. That would be global
rand_logic_vect_v(rand_ctr ,aux,0.5); -- error at all times
noise_reg <= aux; rand_logic_vect_v(rand_ctr ,aux,0.5);
rand_logic_vect_v(rand_ctr ,aux,0.5); noise_reg <= aux;
noise_force <= aux; rand_logic_vect_v(rand_ctr ,aux,0.5);
noise_force <= aux;
wait for integer(noise_time) * 1 ns;
wait for integer(noise_time) * 1 ns;
else else
wait for 10 ns; wait for 10 ns;
end if; end if;
end loop;
end process; end process;
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
...@@ -688,6 +691,7 @@ begin ...@@ -688,6 +691,7 @@ begin
variable fault_state : SW_fault_state; variable fault_state : SW_fault_state;
begin begin
if (do_restart_mem_if(i)) then if (do_restart_mem_if(i)) then
apply_rand_seed(seed, i, rand_ctr_gen(i));
restart_mem_bus(mb_arr(i)); restart_mem_bus(mb_arr(i));
wait for 10 ns; wait for 10 ns;
......
...@@ -73,6 +73,8 @@ entity tb_sanity is ...@@ -73,6 +73,8 @@ entity tb_sanity is
-- Timeout in simulation time. 0 means no limit. -- Timeout in simulation time. 0 means no limit.
timeout : string := "0 ms"; timeout : string := "0 ms";
seed : natural := 0;
topology : string; topology : string;
bus_len_v : string; --bus_length_type; bus_len_v : string; --bus_length_type;
trv_del_v : string; --anat_nc_t; trv_del_v : string; --anat_nc_t;
...@@ -221,6 +223,9 @@ begin ...@@ -221,6 +223,9 @@ begin
end generate; end generate;
t_sanity: entity work.sanity_test t_sanity: entity work.sanity_test
generic map (
seed => seed
)
port map ( port map (
iterations => iterations, iterations => iterations,
log_level => log_level, log_level => log_level,
......
...@@ -23,7 +23,8 @@ entity tb_{{test}} is generic ( ...@@ -23,7 +23,8 @@ entity tb_{{test}} is generic (
log_level : log_lvl_type := info_l; log_level : log_lvl_type := info_l;
error_beh : err_beh_type := quit; error_beh : err_beh_type := quit;
error_tol : natural := 0; error_tol : natural := 0;
timeout : string := "0 ms" timeout : string := "0 ms";
seed : natural := 0
); end entity; ); end entity;
architecture tb of tb_{{test}} is architecture tb of tb_{{test}} is
component vunittb_wrapper is generic ( component vunittb_wrapper is generic (
...@@ -32,7 +33,8 @@ architecture tb of tb_{{test}} is ...@@ -32,7 +33,8 @@ architecture tb of tb_{{test}} is
log_level : log_lvl_type; log_level : log_lvl_type;
error_beh : err_beh_type; error_beh : err_beh_type;
error_tol : natural; error_tol : natural;
timeout : string timeout : string;
seed : natural
); end component; ); end component;
for all:vunittb_wrapper use configuration work.tbconf_{{test}}; for all:vunittb_wrapper use configuration work.tbconf_{{test}};
begin begin
...@@ -42,7 +44,8 @@ begin ...@@ -42,7 +44,8 @@ begin
log_level => log_level, log_level => log_level,
error_beh => error_beh, error_beh => error_beh,
error_tol => error_tol, error_tol => error_tol,
timeout => timeout); timeout => timeout,
seed => seed);
end architecture; end architecture;
-- ----------------------------------------------------------------------------- -- -----------------------------------------------------------------------------
{% endfor %} {% endfor %}
...@@ -6,9 +6,11 @@ import logging ...@@ -6,9 +6,11 @@ import logging
from pathlib import Path from pathlib import Path
from jinja2 import Environment, PackageLoader from jinja2 import Environment, PackageLoader
from pprint import pprint from pprint import pprint
import random
__all__ = ['add_sources', 'add_common_sources', 'get_common_modelsim_init_files', __all__ = ['add_sources', 'add_common_sources', 'get_common_modelsim_init_files',
'add_flags', 'dict_merge', 'vhdl_serialize', 'dump_sim_options', 'TestsBase'] 'add_flags', 'dict_merge', 'vhdl_serialize', 'dump_sim_options',
'TestsBase', 'get_seed']
d = Path(abspath(__file__)).parent d = Path(abspath(__file__)).parent
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -88,6 +90,19 @@ def add_flags(ui, lib, build): ...@@ -88,6 +90,19 @@ def add_flags(ui, lib, build):
ui.set_sim_option("modelsim.init_files.after_load", modelsim_init_files) ui.set_sim_option("modelsim.init_files.after_load", modelsim_init_files)
def get_seed(cfg):
if 'seed' in cfg and 'randomize' in cfg:
log.warning('Both "seed" and "randomize" are set - seed takes precedence')
if 'seed' in cfg:
seed = cfg['seed']
elif cfg.get('randomize', False):
# only 31 bits
seed = int(random.random() * 2**31) & 0x7FFFFFFF
else:
seed = 0
return seed
def dict_merge(up, *lowers): def dict_merge(up, *lowers):
for lower in lowers: for lower in lowers:
for k, v in lower.items(): for k, v in lower.items():
......
import logging import logging
from pathlib import Path from pathlib import Path
from .test_common import add_sources, TestsBase, dict_merge, get_common_modelsim_init_files from .test_common import add_sources, TestsBase, dict_merge, \
get_common_modelsim_init_files, get_seed
from textwrap import dedent from textwrap import dedent
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -54,7 +55,8 @@ class FeatureTests(TestsBase): ...@@ -54,7 +55,8 @@ class FeatureTests(TestsBase):
'iterations' : cfg['iterations'], 'iterations' : cfg['iterations'],
'log_level' : cfg['log_level'] + '_l', 'log_level' : cfg['log_level'] + '_l',
'error_tol' : cfg['error_tolerance'], 'error_tol' : cfg['error_tolerance'],
'test_name' : name 'test_name' : name,
'seed' : get_seed(cfg)
} }
tb.add_config(name, generics=generics) tb.add_config(name, generics=generics)
......
import logging import logging
from .test_common import TestsBase, add_sources, dict_merge, vhdl_serialize from .test_common import TestsBase, add_sources, dict_merge, vhdl_serialize, \
get_seed
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -56,6 +57,7 @@ class SanityTests(TestsBase): ...@@ -56,6 +57,7 @@ class SanityTests(TestsBase):
'iterations' : cfg['iterations'], 'iterations' : cfg['iterations'],
'log_level' : cfg['log_level'] + '_l', 'log_level' : cfg['log_level'] + '_l',
'error_tol' : cfg['error_tolerance'], 'error_tol' : cfg['error_tolerance'],
'seed' : get_seed(cfg),
'topology' : cfg['topology'], 'topology' : cfg['topology'],
#'bm' : vhdl_serialize(bm), #'bm' : vhdl_serialize(bm),
'bus_len_v' : vhdl_serialize(cfg['bus_len_v']), 'bus_len_v' : vhdl_serialize(cfg['bus_len_v']),
......
import re import re
import logging import logging
from textwrap import dedent from textwrap import dedent
from .test_common import add_sources, dict_merge, TestsBase, get_common_modelsim_init_files from .test_common import add_sources, dict_merge, TestsBase, \
get_common_modelsim_init_files, get_seed
from pprint import pprint from pprint import pprint
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -18,16 +19,19 @@ class UnitTests(TestsBase): ...@@ -18,16 +19,19 @@ class UnitTests(TestsBase):
unit_tests = lib.get_test_benches('*_unit_test') unit_tests = lib.get_test_benches('*_unit_test')
for name, cfg in config['tests'].items(): for name, cfg in config['tests'].items():
dict_merge(cfg, default) dict_merge(cfg, default)
tb = lib.get_test_benches('*tb_{}_unit_test'.format(name), allow_empty=True) tb = lib.get_test_benches('*tb_{}_unit_test'.format(name),
allow_empty=True)
if not len(tb): if not len(tb):
pprint([x.name for x in unit_tests]) pprint([x.name for x in unit_tests])
raise RuntimeError('Testbench {}_unit_test does not exist (but specified in config).'.format(name)) raise RuntimeError('Testbench {}_unit_test does not exist'
+ ' (but specified in config).'.format(name))
assert len(tb) == 1 assert len(tb) == 1
tb = tb[0] tb = tb[0]
tb.set_generic('timeout', cfg['timeout']) tb.set_generic('timeout', cfg['timeout'])
tb.set_generic('iterations', cfg['iterations']) tb.set_generic('iterations', cfg['iterations'])
tb.set_generic('log_level', cfg['log_level'] + '_l') tb.set_generic('log_level', cfg['log_level'] + '_l')
tb.set_generic('error_tol', cfg['error_tolerance']) tb.set_generic('error_tol', cfg['error_tolerance'])
tb.set_generic('seed', get_seed(cfg))
# generate & set per-test modelsim tcl file # generate & set per-test modelsim tcl file
tcl = build / 'modelsim_init_{}.tcl'.format(name) tcl = build / 'modelsim_init_{}.tcl'.format(name)
......
_default: &default _default: &default
log_level: info log_level: info
error_tolerance: 0 error_tolerance: 0
# seed: 0 # optional; use to reconstruct results from randomized runs
# randomize: false
unit: unit:
default: default:
<<: *default <<: *default
......
_default: &default _default: &default
log_level: info log_level: info
error_tolerance: 0 error_tolerance: 0
randomize: true
unit: unit:
default: default:
<<: *default <<: *default
......
...@@ -65,7 +65,9 @@ entity vunittb_wrapper is ...@@ -65,7 +65,9 @@ entity vunittb_wrapper is
error_tol : natural := 0; error_tol : natural := 0;
-- Timeout in simulation time. 0 means no limit -- Timeout in simulation time. 0 means no limit
timeout : string := "0 ms" timeout : string := "0 ms";
seed : natural := 0
); );
end entity; end entity;
...@@ -75,6 +77,9 @@ architecture tb of vunittb_wrapper is ...@@ -75,6 +77,9 @@ architecture tb of vunittb_wrapper is
signal t_run : boolean; signal t_run : boolean;
begin begin
i_test: CAN_test i_test: CAN_test
generic map (
seed => seed
)
port map ( port map (
iterations => iterations, iterations => iterations,
log_level => log_level, log_level => log_level,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment