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
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
#This is a simple script to run simulations
#in GHDL
#This is a simple script to run simulations in GHDL
TB=tb_gc_negedge
echo "Running simulation for $TB"
echo " TEST CASE 1 "
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"
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"
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"
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,9 +28,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
......@@ -38,6 +35,7 @@ use osvvm.CoveragePkg.all;
entity tb_gc_negedge is
generic (
g_seed : natural;
g_ASYNC_RST : boolean := FALSE;
g_CLOCK_EDGE : string := "positive");
end entity;
......@@ -52,7 +50,6 @@ architecture tb of tb_gc_negedge is
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
......@@ -73,7 +70,7 @@ begin
data_i => tb_data_i,
pulse_o => tb_pulse_o);
-- Clock and reset generation
-- Clock generation
clk_proc : process
begin
while STOP = FALSE loop
......@@ -85,27 +82,20 @@ begin
wait;
end process clk_proc;
-- Reset generation
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;
variable data : RandomPType;
begin
wait until (tb_rst_n_i='1');
while (NOW < 1 ms) loop
wait until (rising_edge(tb_clk_i));
tb_data_i <= rand_stdl(1);
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
wait until tb_rst_n_i='1';
while NOW < 4 ms loop
wait until rising_edge(tb_clk_i);
tb_data_i <= data.randSlv(1)(1);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
......@@ -115,39 +105,40 @@ begin
end process;
--------------------------------------------------------------------------------
-- Assertions
-- Assertions --
--------------------------------------------------------------------------------
--Assertion to check that the width of the output pulse
--is asserted for only one clock cycle
-- 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
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;
severity error;
end if;
end loop;
wait;
end process;
-- Check that the output pulse is asserted
-- in the falling edge of the input pulse
check_edge : process
check_negedge : 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;
while not stop loop
wait until falling_edge(tb_data_i);
wait for 0 ns; --wait for delta time
assert (tb_pulse_o='1')
report "Negative edge didn't detect" severity failure;
end loop;
wait;
end process;
--------------------------------------------------------------------------------
-- Coverage
-- Coverage --
--------------------------------------------------------------------------------
--sets up coverpoint bins
......@@ -159,8 +150,6 @@ begin
wait;
end process init_coverage;
-- Sample the coverpoints
-- sample coverpoints for reset
sample_rst_n_i : process
begin
......@@ -174,7 +163,7 @@ begin
-- sample coverpoints for input data
sample_data_i : process(tb_clk_i)
begin
if (rising_edge(tb_clk_i)) then
if rising_edge(tb_clk_i) then
cp_data_i.ICover(to_integer(tb_data_i='1'));
end if;
end process;
......@@ -183,7 +172,7 @@ begin
clock_edge_pos : if (g_CLOCK_EDGE="positive") generate
sample_pulse_o : process(tb_clk_i)
begin
if (rising_edge(tb_clk_i)) then
if rising_edge(tb_clk_i) then
cp_pulse_o.ICover(to_integer(tb_pulse_o='1'));
end if;
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
#This is a simple script to run simulations
#in GHDL
#This is a simple script to run simulations in GHDL
TB=tb_gc_posedge
echo "Running simulation for $TB"
echo " TEST CASE 1 "
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"
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"
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"
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,9 +28,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
......@@ -38,13 +35,14 @@ use osvvm.CoveragePkg.all;
entity tb_gc_posedge is
generic (
g_ASYNC_RST : boolean := FALSE;
g_CLOCK_EDGE : string := "positive");
g_seed : natural;
g_ASYNC_RST : boolean;
g_CLOCK_EDGE : string);
end entity;
architecture tb of tb_gc_posedge is
-- constants
-- Constants
constant C_CLK_PERIOD : time := 10 ns;
-- Signals
......@@ -52,7 +50,6 @@ architecture tb of tb_gc_posedge is
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
......@@ -63,7 +60,7 @@ architecture tb of tb_gc_posedge is
begin
-- Unit Under Test
UUT : entity work.gc_negedge
UUT : entity work.gc_posedge
generic map (
g_ASYNC_RST => g_ASYNC_RST,
g_CLOCK_EDGE => g_CLOCK_EDGE)
......@@ -73,7 +70,7 @@ begin
data_i => tb_data_i,
pulse_o => tb_pulse_o);
-- Clock and reset generation
-- Clock generation
clk_proc : process
begin
while STOP = FALSE loop
......@@ -85,27 +82,20 @@ begin
wait;
end process clk_proc;
-- Reset generation
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;
variable data : RandomPType;
begin
uniform(seed1,seed2,r);
stdlog:= '1' when r>0.5 else '0';
return stdlog;
end function;
begin
wait until (tb_rst_n_i='1');
while (NOW < 1 ms) loop
wait until (rising_edge(tb_clk_i));
tb_data_i <= rand_stdl(1);
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
wait until tb_rst_n_i='1';
while NOW < 2 ms loop
wait until rising_edge(tb_clk_i);
tb_data_i <= data.randSlv(1)(1);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
......@@ -115,39 +105,41 @@ begin
end process;
--------------------------------------------------------------------------------
-- Assertions
-- 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
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 if;
end loop;
wait;
end process;
-- Check that the output pulse is asserted
-- in the falling edge of the input pulse
-- in the rising 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"
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 if;
end loop;
wait;
end process;
--------------------------------------------------------------------------------
-- Coverage
-- Coverage --
--------------------------------------------------------------------------------
--sets up coverpoint bins
......@@ -159,8 +151,6 @@ begin
wait;
end process init_coverage;
-- Sample the coverpoints
-- sample coverpoints for reset
sample_rst_n_i : process
begin
......@@ -174,7 +164,7 @@ begin
-- sample coverpoints for input data
sample_data_i : process(tb_clk_i)
begin
if (rising_edge(tb_clk_i)) then
if rising_edge(tb_clk_i) then
cp_data_i.ICover(to_integer(tb_data_i='1'));
end if;
end process;
......@@ -207,7 +197,6 @@ begin
cp_rst_i.writebin;
cp_data_i.writebin;
cp_pulse_o.writebin;
report "PASS";
end process;
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
echo "Running simulation for $TB"
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 "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 "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 "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 "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 "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 "********************************************************************************"
......@@ -30,16 +30,14 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library
--library osvvm;
--use osvvm.RandomPkg.all;
--use osvvm.CoveragePkg.all;
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
entity tb_gc_prio_encoder is
generic (
g_seed : natural;
g_width : integer := 32);
end entity;
......@@ -73,7 +71,6 @@ architecture tb of tb_gc_prio_encoder is
-- signals
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 stop : boolean;
type t_stages_array is array (0 to C_STAGES) of std_logic_vector(g_width-1 downto 0);
......@@ -93,23 +90,13 @@ begin
-- Stimulus
stim : process
variable ncycles : natural;
variable seed1, seed2 : integer := 1992;
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;
variable data : RandomPType;
begin
while (NOW < 2 ms) loop
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
while NOW < 2 ms loop
wait for 10 ns; --give every 10ns a new input
tb_d_i <= rand_slv(g_width);
tb_d_i <= data.randSlv(g_width);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
......@@ -125,9 +112,11 @@ begin
nof_stages : for i in 1 to C_STAGES 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);
end generate;
case_2 : if not (j mod (2 ** i) >= (2 ** (i-1))) generate
s_stage(i)(j) <= s_stage(i-1)(j);
end generate;
......@@ -137,15 +126,13 @@ begin
s_data_o <= s_stage(C_STAGES);
--------------------------------------------------------------------------------
-- Assertions
-- Assertions --
--------------------------------------------------------------------------------
assert (s_data_o = tb_therm_o)
report "Output data mismatch"
severity failure;
report "Output data mismatch" severity failure;
assert (g_width > 0)
report "Invalid value of data width"
severity failure;
report "Invalid value of data width" severity failure;
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
echo "Running simulation for $TB"
ghdl -r --std=08 -frelaxed-rules $TB
ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM
......@@ -27,18 +27,19 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.finish;
use ieee.math_real.all;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
entity tb_gc_pulse_synchronizer is
generic (
g_seed : natural);
end entity;
architecture tb of tb_gc_pulse_synchronizer is
-- Constants
constant C_CLK_IN_PERIOD : time := 10 ns;
constant C_CLK_OUT_PERIOD : time := 8 ns;
......@@ -50,7 +51,7 @@ architecture tb of tb_gc_pulse_synchronizer is
signal tb_d_p_i : std_logic := '0';
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_data_i : covPType;
shared variable cp_data_o : covPType;
......@@ -69,10 +70,10 @@ begin
d_p_i => tb_d_p_i,
q_p_o => tb_q_p_o);
--clocks and resets generation
--clocks generation
clk_in_gen : process
begin
while STOP = FALSE loop
while not stop loop
tb_clk_in_i <= '1';
wait for C_CLK_IN_PERIOD/2;
tb_clk_in_i <= '0';
......@@ -83,7 +84,7 @@ begin
clk_out_gen : process
begin
while STOP = FALSE loop
while not stop loop
tb_clk_out_i <= '1';
wait for C_CLK_OUT_PERIOD/2;
tb_clk_out_i <= '0';
......@@ -92,52 +93,48 @@ begin
wait;
end process;
-- Reset generation
tb_rst_n_i <= '0', '1' after 2*C_CLK_IN_PERIOD;
-- Stimulus
stim : process
variable data_i : RandomPType;
variable seed1, seed2 : integer := 999;
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;
variable data : RandomPType;
variable ncycles : natural;
begin
while (NOW < 2 ms) loop
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
while NOW < 2 ms loop
wait until (rising_edge(tb_clk_in_i) and tb_d_ready_o = '1');
tb_d_p_i <= rand_stdl(1);
tb_d_p_i <= data.randSlv(1)(1);
ncycles := ncycles + 1;
end loop;
report "Number of Simulation cycles = " & to_string(ncycles);
report "Test PASS!";
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
begin
wait until (tb_rst_n_i = '1');
while (stop=FALSE) loop
while not stop loop
wait until falling_edge(tb_d_ready_o);
wait until rising_edge(tb_clk_out_i);
wait for 2*C_CLK_OUT_PERIOD;
report "here";
assert (tb_q_p_o = '1')
report "output is wrong"
severity failure;
report "output is wrong" severity failure;
end loop;
wait;
end process;
--------------------------------------------------------------------------------
-- Coverage
-- Coverage --
--------------------------------------------------------------------------------
--sets up coverpoint bins
......@@ -183,7 +180,6 @@ begin
cp_rst_in_i.writebin;
cp_data_i.writebin;
cp_data_o.writebin;
report "PASS";
end process;
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
echo "Running simulation for $TB"
ghdl -r --std=08 -frelaxed-rules $TB
ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM
......@@ -29,21 +29,22 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.finish;
use ieee.math_real.all;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
entity tb_gc_pulse_synchronizer2 is
generic (
g_seed : natural);
end entity;
architecture tb of tb_gc_pulse_synchronizer2 is
constant C_CLK_IN_PERIOD : time := 10 ns;
constant C_CLK_OUT_PERIOD : time := 8 ns;
-- Constants
constant C_CLK_IN_PERIOD : time := 5 ns;
constant C_CLK_OUT_PERIOD : time := 10 ns;
-- signals
signal tb_clk_in_i : std_logic;
......@@ -54,18 +55,17 @@ architecture tb of tb_gc_pulse_synchronizer2 is
signal tb_d_ack_p_o : std_logic;
signal tb_d_p_i : std_logic := '0';
signal tb_q_p_o : std_logic;
signal stop : boolean := FALSE;
-- variables used for coverage
-- 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;
signal stop : boolean := FALSE;
begin
--Unit Under Test
-- Unit Under Test
UUT : entity work.gc_pulse_synchronizer2
port map (
clk_in_i => tb_clk_in_i,
......@@ -77,10 +77,10 @@ begin
d_p_i => tb_d_p_i,
q_p_o => tb_q_p_o);
--clock and reset generation
-- Clocks generation
clk_in_gen : process
begin
while STOP = FALSE loop
while not stop loop
tb_clk_in_i <= '1';
wait for C_CLK_IN_PERIOD/2;
tb_clk_in_i <= '0';
......@@ -91,7 +91,7 @@ begin
clk_out_gen : process
begin
while STOP = FALSE loop
while not stop loop
tb_clk_out_i <= '1';
wait for C_CLK_OUT_PERIOD/2;
tb_clk_out_i <= '0';
......@@ -100,36 +100,31 @@ begin
wait;
end process;
-- Resets generation
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;
-- Stimulus
stim : process
variable data : RandomPType;
variable ncycles : natural;
variable seed1, seed2 : integer := 999;
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
while (NOW < 1 ms) loop
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
while NOW < 2 ms loop
wait until (rising_edge(tb_clk_in_i) and tb_d_ready_o = '1');
tb_d_p_i <= rand_stdl(1);
tb_d_p_i <= data.randSlv(1)(1);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
report "Number of Simulation cycles = " & to_string(ncycles);
report "Test PASS!";
stop <= TRUE;
wait;
end process;
--------------------------------------------------------------------------------
-- Assertions
-- Assertions --
--------------------------------------------------------------------------------
-- Self-Checking : after the de-assertion of ready_o, after one clock cycle
......@@ -138,19 +133,18 @@ begin
valid_out_data : process
begin
wait until (tb_rst_in_n_i = '1' and tb_rst_out_n_i = '1');
while (stop=FALSE) loop
while not stop loop
wait until falling_edge(tb_d_ready_o);
wait until rising_edge(tb_clk_out_i);
wait for 2*C_CLK_OUT_PERIOD;
assert (tb_q_p_o = '1')
report "output is wrong"
severity failure;
report "output is wrong" severity failure;
end loop;
wait;
end process;
--------------------------------------------------------------------------------
-- Coverage
-- Coverage --
--------------------------------------------------------------------------------
--sets up coverpoint bins
......@@ -208,7 +202,6 @@ begin
cp_rst_in_i.writebin;
cp_data_i.writebin;
cp_data_o.writebin;
report "PASS";
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 @@
TB=tb_gc_reset
echo "Running simulation for $TB"
echo ""
echo " TEST CASE 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"
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"
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"
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 "****************************************************************************"
......@@ -27,9 +27,6 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
......@@ -37,6 +34,7 @@ use osvvm.CoveragePkg.all;
entity tb_gc_reset is
generic (
g_seed : natural;
g_clocks : natural := 2;
g_logdelay : natural := 4;
g_syncdepth : natural := 4);
......@@ -44,7 +42,7 @@ end entity;
architecture tb of tb_gc_reset is
-- constants
-- Constants
constant C_CLK_PERIOD : time := 10 ns;
constant C_LOCKED_DONE: unsigned(g_logdelay-1 downto 0):=(others=>'1');
......@@ -53,7 +51,6 @@ architecture tb of tb_gc_reset is
signal tb_locked_i : std_logic := '1'; -- All the PLL locked signals ANDed together
signal tb_clks_i : std_logic_vector(g_clocks-1 downto 0);
signal tb_rstn_o : std_logic_vector(g_clocks-1 downto 0);
signal stop : boolean;
subtype t_sync_chains is std_logic_vector(g_syncdepth-1 downto 0);
......@@ -64,7 +61,7 @@ architecture tb of tb_gc_reset is
signal s_master_rstn : std_logic := '0';
signal s_rstn_o : std_logic_vector(g_clocks-1 downto 0) := (others=>'0');
-- variables used for coverage
-- Shared variables used for coverage
shared variable cp_master_rstn : covPType;
shared variable cp_rstn_o : covPType;
......@@ -85,7 +82,7 @@ begin
-- Clock generation
clk_proc : process
begin
while STOP = FALSE loop
while not stop loop
tb_free_clk_i <= '1';
wait for C_CLK_PERIOD/2;
tb_free_clk_i <= '0';
......@@ -96,34 +93,15 @@ begin
-- Stimulus
stim : process
variable seed1, seed2 : integer := 1992;
variable data : RandomPType;
variable ncycles : natural;
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;
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
while (NOW < 40 ms) loop
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
while NOW < 8 ms loop
wait until (rising_edge(tb_free_clk_i));
tb_locked_i <= rand_stdl(1);
tb_clks_i <= rand_slv(g_clocks);
tb_locked_i <= data.randSlv(1)(1);
tb_clks_i <= data.randSlv(g_clocks);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
......@@ -143,7 +121,7 @@ begin
s_master_rstn <= '0';
s_locked_cnt <= (others=>'0');
else
if (rising_edge(tb_free_clk_i)) then
if rising_edge(tb_free_clk_i) then
if s_locked_cnt = C_LOCKED_DONE then
s_master_rstn <= '1';
else
......@@ -158,7 +136,7 @@ begin
sync_chains : for i in 0 to g_clocks-1 generate
process(tb_clks_i(i))
begin
if (rising_edge(tb_clks_i(i))) then
if rising_edge(tb_clks_i(i)) then
s_sync_chains(i) <= s_master_rstn & s_sync_chains(i)(g_syncdepth-1 downto 1);
end if;
end process;
......@@ -166,20 +144,19 @@ begin
end generate;
--------------------------------------------------------------------------------
-- Assertions
-- Assertions --
--------------------------------------------------------------------------------
compare_outputs : process(tb_free_clk_i)
begin
if rising_edge(tb_free_clk_i) then
assert (tb_rstn_o = s_rstn_o)
report "Output mimatch"
severity failure;
report "Output mimatch" severity failure;
end if;
end process;
--------------------------------------------------------------------------------
-- Coverage
-- Coverage --
--------------------------------------------------------------------------------
--sets up coverpoint bins
......@@ -203,7 +180,7 @@ begin
sample_rstn_o : process(tb_free_clk_i)
begin
for i in 0 to g_clocks-1 loop
if (rising_edge(tb_free_clk_i)) then
if rising_edge(tb_free_clk_i) then
cp_rstn_o.ICover(to_integer(s_rstn_o(i)='1'));
end if;
end loop;
......@@ -215,9 +192,6 @@ begin
wait until stop;
cp_master_rstn.writebin;
cp_rstn_o.writebin;
report "PASS";
end process;
end tb;
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 @@
TB=tb_gc_reset_multi_aasd
echo "Running simulation for $TB"
echo ""
echo " TEST CASE 1 "
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"
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"
#ghdl -r --std=08 -frelaxed-rules $TB -gg_CLOCKS=2 -gg_RST_LEN=2 --vcd=waveform.vcd
echo " TEST CASE 3 "
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 "****************************************************************************"
#echo "Clock domains = 2, Number of resets = 4"
#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"
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;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--randomization with manually seeds
use ieee.math_real.all;
use std.env.finish;
--OSVVM
--OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
-- Empty entity needed for TB
entity tb_gc_reset_multi_aasd is
generic (
g_seed : natural;
-- number of clock domains
g_CLOCKS : natural := 2;
-- Number of clock ticks (per domain) that the input reset must remain
......@@ -51,24 +47,21 @@ end entity;
architecture tb of tb_gc_reset_multi_aasd is
-- Constants
constant C_CLK_PERIOD : time := 10 ns;
-- Signals
-- all async resets OR'ed together, active high
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');
-- one syncrhonous, active low reset output per domain
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;
--Shared variables for coverage use
shared variable cp_rst_i : covPType;
signal stop : boolean := FALSE;
subtype t_rst_chain is std_logic_vector(g_RST_LEN-1 downto 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'));
begin
......@@ -82,45 +75,29 @@ begin
clks_i => tb_clks_i,
rst_n_o => tb_rst_n_o);
--Randomize stimulus
--Stimulus
stim : process
--number of clk cycles
variable ncycles : natural;
--added for having seeds for random numbers
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;
variable data : RandomPType;
begin
while (NOW < 1 ms) loop
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
while NOW < 1 ms loop
wait for C_CLK_PERIOD;
tb_clks_i <= rand_slv(g_CLOCKS);
tb_arst_i <= rand_stdl(1);
tb_clks_i <= data.randSlv(g_CLOCKS);
tb_arst_i <= data.randSlv(1)(1);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
stop <= TRUE;
report "Test PASS!";
wait;
end process;
--------------------------------------------------------------------------------
-- Assertions --
--------------------------------------------------------------------------------
-- 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"
......@@ -131,14 +108,13 @@ begin
assert_check : for I in g_CLOCKS-1 downto 0 generate
check : process(tb_clks_i, tb_arst_i)
begin
if (tb_arst_i = '0') then
if (tb_clks_i(i)='0') then
if tb_arst_i = '0' then
if tb_clks_i(i)='0' then
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');
assert (tb_rst_n_o(i) = '1')
report "wrong"
severity warning;
report "wrong" severity failure;
end if;
end if;
else
......@@ -148,21 +124,32 @@ begin
end generate;
end generate;
s_rst <= tb_arst_i;
-- Assertion 3: for many clock domains
many_clk_domains : if (g_CLOCKS > 1) 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, s_rst)
begin
if s_rst = '1' then --if NOT reset
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 process;
process(tb_clks_i, s_rst)
begin
if (tb_arst_i = '0') then --if NOT reset
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)))
report "WRONG"
severity warning;
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;
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
echo "Running simulation for $TB"
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 "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 "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 "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 "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 "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 "********************************************************************************"
......@@ -31,16 +31,14 @@ library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library
--library osvvm;
--use osvvm.RandomPkg.all;
--use osvvm.CoveragePkg.all;
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
entity tb_gc_rr_arbiter is
generic (
g_seed : natural;
g_size : integer := 3);
end entity;
......@@ -54,8 +52,7 @@ architecture tb of tb_gc_rr_arbiter is
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 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');
......@@ -74,10 +71,10 @@ begin
grant_o => tb_grant_o,
grant_comb_o => tb_grant_comb_o);
-- Clock and reset generation
-- Clock generation
clk_i_process : process
begin
while stop = FALSE loop
while not stop loop
tb_clk_i <= '1';
wait for C_CLK_PERIOD/2;
tb_clk_i <= '0';
......@@ -86,28 +83,19 @@ begin
wait;
end process;
-- Reset generation
tb_rst_n_i <= '0', '1' after 2*C_CLK_PERIOD;
-- Stimulus
stim : process
variable ncycles : natural;
variable seed1,seed2 : integer := 2000;
impure function rand_slv(len:integer) return std_logic_vector is
variable r : real;
variable slv : std_logic_vector(len - 1 downto 0);
variable data : RandomPType;
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
while (NOW < 1 ms) loop
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
while NOW < 2 ms loop
wait until (rising_edge(tb_clk_i) and tb_rst_n_i = '1');
tb_req_i <= rand_slv(g_size);
tb_req_i <= data.randSlv(g_size);
wait for g_size*C_CLK_PERIOD;
ncycles := ncycles + 1;
end loop;
......@@ -120,8 +108,8 @@ begin
-- grant_comb_o is the same as gtant_o with 1 clock delay
compare_grants : process(tb_clk_i)
begin
if (rising_edge(tb_clk_i)) then
if (tb_rst_n_i = '1') then
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '1' then
s_grant_del <= tb_grant_comb_o;
assert (tb_grant_o = s_grant_del)
report "grant_o and grant_comb_o not the same after 1 clock"
......@@ -132,14 +120,12 @@ begin
process
begin
while (stop=FALSE) loop
while not stop 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) = 1)
report "wrong grant"
severity warning;
report "wrong grant" severity failure;
end loop;
wait;
end process;
......
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
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"
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 "TEST CASE 2"
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 "TEST CASE 3"
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 "TEST CASE 4"
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 "TEST CASE 5"
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 "TEST CASE 6"
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 "TEST CASE 7"
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 "TEST CASE 8"
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 "**********************************************************************************************************"
......@@ -31,13 +31,9 @@
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.finish;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
......@@ -45,10 +41,11 @@ use osvvm.CoveragePkg.all;
entity tb_gc_serial_dac is
generic (
g_num_data_bits : integer := 2; --16;
g_num_extra_bits : integer := 0; --8;
g_num_cs_select : integer := 1; --2;
g_sclk_polarity : integer := 0); --1);
g_seed : natural;
g_num_data_bits : integer := 2;
g_num_extra_bits : integer := 0;
g_num_cs_select : integer := 1;
g_sclk_polarity : integer := 0);
end entity;
architecture tb of tb_gc_serial_dac is
......@@ -67,7 +64,6 @@ architecture tb of tb_gc_serial_dac is
signal tb_dac_sclk_o : std_logic;
signal tb_dac_sdata_o : std_logic;
signal tb_busy_o : std_logic;
signal stop : boolean;
signal s_data_o : std_logic_vector(g_num_data_bits+g_num_extra_bits-1 downto 0);
signal s_divider : unsigned(11 downto 0);
......@@ -76,9 +72,10 @@ architecture tb of tb_gc_serial_dac is
signal s_dac_sclk : std_logic;
signal s_dac_data_o: std_logic;
-- variables used for coverage
-- Shared variables used for coverage
shared variable cp_rst_n_i : covPType;
shared variable cp_busy_o : covPType;
begin
-- Unit Under Test
......@@ -103,7 +100,7 @@ begin
-- Clock generation
clk_proc : process
begin
while STOP = FALSE loop
while not stop loop
tb_clk_i <= '1';
wait for C_CLK_PERIOD/2;
tb_clk_i <= '0';
......@@ -112,41 +109,21 @@ begin
wait;
end process clk_proc;
-- Reset generation
tb_rst_n_i <= '0', '1' after 2*C_CLK_PERIOD;
-- Stimulus
stim : process
variable seed1, seed2 : integer := 1992;
variable data : RandomPType;
variable ncycles : natural;
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;
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
while (NOW < 4 ms) loop
while NOW < 4 ms loop
-- when we are not busy, we sent data
wait until (rising_edge(tb_clk_i) and tb_busy_o = '0');
tb_value_i <= rand_slv(g_num_data_bits);
tb_load_i <= rand_stdl(1);
tb_cs_sel_i <= rand_slv(g_num_cs_select);
tb_sclk_divsel_i <= rand_slv(3);
tb_value_i <= data.randSlv(g_num_data_bits);
tb_load_i <= data.randSlv(1)(1);
tb_cs_sel_i <= data.randSlv(g_num_cs_select);
tb_sclk_divsel_i <= data.randSlv(3);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
......@@ -156,7 +133,7 @@ begin
end process stim;
--------------------------------------------------------------------------------
-- Reproducing the RTL behavior
-- Reproducing the RTL behavior --
--------------------------------------------------------------------------------
divider_sel : process (s_divider, tb_sclk_divsel_i)
......@@ -180,7 +157,7 @@ begin
if tb_load_i = '1' then
s_divider <= (others => '0');
elsif tb_busy_o = '1' then
if(s_div_muxed = '1') then
if s_div_muxed = '1' then
s_divider <= (others => '0');
else
s_divider <= s_divider + 1;
......@@ -223,8 +200,8 @@ begin
data_out : process(tb_clk_i)
begin
if (rising_edge(tb_clk_i)) then
if (tb_rst_n_i = '0') then
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
s_data_o <= (others=>'0');
else
if (tb_load_i = '1' and tb_busy_o = '0') then
......@@ -241,22 +218,21 @@ begin
s_dac_data_o <= s_data_o(s_data_o'left);
--------------------------------------------------------------------------------
-- Assertions
-- Assertions --
--------------------------------------------------------------------------------
process(tb_clk_i)
begin
if falling_edge(tb_clk_i) then
if (tb_rst_n_i = '1') then
if tb_rst_n_i = '1' then
assert (s_dac_data_o = tb_dac_sdata_o)
report "data mismatch"
severity failure;
report "data mismatch" severity failure;
end if;
end if;
end process;
--------------------------------------------------------------------------------
-- Coverage
-- Coverage --
--------------------------------------------------------------------------------
-- sets up coverpoint bins
......@@ -292,7 +268,6 @@ begin
wait until stop;
cp_rst_n_i.writebin;
cp_busy_o.writebin;
report "PASS!";
end process;
end tb;
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