You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

277 lines
8.9 KiB

-- Simple wishbone verification IP
-- For use with GHDL only
-- Suitable for simulation & formal verification
-- Copyright 2021 by Torsten Meissner (programming@goodcleanfun.de)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library wishbone;
use wishbone.wishbone_pkg.all;
entity wishbone_vip is
generic (
MODE : string := "CLASSIC";
ASSERTS : boolean := true;
COVERAGE : boolean := true
);
port (
-- syscon signals
WbSysCon : in t_wb_syscon;
-- master signals
WbMaster : in t_wb_master;
-- slave signals
WbSlave : in t_wb_slave
);
end entity wishbone_vip;
architecture verification of wishbone_vip is
function count_ones (data : in std_logic_vector) return natural is
variable v_return : natural := 0;
begin
for i in data'range loop
if (to_x01(data(i)) = '1') then
v_return := v_return + 1;
end if;
end loop;
return v_return;
end function count_ones;
function one_hot (data : in std_logic_vector) return boolean is
begin
return count_ones(data) = 1;
end function one_hot;
function one_hot_0 (data : in std_logic_vector) return boolean is
begin
return count_ones(data) <= 1;
end function one_hot_0;
alias Clk is WbSysCon.Clk;
alias Reset is WbSysCon.Reset;
signal s_wb_slave_resp : std_logic_vector(2 downto 0);
begin
s_wb_slave_resp <= WbSlave.Rty & WbSlave.Err & WbSlave.Ack;
-- Static interface checks
-- Always enabled, regardless of generic ASSERTS setting
MODE_a : assert MODE = "CLASSIC"
report "ERROR: Unsupported mode"
severity failure;
DATA_MS_WIDTH_a : assert WbMaster.Dat'length = 8 or WbMaster.Dat'length = 16 or
WbMaster.Dat'length = 32 or WbMaster.Dat'length = 64
report "ERROR: Invalid Master Data length"
severity failure;
DATA_SM_WIDTH_a : assert WbSlave.Dat'length = 8 or WbSlave.Dat'length = 16 or
WbSlave.Dat'length = 32 or WbSlave.Dat'length = 64
report "ERROR: Invalid Slave Data length"
severity failure;
DATA_EQUAL_WIDTH_a : assert WbMaster.Dat'length = WbSlave.Dat'length
report "ERROR: Master & Slave Data don't have equal length"
severity failure;
default clock is rising_edge(Clk);
ASSERTS_G : if ASSERTS generate
signal s_wb_master : t_wb_master(Adr(WbMaster.Adr'range),
Dat(WbMaster.Dat'range),
Sel(WbMaster.Sel'range),
Tgc(WbMaster.Tgc'range),
Tga(WbMaster.Tga'range),
Tgd(WbMaster.Tgd'range));
signal s_wb_slave : t_wb_slave(Dat(WbSlave.Dat'range),
Tgd(WbSlave.Tgd'range));
begin
-- Create copies of bus signals
process (Clk) is
begin
if rising_edge(Clk) then
s_wb_master <= WbMaster;
s_wb_slave <= WbSlave;
end if;
end process;
sequence s_stb_not_term is {WbMaster.Stb = '1' and s_wb_slave_resp = "000"};
-- RULE 3.20
-- Synchonous reset
STB_RESET_a : assert always Reset -> next not WbMaster.Stb;
CYC_RESET_a : assert always Reset -> next not WbMaster.Cyc;
-- RULE 3.25
STB_CYC_0_a : assert always WbMaster.Stb -> WbMaster.Cyc;
STB_CYC_1_a : assert always WbMaster.Stb and not s_wb_master.Stb ->
WbMaster.Cyc until not WbMaster.Stb;
-- RULE 3.35
ACK_ERR_RTY_CYC_STB_a : assert always one_hot(s_wb_slave_resp) ->
s_wb_master.Cyc and s_wb_master.Stb;
-- RULE 3.45
ACK_ERR_RTY_ONEHOT_a : assert always one_hot_0(s_wb_slave_resp);
-- RULE 3.50
ACK_ERR_RTY_STB_a : assert always one_hot(s_wb_slave_resp) -> WbMaster.Stb;
-- RULE 3.60
ADR_STABLE_STB_a : assert always s_stb_not_term |=> WbMaster.Adr = s_wb_master.Adr;
DAT_STABLE_STB_a : assert always s_stb_not_term |=> WbMaster.Dat = s_wb_master.Dat;
SEL_STABLE_STB_a : assert always s_stb_not_term |=> WbMaster.Sel = s_wb_master.Sel;
WE_STABLE_STB_a : assert always s_stb_not_term |=> WbMaster.We = s_wb_master.We;
TGC_STABLE_STB_a : assert always s_stb_not_term |=> WbMaster.Tgc = s_wb_master.Tgc;
TGA_STABLE_STB_a : assert always s_stb_not_term |=> WbMaster.Tga = s_wb_master.Tga;
TGD_STABLE_STB_a : assert always s_stb_not_term |=> WbMaster.Tgd = s_wb_master.Tgd;
end generate ASSERTS_G;
COVERAGE_G : if COVERAGE generate
CLASSIC_G : if MODE = "CLASSIC" generate
-- Non waited single cycles, async slave termination or slave knows
-- address in advance or it doesn't matter
sequence s_single_read (boolean resp) is {
not WbMaster.Cyc;
WbMaster.Cyc and not WbMaster.Stb[*];
{resp} &&
{WbMaster.Cyc and WbMaster.Stb and not WbMaster.We}[+];
not WbMaster.Cyc
};
sequence s_single_write (boolean resp) is {
not WbMaster.Cyc;
WbMaster.Cyc and not WbMaster.Stb[*];
{resp} &&
{WbMaster.Cyc and WbMaster.Stb and WbMaster.We}[+];
not WbMaster.Cyc
};
SINGLE_READ_ACKED_c : cover s_single_read(WbSlave.Ack)
report "Single read with ack finished";
SINGLE_READ_ERROR_c : cover s_single_read(WbSlave.Err)
report "Single read with error finished";
SINGLE_READ_RETRY_c : cover s_single_read(WbSlave.Rty)
report "Single read with retry finished";
SINGLE_WRITE_ACKED_c : cover s_single_write(WbSlave.Ack)
report "Single write with ack finished";
SINGLE_WRITE_ERROR_c : cover s_single_write(WbSlave.Err)
report "Single write with error finished";
SINGLE_WRITE_RETRY_c : cover s_single_write(WbSlave.Rty)
report "Single write with retry finished";
-- Waited single cycles, slave termination at least one cycle after stb
-- is asswerted
sequence s_single_waited_read (boolean resp) is {
not WbMaster.Cyc;
WbMaster.Cyc and not WbMaster.Stb[*];
{s_wb_slave_resp = "000"[+]; resp} &&
{WbMaster.Cyc and WbMaster.Stb and not WbMaster.We}[+];
not WbMaster.Cyc
};
sequence s_single_waited_write (boolean resp) is {
not WbMaster.Cyc;
WbMaster.Cyc and not WbMaster.Stb[*];
{s_wb_slave_resp = "000"[+]; resp} &&
{WbMaster.Cyc and WbMaster.Stb and WbMaster.We}[+];
not WbMaster.Cyc
};
SINGLE_READ_WAITED_ACKED_c : cover s_single_waited_read(WbSlave.Ack)
report "Single waited read with ack finished";
SINGLE_READ_WAITED_ERROR_c : cover s_single_waited_read(WbSlave.Err)
report "Single waited read with error finished";
SINGLE_READ_WAITED_RETRY_c : cover s_single_waited_read(WbSlave.Rty)
report "Single waited read with retry finished";
SINGLE_WRITE_WAITED_ACKED_c : cover s_single_waited_write(WbSlave.Ack)
report "Single waited write with ack finished";
SINGLE_WRITE_WAITED_ERROR_c : cover s_single_waited_write(WbSlave.Err)
report "Single waited write with error finished";
SINGLE_WRITE_WAITED_RETRY_c : cover s_single_waited_write(WbSlave.Rty)
report "Single waited write with retry finished";
-- Block cycles, not distinguished between waited & non-waited
-- We don't cover each possible combination of slave termination
-- during block cycles, as there are a lot for longer block cycles
sequence s_block_read (boolean resp) is {
not WbMaster.Cyc;
{WbMaster.Cyc and not WbMaster.Stb[*];
{s_wb_slave_resp = "000"[*]; resp} &&
{WbMaster.Cyc and WbMaster.Stb and not WbMaster.We}[+]}[*2 to inf];
not WbMaster.Cyc
};
sequence s_block_write (boolean resp) is {
not WbMaster.Cyc;
{WbMaster.Cyc and not WbMaster.Stb[*];
{s_wb_slave_resp = "000"[*]; resp} &&
{WbMaster.Cyc and WbMaster.Stb and WbMaster.We}[+]}[*2 to inf];
not WbMaster.Cyc
};
BLOCK_READ_ACKED_c : cover s_block_read(one_hot(s_wb_slave_resp))
report "Block read finished";
BLOCK_WRITE_ACKED_c : cover s_block_write(one_hot(s_wb_slave_resp))
report "Block write finished";
-- Read-modified-write cycles, not distinguished between waited & non-waited
-- We don't cover each possible combination of slave termniation
-- during read-modified-write cycles
sequence s_rmw_read (boolean resp) is {
not WbMaster.Cyc;
{WbMaster.Cyc and not WbMaster.Stb[*];
{s_wb_slave_resp = "000"[*]; resp} &&
{WbMaster.Cyc and WbMaster.Stb and not WbMaster.We}[+]};
{WbMaster.Cyc and not WbMaster.Stb[*];
{s_wb_slave_resp = "000"[*]; resp} &&
{WbMaster.Cyc and WbMaster.Stb and WbMaster.We}[+]};
not WbMaster.Cyc
};
READ_MODIFIED_WRITE_ACKED_c : cover s_rmw_read(one_hot(s_wb_slave_resp))
report "Read-modified-write finished";
end generate CLASSIC_G;
end generate COVERAGE_G;
end architecture verification;