Commit 1a4f47bb authored by CI's avatar CI

Simple cleanup and README added

parent 45518da1
Pipeline #3602 passed with stage
in 27 minutes and 52 seconds
...@@ -51,13 +51,13 @@ begin ...@@ -51,13 +51,13 @@ begin
assert g_CLOCK_EDGE = "positive" or g_CLOCK_EDGE = "negative" severity FAILURE; assert g_CLOCK_EDGE = "positive" or g_CLOCK_EDGE = "negative" severity FAILURE;
gen_pos_pulse : if g_PULSE_EDGE = "positive" generate gen_pos_pulse : if g_PULSE_EDGE = "positive" generate
pulse_o <= data_i and not dff; pulse_o <= data_i and not dff;
end generate gen_pos_pulse; end generate gen_pos_pulse;
gen_neg_pulse : if g_PULSE_EDGE = "negative" generate gen_neg_pulse : if g_PULSE_EDGE = "negative" generate
pulse_o <= not data_i and dff; pulse_o <= not data_i and dff;
end generate gen_neg_pulse; end generate gen_neg_pulse;
gen_async_rst : if g_ASYNC_RST = TRUE generate gen_async_rst : if g_ASYNC_RST = TRUE generate
sync_posedge : if g_CLOCK_EDGE = "positive" generate sync_posedge : if g_CLOCK_EDGE = "positive" generate
......
This is a simple testbench which uses GHDL simulator and OSVVM verification methodology. The goal is to verify the functionality of the gc_negedge (a simple falling edge detector). Through OSVVM, we can achieve randomization of the input data, with randomized seed value. The test cases of the testbench are defined through the different values assigned to the entity's generics.
The generics of this core are the following:
- g_async_rst : Synchronous or asynchronous reset
- g_clock_edge : Clock edge sensitivity of edge detection
Regarding on the values of the above generics, there are the following test cases:
1. TRUE, positive
2. TRUE, negative
3. FALSE, positive
4. FALSE, negative
Assertions are used to provide a self-checking approach. These are:
- The width of the output pulse is always one clock cycle long
- To always detect a negative edge of a falling input data signal
Coverage that is being covered:
- Reset has been asserted
- Input pulse detected
- Output pulse detected
Note: The values of the two last coverage bins are different because the input signal width is not always one clock cycle long
#!/bin/bash #!/bin/bash
#This is a simple script to run simulations #This is a simple script to run simulations in GHDL
#in GHDL
TB=tb_gc_negedge TB=tb_gc_negedge
echo "Running simulation for $TB" echo "Running simulation for $TB"
echo " TEST CASE 1 "
echo "ASYNC_RST=TRUE, CLOCK_EDGE=positive" echo "ASYNC_RST=TRUE, CLOCK_EDGE=positive"
ghdl -r --std=08 -frelaxed-rules $TB -gg_ASYNC_RST=TRUE -gg_CLOCK_EDGE=positive ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_ASYNC_RST=TRUE -gg_CLOCK_EDGE=positive
echo "******************************************************************************************"
echo " TEST CASE 2 "
echo "ASYNC_RST=TRUE, CLOCK_EDGE=negative" echo "ASYNC_RST=TRUE, CLOCK_EDGE=negative"
ghdl -r --std=08 -frelaxed-rules $TB -gg_ASYNC_RST=TRUE -gg_CLOCK_EDGE=negative ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_ASYNC_RST=TRUE -gg_CLOCK_EDGE=negative
echo "******************************************************************************************"
echo " TEST CASE 3 "
echo "ASYNC_RST=FALSE, CLOCK_EDGE=positive" echo "ASYNC_RST=FALSE, CLOCK_EDGE=positive"
ghdl -r --std=08 -frelaxed-rules $TB -gg_ASYNC_RST=FALSE -gg_CLOCK_EDGE=positive ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_ASYNC_RST=FALSE -gg_CLOCK_EDGE=positive
echo "******************************************************************************************"
echo " TEST CASE 4 "
echo "ASYNC_RST=FALSE, CLOCK_EDGE=negative" echo "ASYNC_RST=FALSE, CLOCK_EDGE=negative"
ghdl -r --std=08 -frelaxed-rules $TB -gg_ASYNC_RST=FALSE -gg_CLOCK_EDGE=negative ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_ASYNC_RST=FALSE -gg_CLOCK_EDGE=negative
echo "******************************************************************************************"
...@@ -28,141 +28,130 @@ library ieee; ...@@ -28,141 +28,130 @@ library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library -- OSVVM library
library osvvm; library osvvm;
use osvvm.RandomPkg.all; use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all; use osvvm.CoveragePkg.all;
entity tb_gc_negedge is entity tb_gc_negedge is
generic ( generic (
g_ASYNC_RST : boolean := FALSE; g_seed : natural;
g_CLOCK_EDGE : string := "positive"); g_ASYNC_RST : boolean := FALSE;
g_CLOCK_EDGE : string := "positive");
end entity; end entity;
architecture tb of tb_gc_negedge is architecture tb of tb_gc_negedge is
-- Constants
constant C_CLK_PERIOD : time := 10 ns;
-- Signals
signal tb_clk_i : std_logic;
signal tb_rst_n_i : std_logic;
signal tb_data_i : std_logic := '0';
signal tb_pulse_o : std_logic;
signal stop : boolean; -- Constants
constant C_CLK_PERIOD : time := 10 ns;
-- Variables used for coverage
shared variable cp_rst_i : covPType; -- Signals
shared variable cp_data_i : covPType; signal tb_clk_i : std_logic;
shared variable cp_pulse_o: covPType; signal tb_rst_n_i : std_logic;
signal tb_data_i : std_logic := '0';
signal tb_pulse_o : std_logic;
signal stop : boolean;
-- Variables used for coverage
shared variable cp_rst_i : covPType;
shared variable cp_data_i : covPType;
shared variable cp_pulse_o: covPType;
begin begin
-- Unit Under Test -- Unit Under Test
UUT : entity work.gc_negedge UUT : entity work.gc_negedge
generic map ( generic map (
g_ASYNC_RST => g_ASYNC_RST, g_ASYNC_RST => g_ASYNC_RST,
g_CLOCK_EDGE => g_CLOCK_EDGE) g_CLOCK_EDGE => g_CLOCK_EDGE)
port map ( port map (
clk_i => tb_clk_i, clk_i => tb_clk_i,
rst_n_i => tb_rst_n_i, rst_n_i => tb_rst_n_i,
data_i => tb_data_i, data_i => tb_data_i,
pulse_o => tb_pulse_o); pulse_o => tb_pulse_o);
-- Clock and reset generation -- Clock generation
clk_proc : process clk_proc : process
begin begin
while STOP = FALSE loop while STOP = FALSE loop
tb_clk_i <= '1'; tb_clk_i <= '1';
wait for C_CLK_PERIOD/2; wait for C_CLK_PERIOD/2;
tb_clk_i <= '0'; tb_clk_i <= '0';
wait for C_CLK_PERIOD/2; wait for C_CLK_PERIOD/2;
end loop; end loop;
wait; wait;
end process clk_proc; end process clk_proc;
-- Reset generation
tb_rst_n_i <= '0', '1' after 4*C_CLK_PERIOD; tb_rst_n_i <= '0', '1' after 4*C_CLK_PERIOD;
-- Stimulus -- Stimulus
stim : process stim : process
variable ncycles : natural; variable ncycles : natural;
variable seed1, seed2 : integer := 1992; variable data : RandomPType;
impure function rand_stdl(len:integer:=1) return std_logic is
variable r : real;
variable stdlog : std_logic;
begin
uniform(seed1,seed2,r);
stdlog:= '1' when r>0.5 else '0';
return stdlog;
end function;
begin begin
wait until (tb_rst_n_i='1'); data.InitSeed(g_seed);
while (NOW < 1 ms) loop report "[STARTING] with seed = " & to_string(g_seed);
wait until (rising_edge(tb_clk_i)); wait until tb_rst_n_i='1';
tb_data_i <= rand_stdl(1); while NOW < 4 ms loop
ncycles := ncycles + 1; wait until rising_edge(tb_clk_i);
tb_data_i <= data.randSlv(1)(1);
ncycles := ncycles + 1;
end loop; end loop;
report "Number of simulation cycles = " & to_string(ncycles); report "Number of simulation cycles = " & to_string(ncycles);
stop <= TRUE; stop <= TRUE;
report "Test PASS!"; report "Test PASS!";
wait; wait;
end process; end process;
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Assertions -- Assertions --
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
--Assertion to check that the width of the output pulse -- Assertion to check that the width of the output pulse
--is asserted for only one clock cycle -- is asserted for only one clock cycle
one_clk_width : process one_clk_width : process
begin begin
if (rising_edge(tb_clk_i)) then while not stop loop
if (tb_pulse_o = '1') then wait until rising_edge(tb_clk_i);
wait for C_CLK_PERIOD; if tb_pulse_o = '1' then
assert (tb_pulse_o = '0') wait for C_CLK_PERIOD;
report "output pulse remains high for more than one clock" assert (tb_pulse_o = '0')
severity failure; report "output pulse remains high for more than one clock"
end if; severity error;
end if; end if;
wait; end loop;
end process; wait;
end process;
-- Check that the output pulse is asserted
-- in the falling edge of the input pulse -- Check that the output pulse is asserted
check_edge : process -- in the falling edge of the input pulse
begin check_negedge : process
if (rising_edge(tb_clk_i)) then begin
wait until (falling_edge(tb_data_i)); while not stop loop
assert (rising_edge(tb_pulse_o)) wait until falling_edge(tb_data_i);
report "Negative edge didn't detect" wait for 0 ns; --wait for delta time
severity failure; assert (tb_pulse_o='1')
end if; report "Negative edge didn't detect" severity failure;
wait; end loop;
end process; wait;
end process;
--------------------------------------------------------------------------------
-- Coverage --------------------------------------------------------------------------------
-------------------------------------------------------------------------------- -- Coverage --
--------------------------------------------------------------------------------
--sets up coverpoint bins
--sets up coverpoint bins
init_coverage : process init_coverage : process
begin begin
cp_rst_i.AddBins("reset has asserted", ONE_BIN); cp_rst_i.AddBins("reset has asserted", ONE_BIN);
cp_data_i.AddBins("Input pulse detected", ONE_BIN); cp_data_i.AddBins("Input pulse detected", ONE_BIN);
cp_pulse_o.AddBins("Output pulse detected", ONE_BIN); cp_pulse_o.AddBins("Output pulse detected", ONE_BIN);
wait; wait;
end process init_coverage; end process init_coverage;
-- Sample the coverpoints -- sample coverpoints for reset
sample_rst_n_i : process
-- sample coverpoints for reset
sample_rst_n_i : process
begin begin
loop loop
wait on tb_rst_n_i; wait on tb_rst_n_i;
...@@ -171,42 +160,42 @@ begin ...@@ -171,42 +160,42 @@ begin
end loop; end loop;
end process; end process;
-- sample coverpoints for input data -- sample coverpoints for input data
sample_data_i : process(tb_clk_i) sample_data_i : process(tb_clk_i)
begin
if rising_edge(tb_clk_i) then
cp_data_i.ICover(to_integer(tb_data_i='1'));
end if;
end process;
-- sample coverpoints for output pulse
clock_edge_pos : if (g_CLOCK_EDGE="positive") generate
sample_pulse_o : process(tb_clk_i)
begin
if rising_edge(tb_clk_i) then
cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end if;
end process;
end generate;
clock_edge_neg : if (g_CLOCK_EDGE="negative") generate
sample_pulse_o : process
begin begin
if (rising_edge(tb_clk_i)) then loop
cp_data_i.ICover(to_integer(tb_data_i='1')); wait until (falling_edge(tb_clk_i));
end if; cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end loop;
wait;
end process; end process;
end generate;
-- sample coverpoints for output pulse -- Coverage report
clock_edge_pos : if (g_CLOCK_EDGE="positive") generate cover_report: process
sample_pulse_o : process(tb_clk_i)
begin
if (rising_edge(tb_clk_i)) then
cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end if;
end process;
end generate;
clock_edge_neg : if (g_CLOCK_EDGE="negative") generate
sample_pulse_o : process
begin
loop
wait until (falling_edge(tb_clk_i));
cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end loop;
wait;
end process;
end generate;
-- Coverage report
cover_report: process
begin begin
wait until stop; wait until stop;
cp_rst_i.writebin; cp_rst_i.writebin;
cp_data_i.writebin; cp_data_i.writebin;
cp_pulse_o.writebin; cp_pulse_o.writebin;
report "PASS"; report "PASS";
end process; end process;
......
This is a simple testbench which uses GHDL simulator and OSVVM verification methodology. The goal is to verify the functionality of the gc_posedge (a simple positive edge detector). Through OSVVM, we can achieve randomization of the input data, with randomized seed value. The test cases of the testbench are defined through the different values assigned to the entity's generics.
The generics of this core are the following:
- g_async_rst : Synchronous or asynchronous reset
- g_clock_edge : Clock edge sensitivity of edge detection
Regarding on the values of the above generics, there are the following test cases:
1. TRUE, positive
2. TRUE, negative
3. FALSE, positive
4. FALSE, negative
Assertions are used to provide a self-checking approach. These are:
- The width of the output pulse is always one clock cycle long
- To always detect a positive edge of a rising input data signal
Coverage that is being covered:
- Reset has been asserted
- Input pulse detected
- Output pulse detected
Note: The values of the two last coverage bins are different because the input signal width is not always one clock cycle long
#!/bin/bash #!/bin/bash
#This is a simple script to run simulations #This is a simple script to run simulations in GHDL
#in GHDL
TB=tb_gc_posedge TB=tb_gc_posedge
echo "Running simulation for $TB" echo " TEST CASE 1 "
echo "ASYNC_RST=TRUE, CLOCK_EDGE=positive" echo "ASYNC_RST=TRUE, CLOCK_EDGE=positive"
ghdl -r --std=08 -frelaxed-rules $TB -gg_ASYNC_RST=TRUE -gg_CLOCK_EDGE=positive ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_ASYNC_RST=TRUE -gg_CLOCK_EDGE="positive" --wave=waveform1.ghw
echo "******************************************************************************************"
echo " TEST CASE 2 "
echo "ASYNC_RST=TRUE, CLOCK_EDGE=negative" echo "ASYNC_RST=TRUE, CLOCK_EDGE=negative"
ghdl -r --std=08 -frelaxed-rules $TB -gg_ASYNC_RST=TRUE -gg_CLOCK_EDGE=negative ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_ASYNC_RST=TRUE -gg_CLOCK_EDGE="negative" --wave=waveform2.ghw
echo "******************************************************************************************"
echo " TEST CASE 3 "
echo "ASYNC_RST=FALSE, CLOCK_EDGE=positive" echo "ASYNC_RST=FALSE, CLOCK_EDGE=positive"
ghdl -r --std=08 -frelaxed-rules $TB -gg_ASYNC_RST=FALSE -gg_CLOCK_EDGE=positive ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_ASYNC_RST=FALSE -gg_CLOCK_EDGE="positive" --wave=waveform3.ghw
echo "******************************************************************************************"
echo " TEST CASE 4 "
echo "ASYNC_RST=FALSE, CLOCK_EDGE=negative" echo "ASYNC_RST=FALSE, CLOCK_EDGE=negative"
ghdl -r --std=08 -frelaxed-rules $TB -gg_ASYNC_RST=FALSE -gg_CLOCK_EDGE=negative ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_ASYNC_RST=FALSE -gg_CLOCK_EDGE="negative" --wave=waveform4.ghw
echo "******************************************************************************************"
...@@ -28,186 +28,175 @@ library ieee; ...@@ -28,186 +28,175 @@ library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library -- OSVVM library
library osvvm; library osvvm;
use osvvm.RandomPkg.all; use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all; use osvvm.CoveragePkg.all;
entity tb_gc_posedge is entity tb_gc_posedge is
generic ( generic (
g_ASYNC_RST : boolean := FALSE; g_seed : natural;
g_CLOCK_EDGE : string := "positive"); g_ASYNC_RST : boolean;
g_CLOCK_EDGE : string);
end entity; end entity;
architecture tb of tb_gc_posedge is architecture tb of tb_gc_posedge is
-- constants -- Constants
constant C_CLK_PERIOD : time := 10 ns; constant C_CLK_PERIOD : time := 10 ns;
-- Signals -- Signals
signal tb_clk_i : std_logic; signal tb_clk_i : std_logic;
signal tb_rst_n_i : std_logic; signal tb_rst_n_i : std_logic;
signal tb_data_i : std_logic := '0'; signal tb_data_i : std_logic := '0';
signal tb_pulse_o : std_logic; signal tb_pulse_o : std_logic;
signal stop : boolean;
signal stop : boolean;
-- Variables used for coverage
-- Variables used for coverage shared variable cp_rst_i : covPType;
shared variable cp_rst_i : covPType; shared variable cp_data_i : covPType;
shared variable cp_data_i : covPType; shared variable cp_pulse_o: covPType;
shared variable cp_pulse_o: covPType;
begin begin
-- Unit Under Test -- Unit Under Test
UUT : entity work.gc_negedge UUT : entity work.gc_posedge
generic map ( generic map (
g_ASYNC_RST => g_ASYNC_RST, g_ASYNC_RST => g_ASYNC_RST,
g_CLOCK_EDGE => g_CLOCK_EDGE) g_CLOCK_EDGE => g_CLOCK_EDGE)
port map ( port map (
clk_i => tb_clk_i, clk_i => tb_clk_i,
rst_n_i => tb_rst_n_i, rst_n_i => tb_rst_n_i,
data_i => tb_data_i, data_i => tb_data_i,
pulse_o => tb_pulse_o); pulse_o => tb_pulse_o);
-- Clock and reset generation -- Clock generation
clk_proc : process clk_proc : process
begin begin
while STOP = FALSE loop while STOP = FALSE loop
tb_clk_i <= '1'; tb_clk_i <= '1';
wait for C_CLK_PERIOD/2; wait for C_CLK_PERIOD/2;
tb_clk_i <= '0'; tb_clk_i <= '0';
wait for C_CLK_PERIOD/2; wait for C_CLK_PERIOD/2;
end loop; end loop;
wait; wait;
end process clk_proc; end process clk_proc;
-- Reset generation
tb_rst_n_i <= '0', '1' after 4*C_CLK_PERIOD; tb_rst_n_i <= '0', '1' after 4*C_CLK_PERIOD;
-- Stimulus
stim : process
variable ncycles : natural;
variable seed1, seed2 : integer := 1992;
impure function rand_stdl(len:integer:=1) return std_logic is
variable r : real;
variable stdlog : std_logic;
begin
uniform(seed1,seed2,r);
stdlog:= '1' when r>0.5 else '0';
return stdlog;
end function;
-- Stimulus
stim : process
variable ncycles : natural;
variable data : RandomPType;
begin begin
wait until (tb_rst_n_i='1'); data.InitSeed(g_seed);
while (NOW < 1 ms) loop report "[STARTING] with seed = " & to_string(g_seed);
wait until (rising_edge(tb_clk_i)); wait until tb_rst_n_i='1';
tb_data_i <= rand_stdl(1); while NOW < 2 ms loop
ncycles := ncycles + 1; wait until rising_edge(tb_clk_i);
tb_data_i <= data.randSlv(1)(1);
ncycles := ncycles + 1;
end loop; end loop;
report "Number of simulation cycles = " & to_string(ncycles); report "Number of simulation cycles = " & to_string(ncycles);
stop <= TRUE; stop <= TRUE;
report "Test PASS!"; report "Test PASS!";
wait; wait;
end process; end process;
--------------------------------------------------------------------------------
-- Assertions
--------------------------------------------------------------------------------
--Assertion to check that the width of the output pulse
--is asserted for only one clock cycle
one_clk_width : process
begin
if (rising_edge(tb_clk_i)) then
if (tb_pulse_o = '1') then
wait for C_CLK_PERIOD;
assert (tb_pulse_o = '0')
report "output pulse remains high for more than one clock"
severity failure;
end if;
end if;
wait;
end process;
-- Check that the output pulse is asserted
-- in the falling edge of the input pulse
check_edge : process
begin
if (rising_edge(tb_clk_i)) then
wait until (falling_edge(tb_data_i));
assert (rising_edge(tb_pulse_o))
report "Negative edge didn't detect"
severity failure;
end if;
wait;
end process;
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Coverage -- Assertions --
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
--sets up coverpoint bins --Assertion to check that the width of the output pulse
--is asserted for only one clock cycle
one_clk_width : process
begin
while not stop loop
wait until rising_edge(tb_clk_i);
if tb_pulse_o = '1' then
wait for C_CLK_PERIOD;
assert (tb_pulse_o = '0')
report "output pulse remains high for more than one clock"
severity failure;
end if;
end loop;
wait;
end process;
-- Check that the output pulse is asserted
-- in the rising edge of the input pulse
check_edge : process
begin
while not stop loop
wait until rising_edge(tb_data_i);
wait for 0 ns; --wait for delta time
assert (tb_pulse_o = '1')
report "Positive edge didn't detect"
severity failure;
end loop;
wait;
end process;
--------------------------------------------------------------------------------
-- Coverage --
--------------------------------------------------------------------------------
--sets up coverpoint bins
init_coverage : process init_coverage : process
begin begin
cp_rst_i.AddBins("reset has asserted", ONE_BIN); cp_rst_i.AddBins("reset has asserted", ONE_BIN);
cp_data_i.AddBins("Input pulse detected", ONE_BIN); cp_data_i.AddBins("Input pulse detected", ONE_BIN);
cp_pulse_o.AddBins("Output pulse detected", ONE_BIN); cp_pulse_o.AddBins("Output pulse detected", ONE_BIN);
wait; wait;
end process init_coverage; end process init_coverage;
-- Sample the coverpoints -- sample coverpoints for reset
sample_rst_n_i : process
-- sample coverpoints for reset
sample_rst_n_i : process
begin begin
loop loop
wait on tb_rst_n_i; wait on tb_rst_n_i;
wait for C_CLK_PERIOD; wait for C_CLK_PERIOD;
cp_rst_i.ICover(to_integer(tb_rst_n_i = '1')); cp_rst_i.ICover(to_integer(tb_rst_n_i = '1'));
end loop; end loop;
end process; end process;
-- sample coverpoints for input data -- sample coverpoints for input data
sample_data_i : process(tb_clk_i) sample_data_i : process(tb_clk_i)
begin
if rising_edge(tb_clk_i) then
cp_data_i.ICover(to_integer(tb_data_i='1'));
end if;
end process;
-- sample coverpoints for output pulse
clock_edge_pos : if (g_CLOCK_EDGE="positive") generate
sample_pulse_o : process(tb_clk_i)
begin
if (rising_edge(tb_clk_i)) then
cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end if;
end process;
end generate;
clock_edge_neg : if (g_CLOCK_EDGE="negative") generate
sample_pulse_o : process
begin begin
if (rising_edge(tb_clk_i)) then loop
cp_data_i.ICover(to_integer(tb_data_i='1')); wait until (falling_edge(tb_clk_i));
end if; cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end loop;
wait;
end process; end process;
end generate;
-- sample coverpoints for output pulse -- Coverage report
clock_edge_pos : if (g_CLOCK_EDGE="positive") generate cover_report: process
sample_pulse_o : process(tb_clk_i)
begin
if (rising_edge(tb_clk_i)) then
cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end if;
end process;
end generate;
clock_edge_neg : if (g_CLOCK_EDGE="negative") generate
sample_pulse_o : process
begin
loop
wait until (falling_edge(tb_clk_i));
cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end loop;
wait;
end process;
end generate;
-- Coverage report
cover_report: process
begin begin
wait until stop; wait until stop;
cp_rst_i.writebin; cp_rst_i.writebin;
cp_data_i.writebin; cp_data_i.writebin;
cp_pulse_o.writebin; cp_pulse_o.writebin;
report "PASS";
end process; end process;
end tb; end tb;
Testbench to verify the functionality of the gc_prio_encoder general core. It receives randomized input signals with random seed. It consist of 6 test cases (can be extented to more) regarding the incoming data width. These test cases are:
1. g_width = 1
2. g_width = 3
3. g_width = 7
4. g_width = 16
5. g_width = 31
6. g_width = 128
This testbench is using the simple logic of the priority encoder, like in the RTL code. The result is stored in a vector and then it is being compared with the one which coming from the RTL core.
Assertions are being used for better self-checking purposes. First of all, it checks if there is a mismatch between the output data of the testbench and RTL code. In addition, the other assertion, checks if the generic value is valid (should be 1 or higher).
...@@ -7,26 +7,26 @@ TB=tb_gc_prio_encoder ...@@ -7,26 +7,26 @@ TB=tb_gc_prio_encoder
echo "Running simulation for $TB" echo "Running simulation for $TB"
echo "Width = 1" echo "Width = 1"
ghdl -r --std=08 -frelaxed-rules $TB -gg_width=1 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_width=1
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 3" echo "Width = 3"
ghdl -r --std=08 -frelaxed-rules $TB -gg_width=3 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_width=3 --wave=waveform.ghw
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 7" echo "Width = 7"
ghdl -r --std=08 -frelaxed-rules $TB -gg_width=7 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_width=7
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 16" echo "Width = 16"
ghdl -r --std=08 -frelaxed-rules $TB -gg_width=16 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_width=16
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 31" echo "Width = 31"
ghdl -r --std=08 -frelaxed-rules $TB -gg_width=31 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_width=31
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 128" echo "Width = 128"
ghdl -r --std=08 -frelaxed-rules $TB -gg_width=128 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_width=128
echo "********************************************************************************" echo "********************************************************************************"
...@@ -30,122 +30,109 @@ library ieee; ...@@ -30,122 +30,109 @@ library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library -- OSVVM library
--library osvvm; library osvvm;
--use osvvm.RandomPkg.all; use osvvm.RandomPkg.all;
--use osvvm.CoveragePkg.all; use osvvm.CoveragePkg.all;
entity tb_gc_prio_encoder is entity tb_gc_prio_encoder is
generic ( generic (
g_width : integer := 32); g_seed : natural;
g_width : integer := 32);
end entity; end entity;
architecture tb of tb_gc_prio_encoder is architecture tb of tb_gc_prio_encoder is
-- functions -- functions
function f_count_stages(width : integer) return integer is function f_count_stages(width : integer) return integer is
begin begin
if(width <= 2) then if(width <= 2) then
return 2; return 2;
elsif(width <= 4) then elsif(width <= 4) then
return 3; return 3;
elsif(width <= 8) then elsif(width <= 8) then
return 4; return 4;
elsif(width <= 16) then elsif(width <= 16) then
return 5; return 5;
elsif(width <= 32) then elsif(width <= 32) then
return 6; return 6;
elsif(width <= 64) then elsif(width <= 64) then
return 7; return 7;
elsif(width <= 128) then elsif(width <= 128) then
return 8; return 8;
else else
return 0; return 0;
end if; end if;
end f_count_stages; end f_count_stages;
-- constants -- constants
constant C_STAGES : integer := f_count_stages(g_width); constant C_STAGES : integer := f_count_stages(g_width);
-- signals -- signals
signal tb_d_i : std_logic_vector(g_width-1 downto 0) := (others=>'0'); signal tb_d_i : std_logic_vector(g_width-1 downto 0) := (others=>'0');
signal tb_therm_o : std_logic_vector(g_width-1 downto 0); signal tb_therm_o : std_logic_vector(g_width-1 downto 0);
signal stop : boolean;
signal stop : boolean;
type t_stages_array is array (0 to C_STAGES) of std_logic_vector(g_width-1 downto 0);
type t_stages_array is array (0 to C_STAGES) of std_logic_vector(g_width-1 downto 0); signal s_stage : t_stages_array;
signal s_stage : t_stages_array; signal s_data_o : std_logic_vector(g_width-1 downto 0);
signal s_data_o : std_logic_vector(g_width-1 downto 0);
begin begin
-- Unit Under Test -- Unit Under Test
UUT : entity work.gc_prio_encoder UUT : entity work.gc_prio_encoder
generic map ( generic map (
g_width => g_width) g_width => g_width)
port map ( port map (
d_i => tb_d_i, d_i => tb_d_i,
therm_o => tb_therm_o); therm_o => tb_therm_o);
-- Stimulus -- Stimulus
stim : process stim : process
variable ncycles : natural; variable ncycles : natural;
variable seed1, seed2 : integer := 1992; variable data : RandomPType;
impure function rand_slv(len:integer) return std_logic_vector is
variable r : real;
variable slv : std_logic_vector(len - 1 downto 0);
begin
for i in slv'range loop
uniform(seed1, seed2, r);
slv(i) := '1' when r>0.5 else '0';
end loop;
return slv;
end function;
begin begin
while (NOW < 2 ms) loop data.InitSeed(g_seed);
wait for 10 ns; --give every 10ns a new input report "[STARTING] with seed = " & to_string(g_seed);
tb_d_i <= rand_slv(g_width); while NOW < 2 ms loop
wait for 10 ns; --give every 10ns a new input
tb_d_i <= data.randSlv(g_width);
ncycles := ncycles + 1; ncycles := ncycles + 1;
end loop; end loop;
report "Number of simulation cycles = " & to_string(ncycles); report "Number of simulation cycles = " & to_string(ncycles);
stop <= TRUE; stop <= TRUE;
report "Test PASS!"; report "Test PASS!";
wait; wait;
end process; end process;
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Reproduce the RTL behavior in order to compare it with the actual RTL -- Reproduce the RTL behavior in order to compare it with the actual RTL
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
s_stage(0) <= tb_d_i; s_stage(0) <= tb_d_i;
nof_stages : for i in 1 to C_STAGES generate nof_stages : for i in 1 to C_STAGES generate
data_width : for j in 0 to g_width-1 generate data_width : for j in 0 to g_width-1 generate
case_1 : if (j mod (2 ** i) >= (2 ** (i-1))) generate
s_stage(i)(j) <= s_stage(i-1)(j) or s_stage(i-1) (j - (j mod (2**i)) + (2**(i-1)) - 1); case_1 : if (j mod (2 ** i) >= (2 ** (i-1))) generate
end generate; s_stage(i)(j) <= s_stage(i-1)(j) or s_stage(i-1) (j - (j mod (2**i)) + (2**(i-1)) - 1);
case_2 : if not (j mod (2 ** i) >= (2 ** (i-1))) generate end generate;
s_stage(i)(j) <= s_stage(i-1)(j);
end generate; case_2 : if not (j mod (2 ** i) >= (2 ** (i-1))) generate
end generate; s_stage(i)(j) <= s_stage(i-1)(j);
end generate;
end generate; end generate;
end generate;
s_data_o <= s_stage(C_STAGES); s_data_o <= s_stage(C_STAGES);
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Assertions -- Assertions --
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
assert (s_data_o = tb_therm_o) assert (s_data_o = tb_therm_o)
report "Output data mismatch" report "Output data mismatch" severity failure;
severity failure;
assert (g_width > 0) assert (g_width > 0)
report "Invalid value of data width" report "Invalid value of data width" severity failure;
severity failure;
end tb; end tb;
Testbench to verify the functionality of the gc_pulse_synchronizer general core. It uses GHDL simulator and OSVVM verification methodology. Since in this core there are no generics in the entity, there is only one test case.
The testing process is very simple. It receives random input data (with random seeds). One assertion exist in the testbench to bring self-checking capabilities in it. What it does is that, after the de-assertion of ready_o, checks if, in the next rising edge of clock, the output is HIGH.
Simple coverage is being covered also:
- Reset has been asserted
- New HIGH data arrived
- New valid HIGH data produced
...@@ -6,5 +6,5 @@ TB=tb_gc_pulse_synchronizer ...@@ -6,5 +6,5 @@ TB=tb_gc_pulse_synchronizer
echo "Running simulation for $TB" echo "Running simulation for $TB"
ghdl -r --std=08 -frelaxed-rules $TB ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM
...@@ -27,129 +27,126 @@ library ieee; ...@@ -27,129 +27,126 @@ library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
use std.env.finish; -- OSVVM library
use ieee.math_real.all;
library osvvm; library osvvm;
use osvvm.RandomPkg.all; use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all; use osvvm.CoveragePkg.all;
entity tb_gc_pulse_synchronizer is entity tb_gc_pulse_synchronizer is
generic (
g_seed : natural);
end entity; end entity;
architecture tb of tb_gc_pulse_synchronizer is architecture tb of tb_gc_pulse_synchronizer is
constant C_CLK_IN_PERIOD : time := 10 ns; -- Constants
constant C_CLK_OUT_PERIOD : time := 8 ns; constant C_CLK_IN_PERIOD : time := 10 ns;
constant C_CLK_OUT_PERIOD : time := 8 ns;
--signals --signals
signal tb_clk_in_i : std_logic; signal tb_clk_in_i : std_logic;
signal tb_rst_n_i : std_logic; signal tb_rst_n_i : std_logic;
signal tb_clk_out_i : std_logic; signal tb_clk_out_i : std_logic;
signal tb_d_ready_o : std_logic; signal tb_d_ready_o : std_logic;
signal tb_d_p_i : std_logic := '0'; signal tb_d_p_i : std_logic := '0';
signal tb_q_p_o : std_logic; signal tb_q_p_o : std_logic;
-- variables used for coverage -- Shared variables used for coverage
shared variable cp_rst_in_i : covPType; shared variable cp_rst_in_i : covPType;
shared variable cp_data_i : covPType; shared variable cp_data_i : covPType;
shared variable cp_data_o : covPType; shared variable cp_data_o : covPType;
signal stop : boolean := FALSE; signal stop : boolean := FALSE;
begin begin
-- Unit Under Test -- Unit Under Test
UUT : entity work.gc_pulse_synchronizer UUT : entity work.gc_pulse_synchronizer
port map ( port map (
clk_in_i => tb_clk_in_i, clk_in_i => tb_clk_in_i,
rst_n_i => tb_rst_n_i, rst_n_i => tb_rst_n_i,
clk_out_i => tb_clk_out_i, clk_out_i => tb_clk_out_i,
d_ready_o => tb_d_ready_o, d_ready_o => tb_d_ready_o,
d_p_i => tb_d_p_i, d_p_i => tb_d_p_i,
q_p_o => tb_q_p_o); q_p_o => tb_q_p_o);
--clocks and resets generation --clocks generation
clk_in_gen : process clk_in_gen : process
begin begin
while STOP = FALSE loop while not stop loop
tb_clk_in_i <= '1'; tb_clk_in_i <= '1';
wait for C_CLK_IN_PERIOD/2; wait for C_CLK_IN_PERIOD/2;
tb_clk_in_i <= '0'; tb_clk_in_i <= '0';
wait for C_CLK_IN_PERIOD/2; wait for C_CLK_IN_PERIOD/2;
end loop; end loop;
wait; wait;
end process; end process;
clk_out_gen : process clk_out_gen : process
begin begin
while STOP = FALSE loop while not stop loop
tb_clk_out_i <= '1'; tb_clk_out_i <= '1';
wait for C_CLK_OUT_PERIOD/2; wait for C_CLK_OUT_PERIOD/2;
tb_clk_out_i <= '0'; tb_clk_out_i <= '0';
wait for C_CLK_OUT_PERIOD/2; wait for C_CLK_OUT_PERIOD/2;
end loop; end loop;
wait; wait;
end process; end process;
tb_rst_n_i <= '0', '1' after 2*C_CLK_IN_PERIOD; -- Reset generation
tb_rst_n_i <= '0', '1' after 2*C_CLK_IN_PERIOD;
stim : process
variable data_i : RandomPType; -- Stimulus
variable seed1, seed2 : integer := 999; stim : process
variable data : RandomPType;
impure function rand_stdl(len:integer:=1) return std_logic is variable ncycles : natural;
variable r : real; begin
variable stdlog : std_logic; data.InitSeed(g_seed);
begin report "[STARTING] with seed = " & to_string(g_seed);
uniform(seed1,seed2,r); while NOW < 2 ms loop
stdlog := '1' when r>0.5 else '0'; wait until (rising_edge(tb_clk_in_i) and tb_d_ready_o = '1');
return stdlog; tb_d_p_i <= data.randSlv(1)(1);
end function; ncycles := ncycles + 1;
end loop;
begin report "Number of Simulation cycles = " & to_string(ncycles);
while (NOW < 2 ms) loop report "Test PASS!";
wait until (rising_edge(tb_clk_in_i) and tb_d_ready_o = '1'); stop <= TRUE;
tb_d_p_i <= rand_stdl(1); wait;
end loop; end process;
stop <= TRUE;
wait; --------------------------------------------------------------------------------
end process; -- Assertions --
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Assertions -- Self-Checking : after the de-assertion of ready_o, in the next rising edge
-------------------------------------------------------------------------------- -- of clock we expect the output to be HIGH
valid_out_data : process
-- Self-Checking : after the de-assertion of ready_o, in the next rising edge begin
-- of clock we expect the output to be HIGH while not stop loop
valid_out_data : process wait until falling_edge(tb_d_ready_o);
begin wait until rising_edge(tb_clk_out_i);
wait until (tb_rst_n_i = '1'); wait for 2*C_CLK_OUT_PERIOD;
while (stop=FALSE) loop report "here";
wait until falling_edge(tb_d_ready_o); assert (tb_q_p_o = '1')
wait until rising_edge(tb_clk_out_i); report "output is wrong" severity failure;
wait for 2*C_CLK_OUT_PERIOD; end loop;
assert (tb_q_p_o = '1') wait;
report "output is wrong" end process;
severity failure;
end loop; --------------------------------------------------------------------------------
wait; -- Coverage --
end process; --------------------------------------------------------------------------------
-------------------------------------------------------------------------------- --sets up coverpoint bins
-- Coverage
--------------------------------------------------------------------------------
--sets up coverpoint bins
init_coverage : process init_coverage : process
begin begin
cp_rst_in_i.AddBins("reset in has been asserted", ONE_BIN); cp_rst_in_i.AddBins("reset in has been asserted", ONE_BIN);
cp_data_i.AddBins("new HIGH data arrived", ONE_BIN); cp_data_i.AddBins("new HIGH data arrived", ONE_BIN);
cp_data_o.AddBins("output pulse for HIGH input", ONE_BIN); cp_data_o.AddBins("output pulse for HIGH input", ONE_BIN);
wait; wait;
end process init_coverage; end process init_coverage;
-- Sample the coverpoints -- Sample the coverpoints
sample_rst_i : process sample_rst_i : process
begin begin
loop loop
...@@ -159,31 +156,30 @@ begin ...@@ -159,31 +156,30 @@ begin
end loop; end loop;
end process sample_rst_i; end process sample_rst_i;
sample_data_i : process sample_data_i : process
begin begin
loop loop
wait until (rising_edge(tb_clk_in_i)); wait until (rising_edge(tb_clk_in_i));
wait until (rising_edge(tb_d_p_i)); wait until (rising_edge(tb_d_p_i));
cp_data_i.ICover(to_integer(tb_d_p_i = '1')); cp_data_i.ICover(to_integer(tb_d_p_i = '1'));
end loop; end loop;
end process; end process;
sample_data_o : process sample_data_o : process
begin begin
loop loop
wait until (falling_edge(tb_d_ready_o)); wait until (falling_edge(tb_d_ready_o));
wait until (rising_edge(tb_q_p_o)); wait until (rising_edge(tb_q_p_o));
cp_data_o.ICover(to_integer(tb_q_p_o='1')); cp_data_o.ICover(to_integer(tb_q_p_o='1'));
end loop; end loop;
end process; end process;
cover_report: process cover_report: process
begin begin
wait until stop; wait until stop;
cp_rst_in_i.writebin; cp_rst_in_i.writebin;
cp_data_i.writebin; cp_data_i.writebin;
cp_data_o.writebin; cp_data_o.writebin;
report "PASS";
end process; end process;
end tb; end tb;
......
Testbench to verify the functionality of the gc_pulse_synchronizer2 general core. This testbench is very similar to the one for gc_pulse_synchronizer. One of the differences is that, this core, has two different reset ports. It uses GHDL simulator and OSVVM verification methodology. Since in this core there are no generics in the entity, there is only one test case.
The testing process is very simple. It receives random input data (with random seeds). One assertion exist in the testbench to bring self-checking capabilities in it. What it does is that, after the de-assertion of ready_o, checks if, in the next rising edge of clock, the output is HIGH.
Simple coverage is being covered also:
- Reset in has been asserted
- Reset out has been asserted
- New HIGH data arrived
- New valid HIGH data produced
...@@ -6,4 +6,4 @@ TB=tb_gc_pulse_synchronizer2 ...@@ -6,4 +6,4 @@ TB=tb_gc_pulse_synchronizer2
echo "Running simulation for $TB" echo "Running simulation for $TB"
ghdl -r --std=08 -frelaxed-rules $TB ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM
...@@ -29,141 +29,135 @@ library ieee; ...@@ -29,141 +29,135 @@ library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
use std.env.finish; -- OSVVM library
use ieee.math_real.all;
library osvvm; library osvvm;
use osvvm.RandomPkg.all; use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all; use osvvm.CoveragePkg.all;
entity tb_gc_pulse_synchronizer2 is entity tb_gc_pulse_synchronizer2 is
generic (
g_seed : natural);
end entity; end entity;
architecture tb of tb_gc_pulse_synchronizer2 is architecture tb of tb_gc_pulse_synchronizer2 is
constant C_CLK_IN_PERIOD : time := 10 ns; -- Constants
constant C_CLK_OUT_PERIOD : time := 8 ns; constant C_CLK_IN_PERIOD : time := 5 ns;
constant C_CLK_OUT_PERIOD : time := 10 ns;
-- signals -- signals
signal tb_clk_in_i : std_logic; signal tb_clk_in_i : std_logic;
signal tb_rst_in_n_i : std_logic; signal tb_rst_in_n_i : std_logic;
signal tb_clk_out_i : std_logic; signal tb_clk_out_i : std_logic;
signal tb_rst_out_n_i : std_logic; signal tb_rst_out_n_i : std_logic;
signal tb_d_ready_o : std_logic; signal tb_d_ready_o : std_logic;
signal tb_d_ack_p_o : std_logic; signal tb_d_ack_p_o : std_logic;
signal tb_d_p_i : std_logic := '0'; signal tb_d_p_i : std_logic := '0';
signal tb_q_p_o : std_logic; signal tb_q_p_o : std_logic;
-- variables used for coverage
shared variable cp_rst_in_i : covPType;
shared variable cp_rst_out_i : covPType;
shared variable cp_data_i : covPType;
shared variable cp_data_o : covPType;
signal stop : boolean := FALSE; signal stop : boolean := FALSE;
-- Shared variables used for coverage
shared variable cp_rst_in_i : covPType;
shared variable cp_rst_out_i : covPType;
shared variable cp_data_i : covPType;
shared variable cp_data_o : covPType;
begin begin
--Unit Under Test -- Unit Under Test
UUT : entity work.gc_pulse_synchronizer2 UUT : entity work.gc_pulse_synchronizer2
port map ( port map (
clk_in_i => tb_clk_in_i, clk_in_i => tb_clk_in_i,
rst_in_n_i => tb_rst_in_n_i, rst_in_n_i => tb_rst_in_n_i,
clk_out_i => tb_clk_out_i, clk_out_i => tb_clk_out_i,
rst_out_n_i => tb_rst_out_n_i, rst_out_n_i => tb_rst_out_n_i,
d_ready_o => tb_d_ready_o, d_ready_o => tb_d_ready_o,
d_ack_p_o => tb_d_ack_p_o, d_ack_p_o => tb_d_ack_p_o,
d_p_i => tb_d_p_i, d_p_i => tb_d_p_i,
q_p_o => tb_q_p_o); q_p_o => tb_q_p_o);
--clock and reset generation -- Clocks generation
clk_in_gen : process clk_in_gen : process
begin begin
while STOP = FALSE loop while not stop loop
tb_clk_in_i <= '1'; tb_clk_in_i <= '1';
wait for C_CLK_IN_PERIOD/2; wait for C_CLK_IN_PERIOD/2;
tb_clk_in_i <= '0'; tb_clk_in_i <= '0';
wait for C_CLK_IN_PERIOD/2; wait for C_CLK_IN_PERIOD/2;
end loop; end loop;
wait; wait;
end process; end process;
clk_out_gen : process clk_out_gen : process
begin begin
while STOP = FALSE loop while not stop loop
tb_clk_out_i <= '1'; tb_clk_out_i <= '1';
wait for C_CLK_OUT_PERIOD/2; wait for C_CLK_OUT_PERIOD/2;
tb_clk_out_i <= '0'; tb_clk_out_i <= '0';
wait for C_CLK_OUT_PERIOD/2; wait for C_CLK_OUT_PERIOD/2;
end loop; end loop;
wait; wait;
end process; end process;
-- Resets generation
tb_rst_in_n_i <= '0', '1' after 2*C_CLK_IN_PERIOD; tb_rst_in_n_i <= '0', '1' after 2*C_CLK_IN_PERIOD;
tb_rst_out_n_i <= '0', '1' after 2*C_CLK_OUT_PERIOD; tb_rst_out_n_i <= '0', '1' after 2*C_CLK_OUT_PERIOD;
-- Stimulus
stim : process -- Stimulus
variable ncycles : natural; stim : process
variable seed1, seed2 : integer := 999; variable data : RandomPType;
variable ncycles : natural;
impure function rand_stdl(len:integer:=1) return std_logic is begin
variable r : real; data.InitSeed(g_seed);
variable stdlog : std_logic; report "[STARTING] with seed = " & to_string(g_seed);
begin while NOW < 2 ms loop
uniform(seed1,seed2,r); wait until (rising_edge(tb_clk_in_i) and tb_d_ready_o = '1');
stdlog := '1' when r>0.5 else '0'; tb_d_p_i <= data.randSlv(1)(1);
return stdlog; ncycles := ncycles + 1;
end function; end loop;
report "Number of Simulation cycles = " & to_string(ncycles);
begin report "Test PASS!";
while (NOW < 1 ms) loop stop <= TRUE;
wait until (rising_edge(tb_clk_in_i) and tb_d_ready_o = '1'); wait;
tb_d_p_i <= rand_stdl(1); end process;
ncycles := ncycles + 1;
end loop; --------------------------------------------------------------------------------
report "Number of simulation cycles = " & to_string(ncycles); -- Assertions --
stop <= TRUE; --------------------------------------------------------------------------------
wait;
end process; -- Self-Checking : after the de-assertion of ready_o, after one clock cycle
-- (due to g_sync module), we want the output to be like the input pulse
-------------------------------------------------------------------------------- -- but last for one clock
-- Assertions valid_out_data : process
-------------------------------------------------------------------------------- begin
wait until (tb_rst_in_n_i = '1' and tb_rst_out_n_i = '1');
-- Self-Checking : after the de-assertion of ready_o, after one clock cycle while not stop loop
-- (due to g_sync module), we want the output to be like the input pulse wait until falling_edge(tb_d_ready_o);
-- but last for one clock wait until rising_edge(tb_clk_out_i);
valid_out_data : process wait for 2*C_CLK_OUT_PERIOD;
begin assert (tb_q_p_o = '1')
wait until (tb_rst_in_n_i = '1' and tb_rst_out_n_i = '1'); report "output is wrong" severity failure;
while (stop=FALSE) loop end loop;
wait until falling_edge(tb_d_ready_o); wait;
wait until rising_edge(tb_clk_out_i); end process;
wait for 2*C_CLK_OUT_PERIOD;
assert (tb_q_p_o = '1') --------------------------------------------------------------------------------
report "output is wrong" -- Coverage --
severity failure; --------------------------------------------------------------------------------
end loop;
wait; --sets up coverpoint bins
end process;
--------------------------------------------------------------------------------
-- Coverage
--------------------------------------------------------------------------------
--sets up coverpoint bins
init_coverage : process init_coverage : process
begin begin
cp_rst_in_i.AddBins("reset in has been asserted", ONE_BIN); cp_rst_in_i.AddBins("reset in has been asserted", ONE_BIN);
cp_rst_out_i.AddBins("reset out has been asserted",ONE_BIN); cp_rst_out_i.AddBins("reset out has been asserted",ONE_BIN);
cp_data_i.AddBins("new HIGH data arrives",ONE_BIN); cp_data_i.AddBins("new HIGH data arrives",ONE_BIN);
cp_data_o.AddBins("output pulse for HIGH input",ONE_BIN); cp_data_o.AddBins("output pulse for HIGH input",ONE_BIN);
wait; wait;
end process init_coverage; end process init_coverage;
-- Sample the coverpoints -- Sample the coverpoints
sample_rst_i : process sample_rst_i : process
begin begin
loop loop
...@@ -182,33 +176,32 @@ begin ...@@ -182,33 +176,32 @@ begin
end loop; end loop;
end process sample_rst_out; end process sample_rst_out;
sample_data_i : process sample_data_i : process
begin begin
loop loop
wait until (rising_edge(tb_clk_in_i)); wait until (rising_edge(tb_clk_in_i));
wait until (rising_edge(tb_d_p_i)); wait until (rising_edge(tb_d_p_i));
cp_data_i.ICover(to_integer(tb_d_p_i = '1')); cp_data_i.ICover(to_integer(tb_d_p_i = '1'));
end loop; end loop;
end process; end process;
sample_data_o : process sample_data_o : process
begin begin
loop loop
wait until (falling_edge(tb_d_ready_o)); wait until (falling_edge(tb_d_ready_o));
wait until (rising_edge(tb_q_p_o)); wait until (rising_edge(tb_q_p_o));
cp_data_o.ICover(to_integer(tb_q_p_o='1')); cp_data_o.ICover(to_integer(tb_q_p_o='1'));
end loop; end loop;
end process; end process;
-- coverage reports -- coverage reports
cover_report: process cover_report: process
begin begin
wait until stop; wait until stop;
cp_rst_out_i.writebin; cp_rst_out_i.writebin;
cp_rst_in_i.writebin; cp_rst_in_i.writebin;
cp_data_i.writebin; cp_data_i.writebin;
cp_data_o.writebin; cp_data_o.writebin;
report "PASS";
end process; end process;
......
Testbench to verify the functionality of the gc_reset general core. It uses GHDL simulator and OSVVM verification methodology. This core is using 3 generics in the entity:
- g_clocks : Number of clocks
- g_logdelay : Delay duration
- g_syncdepth : Synchronization depth
A combination of them, create these test cases (there can be even more than them):
- 1, 1, 1
- 2, 2, 2
- 1, 5, 3
- 4, 3, 4
The testing process is very simple. It receives random input data (with random seeds). It uses a similar logic to the one that RTL uses and generates a testbench output. One assertion exist in the testbench to bring self-checking capabilities in it and compare the output of the testbench with the one in the RTL code.
Simple coverage is being covered also:
- Asynchronous reset has been asserted
- Output reset has been asserted
Note: It is advised, for simulation purposes, to keep the generic values quite low in order to see the behavior of the module. For higher generic values, increase the simulation time.
It is advised, for simulation purposes, to keep the generic
values quite low in order to see the behavior of the module.
For higher generic values, increase the simulation time
more than 40 ms
...@@ -6,18 +6,27 @@ ...@@ -6,18 +6,27 @@
TB=tb_gc_reset TB=tb_gc_reset
echo "Running simulation for $TB" echo "Running simulation for $TB"
echo ""
echo " TEST CASE 1 "
echo "Number of clocks = 1, LogDelay = 1 , SyncDepth = 1" echo "Number of clocks = 1, LogDelay = 1 , SyncDepth = 1"
ghdl -r --std=08 -frelaxed-rules $TB -gg_clocks=1 -gg_logdelay=1 -gg_syncdepth=1 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_clocks=1 -gg_logdelay=1 -gg_syncdepth=1
echo "****************************************************************************"
echo " TEST CASE 2 "
echo "Number of clocks = 2, LogDelay = 2 , SyncDepth = 2" echo "Number of clocks = 2, LogDelay = 2 , SyncDepth = 2"
ghdl -r --std=08 -frelaxed-rules $TB -gg_clocks=2 -gg_logdelay=2 -gg_syncdepth=2 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_clocks=2 -gg_logdelay=2 -gg_syncdepth=2
echo "****************************************************************************"
echo " TEST CASE 3 "
echo "Number of clocks = 1, LogDelay = 5 , SyncDepth = 3" echo "Number of clocks = 1, LogDelay = 5 , SyncDepth = 3"
ghdl -r --std=08 -frelaxed-rules $TB -gg_clocks=1 -gg_logdelay=3 -gg_syncdepth=4 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_clocks=1 -gg_logdelay=3 -gg_syncdepth=4
echo "****************************************************************************"
echo " TEST CASE 4 "
echo "Number of clocks = 4, LogDelay = 3, SyncDepth = 4" echo "Number of clocks = 4, LogDelay = 3, SyncDepth = 4"
ghdl -r --std=08 -frelaxed-rules $TB -gg_clocks=4 -gg_logdelay=4 -gg_syncdepth=4 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_clocks=4 -gg_logdelay=4 -gg_syncdepth=4
echo "****************************************************************************"
This diff is collapsed.
Testbench to verify the functionality of the gc_reset_multi_aasd general core. It uses GHDL simulator and OSVVM verification methodology. This core is using 2 generics in the entity:
- g_clocks : Number of clocks
- g_rst_len : Number of clock ticks (per domain) that the input reset must remain deasserted and stable before deasserting the reset output(s)
A combination of them, create these test cases (there can be even more than them):
- 1, 2
- 1, 4
- 2, 2
- 2, 4
- 1, 1
The testing process is very simple. It receives random input data (with random seeds). It uses a similar logic to the one that RTL uses and generates a testbench output (in case of more than one clocks). One assertion exist in the testbench to bring self-checking capabilities in it and compare the output of the testbench with the one in the RTL code.
...@@ -5,21 +5,29 @@ ...@@ -5,21 +5,29 @@
TB=tb_gc_reset_multi_aasd TB=tb_gc_reset_multi_aasd
echo "Running simulation for $TB" echo "Running simulation for $TB"
echo ""
echo " TEST CASE 1 "
echo "Clock domains = 1, Number of resets = 2" echo "Clock domains = 1, Number of resets = 2"
ghdl -r --std=08 -frelaxed-rules $TB -gg_CLOCKS=1 -gg_RST_LEN=2 --vcd=waveform.vcd ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_CLOCKS=1 -gg_RST_LEN=2
echo "****************************************************************************"
echo " TEST CASE 2 "
echo "Clock domains = 1, Number of resets = 4" echo "Clock domains = 1, Number of resets = 4"
ghdl -r --std=08 -frelaxed-rules $TB -gg_CLOCKS=1 -gg_RST_LEN=4 --vcd=waveform.vcd ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_CLOCKS=1 -gg_RST_LEN=4
echo "****************************************************************************"
#echo "Clock domains = 2, Number of resets = 2" echo " TEST CASE 3 "
#ghdl -r --std=08 -frelaxed-rules $TB -gg_CLOCKS=2 -gg_RST_LEN=2 --vcd=waveform.vcd echo "Clock domains = 2, Number of resets = 2"
ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_CLOCKS=2 -gg_RST_LEN=2
#echo "Clock domains = 2, Number of resets = 4" echo "****************************************************************************"
#ghdl -r --std=08 -frelaxed-rules $TB -gg_CLOCKS=2 -gg_RST_LEN=4 --vcd=waveform.vcd
echo " TEST CASE 4 "
echo "Clock domains = 2, Number of resets = 4"
ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_CLOCKS=2 -gg_RST_LEN=4
echo "****************************************************************************"
echo " TEST CASE 5 "
echo "Clock domains = 1, Number of resets = 1" echo "Clock domains = 1, Number of resets = 1"
ghdl -r --std=08 -frelaxed-rules $TB -gg_CLOCKS=1 -gg_RST_LEN=1 --vcd=waveform.vcd ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_CLOCKS=1 -gg_RST_LEN=1
#Printing result
echo "Test PASS"
...@@ -30,18 +30,14 @@ library ieee; ...@@ -30,18 +30,14 @@ library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
--randomization with manually seeds --OSVVM library
use ieee.math_real.all;
use std.env.finish;
--OSVVM
library osvvm; library osvvm;
use osvvm.RandomPkg.all; use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all; use osvvm.CoveragePkg.all;
-- Empty entity needed for TB
entity tb_gc_reset_multi_aasd is entity tb_gc_reset_multi_aasd is
generic ( generic (
g_seed : natural;
-- number of clock domains -- number of clock domains
g_CLOCKS : natural := 2; g_CLOCKS : natural := 2;
-- Number of clock ticks (per domain) that the input reset must remain -- Number of clock ticks (per domain) that the input reset must remain
...@@ -51,24 +47,21 @@ end entity; ...@@ -51,24 +47,21 @@ end entity;
architecture tb of tb_gc_reset_multi_aasd is architecture tb of tb_gc_reset_multi_aasd is
-- Constants
constant C_CLK_PERIOD : time := 10 ns; constant C_CLK_PERIOD : time := 10 ns;
-- Signals -- Signals
-- all async resets OR'ed together, active high
signal tb_arst_i : std_logic := '0'; signal tb_arst_i : std_logic := '0';
-- one clock signal per domain
signal tb_clks_i : std_logic_vector(g_CLOCKS-1 downto 0) := (others=>'0'); signal tb_clks_i : std_logic_vector(g_CLOCKS-1 downto 0) := (others=>'0');
-- one syncrhonous, active low reset output per domain
signal tb_rst_n_o : std_logic_vector(g_CLOCKS-1 downto 0); signal tb_rst_n_o : std_logic_vector(g_CLOCKS-1 downto 0);
signal stop : boolean;
signal s_cnt_rst : unsigned(g_RST_LEN-1 downto 0) := (others=>'0');
signal s_cnt_clks : unsigned(g_CLOCKS-1 downto 0) := (others=>'0');
signal s_rst : std_logic;
signal s_cnt_rst : unsigned(g_RST_LEN-1 downto 0) := (others=>'0'); subtype t_rst_chain is std_logic_vector(g_RST_LEN-1 downto 0);
signal s_cnt_clks : unsigned(g_CLOCKS-1 downto 0) := (others=>'0'); type t_rst_chains is array(natural range <>) of t_rst_chain;
signal s_rst_chains : t_rst_chains(g_CLOCKS-1 downto 0) := (others => (others => '0'));
--Shared variables for coverage use
shared variable cp_rst_i : covPType;
signal stop : boolean := FALSE;
begin begin
...@@ -82,87 +75,81 @@ begin ...@@ -82,87 +75,81 @@ begin
clks_i => tb_clks_i, clks_i => tb_clks_i,
rst_n_o => tb_rst_n_o); rst_n_o => tb_rst_n_o);
--Randomize stimulus --Stimulus
stim : process stim : process
--number of clk cycles
variable ncycles : natural; variable ncycles : natural;
--added for having seeds for random numbers variable data : RandomPType;
variable seed1, seed2 : integer := 1692013;
impure function rand_slv(len:integer) return std_logic_vector is
variable r : real;
variable slv : std_logic_vector(len - 1 downto 0);
begin
for i in slv'range loop
uniform(seed1, seed2, r);
slv(i) := '1' when r>0.5 else '0';
end loop;
return slv;
end function;
impure function rand_stdl(len:integer:=1) return std_logic is
variable r: real;
variable stdlog : std_logic;
begin
uniform(seed1,seed2,r);
stdlog := '1' when r>0.5 else '0';
return stdlog;
end function;
begin begin
while (NOW < 1 ms) loop data.InitSeed(g_seed);
wait for C_CLK_PERIOD; report "[STARTING] with seed = " & to_string(g_seed);
tb_clks_i <= rand_slv(g_CLOCKS); while NOW < 1 ms loop
tb_arst_i <= rand_stdl(1); wait for C_CLK_PERIOD;
ncycles := ncycles + 1; tb_clks_i <= data.randSlv(g_CLOCKS);
tb_arst_i <= data.randSlv(1)(1);
ncycles := ncycles + 1;
end loop; end loop;
report "Number of simulation cycles = " & to_string(ncycles); report "Number of simulation cycles = " & to_string(ncycles);
stop <= TRUE; stop <= TRUE;
report "Test PASS!";
wait; wait;
end process; end process;
-- Assertion 1: checking the values of the generics --------------------------------------------------------------------------------
assert (g_CLOCKS >0 and g_RST_LEN>0) -- Assertions --
report "g_CLOCKS and g_RST_LEN should be greater than zero" --------------------------------------------------------------------------------
severity failure;
-- Assertion 1: checking the values of the generics
assert (g_CLOCKS >0 and g_RST_LEN>0)
report "g_CLOCKS and g_RST_LEN should be greater than zero"
severity failure;
-- Assertion 2: for one clock domain -- Assertion 2: for one clock domain
single_clk_domain : if (g_CLOCKS = 1) generate single_clk_domain : if (g_CLOCKS = 1) generate
assert_check : for I in g_CLOCKS-1 downto 0 generate assert_check : for I in g_CLOCKS-1 downto 0 generate
check : process(tb_clks_i, tb_arst_i) check : process(tb_clks_i, tb_arst_i)
begin begin
if (tb_arst_i = '0') then if tb_arst_i = '0' then
if (tb_clks_i(i)='0') then if tb_clks_i(i)='0' then
s_cnt_rst <= s_cnt_rst + 1; s_cnt_rst <= s_cnt_rst + 1;
if (s_cnt_rst = g_RST_LEN) then if s_cnt_rst = g_RST_LEN then
s_cnt_rst <= (others=>'0'); s_cnt_rst <= (others=>'0');
assert (tb_rst_n_o(i) = '1') assert (tb_rst_n_o(i) = '1')
report "wrong" report "wrong" severity failure;
severity warning;
end if;
end if; end if;
end if;
else else
s_cnt_rst <= (others=>'0'); s_cnt_rst <= (others=>'0');
end if; end if;
end process; end process;
end generate;
end generate; end generate;
end generate;
-- Assertion 3: for many clock domains
many_clk_domains : if (g_CLOCKS > 1) generate s_rst <= tb_arst_i;
assert_check : for I in g_CLOCKS-1 downto 0 generate
check : process(tb_clks_i, tb_arst_i) -- Assertion 3: for many clock domains
begin many_clk_domains : if (g_CLOCKS > 1) generate
if (tb_arst_i = '0') then --if NOT reset assert_check : for I in g_CLOCKS-1 downto 0 generate
if (rising_edge(tb_clks_i(i))) then --and the clock is going from 0 to 1
assert (rising_edge(tb_rst_n_o(i))) check : process(tb_clks_i, s_rst)
report "WRONG" begin
severity warning; if s_rst = '1' then --if NOT reset
end if; s_rst_chains(i) <= (others=>'0');
elsif rising_edge(tb_clks_i(i)) then
s_rst_chains(i) <= '1' & s_rst_chains(i)(g_RST_LEN-1 downto 1);
end if; end if;
end process; end process;
end generate;
end generate; process(tb_clks_i, s_rst)
begin
if s_rst = '0' then
if rising_edge(tb_clks_i(i)) then
assert (s_rst_chains(i)(0) = tb_rst_n_o(i))
report "Wrong" severity warning;
end if;
end if;
end process;
end generate;
end generate;
end tb; end tb;
Testbench to verify the functionality of the gc_rr_arbiter general core. It uses GHDL simulator and OSVVM verification methodology. The test cases of this testbench arise from the g_size generic and they are : 1, 3, 7, 16, 31, 128.
The testing process is the following: It receives random input data (with random seeds). Two assertions are being used to bring self-checking capabilities in the testbench:
1. Output grant_o is the delayed (by 1 clock cycle) version of grant_comb_o
2. The valid values of grant_comb_o are 0, 1.
An example to the second assertion is the following, for g_size = 3:
req_i grant_o
000 000
001 001
010 010
011 010 / 001
100 100
101 100 / 001
110 100 / 010
111 100 / 010 / 001
Note: It is advised, for simulation purposes, to keep the generic values quite low in order to see the behavior of the module. For higher generic values, increase the simulation time.
Purpose of this test is to verify that :
1) grant has valid values like 0, 1, mod 2
for example, in case of g_size=3 valid values
are 0,1,2,4
req_i grant_o
000 000
001 001
010 010
011 010 / 001
100 100
101 100 / 001
110 100 / 010
111 100 / 010 / 001
2) grant_o is the delayed by 1 clock version of grant_comb_o
...@@ -7,26 +7,26 @@ TB=tb_gc_rr_arbiter ...@@ -7,26 +7,26 @@ TB=tb_gc_rr_arbiter
echo "Running simulation for $TB" echo "Running simulation for $TB"
echo "Width = 1" echo "Width = 1"
ghdl -r --std=08 -frelaxed-rules $TB -gg_size=1 ghdl -r --std=08 -frelaxed-rules $TB -gg_size=1 -gg_seed=$RANDOM
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 3" echo "Width = 3"
ghdl -r --std=08 -frelaxed-rules $TB -gg_size=3 ghdl -r --std=08 -frelaxed-rules $TB -gg_size=3 -gg_seed=$RANDOM
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 7" echo "Width = 7"
ghdl -r --std=08 -frelaxed-rules $TB -gg_size=7 ghdl -r --std=08 -frelaxed-rules $TB -gg_size=7 -gg_seed=$RANDOM
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 16" echo "Width = 16"
ghdl -r --std=08 -frelaxed-rules $TB -gg_size=16 ghdl -r --std=08 -frelaxed-rules $TB -gg_size=16 -gg_seed=$RANDOM
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 31" echo "Width = 31"
ghdl -r --std=08 -frelaxed-rules $TB -gg_size=31 ghdl -r --std=08 -frelaxed-rules $TB -gg_size=31 -gg_seed=$RANDOM
echo "********************************************************************************" echo "********************************************************************************"
echo "Width = 128" echo "Width = 128"
ghdl -r --std=08 -frelaxed-rules $TB -gg_size=128 ghdl -r --std=08 -frelaxed-rules $TB -gg_size=128 -gg_seed=$RANDOM
echo "********************************************************************************" echo "********************************************************************************"
...@@ -31,117 +31,103 @@ library ieee; ...@@ -31,117 +31,103 @@ library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library -- OSVVM library
--library osvvm; library osvvm;
--use osvvm.RandomPkg.all; use osvvm.RandomPkg.all;
--use osvvm.CoveragePkg.all; use osvvm.CoveragePkg.all;
entity tb_gc_rr_arbiter is entity tb_gc_rr_arbiter is
generic ( generic (
g_size : integer := 3); g_seed : natural;
g_size : integer := 3);
end entity; end entity;
architecture tb of tb_gc_rr_arbiter is architecture tb of tb_gc_rr_arbiter is
-- constants -- constants
constant C_CLK_PERIOD : time := 10 ns; constant C_CLK_PERIOD : time := 10 ns;
-- signals
signal tb_clk_i : std_logic;
signal tb_rst_n_i : std_logic;
signal tb_req_i : std_logic_vector(g_size-1 downto 0) := (others=>'0');
signal tb_grant_o : std_logic_vector(g_size-1 downto 0);
signal tb_grant_comb_o: std_logic_vector(g_size-1 downto 0);
signal stop : boolean; -- signals
signal s_grant_del : std_logic_vector(g_size-1 downto 0) := (others=>'0'); signal tb_clk_i : std_logic;
signal s_data_o : std_logic_vector(g_size-1 downto 0) := (others=>'0'); signal tb_rst_n_i : std_logic;
signal s_cnt : unsigned(1 downto 0); signal tb_req_i : std_logic_vector(g_size-1 downto 0) := (others=>'0');
signal tb_grant_o : std_logic_vector(g_size-1 downto 0);
signal tb_grant_comb_o : std_logic_vector(g_size-1 downto 0);
signal stop : boolean;
signal s_grant_del : std_logic_vector(g_size-1 downto 0) := (others=>'0');
signal s_data_o : std_logic_vector(g_size-1 downto 0) := (others=>'0');
signal s_cnt : unsigned(1 downto 0);
begin begin
-- Unit Under Test -- Unit Under Test
UUT : entity work.gc_rr_arbiter UUT : entity work.gc_rr_arbiter
generic map ( generic map (
g_size => g_size) g_size => g_size)
port map ( port map (
clk_i => tb_clk_i, clk_i => tb_clk_i,
rst_n_i => tb_rst_n_i, rst_n_i => tb_rst_n_i,
req_i => tb_req_i, req_i => tb_req_i,
grant_o => tb_grant_o, grant_o => tb_grant_o,
grant_comb_o => tb_grant_comb_o); grant_comb_o => tb_grant_comb_o);
-- Clock and reset generation -- Clock generation
clk_i_process : process clk_i_process : process
begin begin
while stop = FALSE loop while not stop loop
tb_clk_i <= '1'; tb_clk_i <= '1';
wait for C_CLK_PERIOD/2; wait for C_CLK_PERIOD/2;
tb_clk_i <= '0'; tb_clk_i <= '0';
wait for C_CLK_PERIOD/2; wait for C_CLK_PERIOD/2;
end loop; end loop;
wait; wait;
end process; end process;
tb_rst_n_i <= '0', '1' after 2*C_CLK_PERIOD; -- Reset generation
tb_rst_n_i <= '0', '1' after 2*C_CLK_PERIOD;
-- Stimulus
stim : process -- Stimulus
variable ncycles : natural; stim : process
variable seed1,seed2 : integer := 2000; variable ncycles : natural;
variable data : RandomPType;
impure function rand_slv(len:integer) return std_logic_vector is begin
variable r : real; data.InitSeed(g_seed);
variable slv : std_logic_vector(len - 1 downto 0); report "[STARTING] with seed = " & to_string(g_seed);
begin while NOW < 2 ms loop
for i in slv'range loop wait until (rising_edge(tb_clk_i) and tb_rst_n_i = '1');
uniform(seed1, seed2, r); tb_req_i <= data.randSlv(g_size);
slv(i) := '1' when r>0.5 else '0'; wait for g_size*C_CLK_PERIOD;
end loop; ncycles := ncycles + 1;
return slv; end loop;
end function; report "Number of Simulation cycles = " & to_string(ncycles);
report "Test PASS!";
begin stop <= TRUE;
while (NOW < 1 ms) loop wait;
wait until (rising_edge(tb_clk_i) and tb_rst_n_i = '1'); end process;
tb_req_i <= rand_slv(g_size);
wait for g_size*C_CLK_PERIOD; -- grant_comb_o is the same as gtant_o with 1 clock delay
ncycles := ncycles + 1; compare_grants : process(tb_clk_i)
end loop; begin
report "Number of Simulation cycles = " & to_string(ncycles); if rising_edge(tb_clk_i) then
report "Test PASS!"; if tb_rst_n_i = '1' then
stop <= TRUE; s_grant_del <= tb_grant_comb_o;
wait; assert (tb_grant_o = s_grant_del)
end process; report "grant_o and grant_comb_o not the same after 1 clock"
severity failure;
-- grant_comb_o is the same as gtant_o with 1 clock delay end if;
compare_grants : process(tb_clk_i) end if;
begin end process;
if (rising_edge(tb_clk_i)) then
if (tb_rst_n_i = '1') then process
s_grant_del <= tb_grant_comb_o; begin
assert (tb_grant_o = s_grant_del) while not stop loop
report "grant_o and grant_comb_o not the same after 1 clock" wait until tb_rst_n_i = '1';
severity failure; assert ((to_integer(unsigned(tb_grant_comb_o))) mod 2 = 0
end if;
end if;
end process;
process
begin
while (stop=FALSE) loop
wait until tb_rst_n_i = '1';
assert ((to_integer(unsigned(tb_grant_comb_o))) mod 2 = 0
or unsigned(tb_grant_comb_o) = 0 or unsigned(tb_grant_comb_o) = 0
or unsigned(tb_grant_comb_o) = 1) or unsigned(tb_grant_comb_o) = 1)
report "wrong grant" severity failure;
report "wrong grant" end loop;
severity warning; wait;
end loop; end process;
wait;
end process;
end tb; end tb;
Testbench to verify the functionality of the gc_serial_dac general core. It uses GHDL simulator and OSVVM verification methodology. This core is using 4 generics in the entity:
- g_num_data_bits : Number of DAC data word bits, LSBs
- g_num_extra_bits : Number of padding MSBs sent as zeros
- g_num_cs_select : Number of chip select inputs
- g_sclk_polarity : Serial clock polarity (0 for rising, 1 for falling edge)
A combination of them, create these test cases (there can be even more than them):
1. 2, 0, 1, 0
2. 2, 1, 2, 0
3. 4, 4, 2, 0
4. 16,8, 1, 0
5. 2, 0, 1, 1
6. 4, 2, 1, 1
7. 8, 4, 2, 1
8. 16,8, 2, 1
The testbench, receives random input data (with random seeds). It uses a similar logic to the one that RTL uses and generates a testbench output. One assertion exist in the testbench to bring self-checking capabilities in it and compare the output of the testbench with the one in the RTL code.
Simple coverage is being covered also:
- Reset has been asserted
- DAC is not busy
Note: It is advised, for simulation purposes, to keep the generic values quite low in order to see the behavior of the module. For higher generic values, increase the simulation time.
...@@ -7,34 +7,42 @@ TB=tb_gc_serial_dac ...@@ -7,34 +7,42 @@ TB=tb_gc_serial_dac
echo "Running simulation for $TB" echo "Running simulation for $TB"
echo "TEST CASE 1"
echo "DAC data word bits = 2, Padding MSBs sent as zeros= 0, chip select inputs = 1, Serial clock polarity = 0" echo "DAC data word bits = 2, Padding MSBs sent as zeros= 0, chip select inputs = 1, Serial clock polarity = 0"
ghdl -r --std=08 -frelaxed-rules $TB -gg_num_data_bits=2 -gg_num_extra_bits=0 -gg_num_cs_select=1 -gg_sclk_polarity=0 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_num_data_bits=2 -gg_num_extra_bits=0 -gg_num_cs_select=1 -gg_sclk_polarity=0
echo "**********************************************************************************************************" echo "**********************************************************************************************************"
echo "TEST CASE 2"
echo "DAC data word bits = 2, Padding MSBs sent as zeros= 1, chip select inputs = 2, Serial clock polarity = 0" echo "DAC data word bits = 2, Padding MSBs sent as zeros= 1, chip select inputs = 2, Serial clock polarity = 0"
ghdl -r --std=08 -frelaxed-rules $TB -gg_num_data_bits=2 -gg_num_extra_bits=1 -gg_num_cs_select=2 -gg_sclk_polarity=0 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_num_data_bits=2 -gg_num_extra_bits=1 -gg_num_cs_select=2 -gg_sclk_polarity=0
echo "**********************************************************************************************************" echo "**********************************************************************************************************"
echo "TEST CASE 3"
echo "DAC data word bits = 4, Padding MSBs sent as zeros= 4, chip select inputs = 2, Serial clock polarity = 0" echo "DAC data word bits = 4, Padding MSBs sent as zeros= 4, chip select inputs = 2, Serial clock polarity = 0"
ghdl -r --std=08 -frelaxed-rules $TB -gg_num_data_bits=4 -gg_num_extra_bits=4 -gg_num_cs_select=2 -gg_sclk_polarity=0 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_num_data_bits=4 -gg_num_extra_bits=4 -gg_num_cs_select=2 -gg_sclk_polarity=0
echo "**********************************************************************************************************" echo "**********************************************************************************************************"
echo "TEST CASE 4"
echo "DAC data word bits = 16, Padding MSBs sent as zeros= 8, chip select inputs = 1, Serial clock polarity = 0" echo "DAC data word bits = 16, Padding MSBs sent as zeros= 8, chip select inputs = 1, Serial clock polarity = 0"
ghdl -r --std=08 -frelaxed-rules $TB -gg_num_data_bits=16 -gg_num_extra_bits=8 -gg_num_cs_select=1 -gg_sclk_polarity=0 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_num_data_bits=16 -gg_num_extra_bits=8 -gg_num_cs_select=1 -gg_sclk_polarity=0
echo "**********************************************************************************************************" echo "**********************************************************************************************************"
echo "TEST CASE 5"
echo "DAC data word bits = 2, Padding MSBs sent as zeros= 0, chip select inputs = 1, Serial clock polarity = 1" echo "DAC data word bits = 2, Padding MSBs sent as zeros= 0, chip select inputs = 1, Serial clock polarity = 1"
ghdl -r --std=08 -frelaxed-rules $TB -gg_num_data_bits=2 -gg_num_extra_bits=0 -gg_num_cs_select=1 -gg_sclk_polarity=1 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_num_data_bits=2 -gg_num_extra_bits=0 -gg_num_cs_select=1 -gg_sclk_polarity=1
echo "**********************************************************************************************************" echo "**********************************************************************************************************"
echo "TEST CASE 6"
echo "DAC data word bits = 4, Padding MSBs sent as zeros= 2, chip select inputs = 1, Serial clock polarity = 1" echo "DAC data word bits = 4, Padding MSBs sent as zeros= 2, chip select inputs = 1, Serial clock polarity = 1"
ghdl -r --std=08 -frelaxed-rules $TB -gg_num_data_bits=4 -gg_num_extra_bits=2 -gg_num_cs_select=1 -gg_sclk_polarity=1 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_num_data_bits=4 -gg_num_extra_bits=2 -gg_num_cs_select=1 -gg_sclk_polarity=1
echo "**********************************************************************************************************" echo "**********************************************************************************************************"
echo "TEST CASE 7"
echo "DAC data word bits = 8, Padding MSBs sent as zeros= 4, chip select inputs = 2, Serial clock polarity = 1" echo "DAC data word bits = 8, Padding MSBs sent as zeros= 4, chip select inputs = 2, Serial clock polarity = 1"
ghdl -r --std=08 -frelaxed-rules $TB -gg_num_data_bits=8 -gg_num_extra_bits=4 -gg_num_cs_select=2 -gg_sclk_polarity=1 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_num_data_bits=8 -gg_num_extra_bits=4 -gg_num_cs_select=2 -gg_sclk_polarity=1
echo "**********************************************************************************************************" echo "**********************************************************************************************************"
echo "TEST CASE 8"
echo "DAC data word bits = 16, Padding MSBs sent as zeros= 8, chip select inputs = 2, Serial clock polarity = 1" echo "DAC data word bits = 16, Padding MSBs sent as zeros= 8, chip select inputs = 2, Serial clock polarity = 1"
ghdl -r --std=08 -frelaxed-rules $TB -gg_num_data_bits=16 -gg_num_extra_bits=8 -gg_num_cs_select=2 -gg_sclk_polarity=1 ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_num_data_bits=16 -gg_num_extra_bits=8 -gg_num_cs_select=2 -gg_sclk_polarity=1
echo "**********************************************************************************************************" echo "**********************************************************************************************************"
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