Browse Source

Add 1st version of simple wishbone vip

master
T. Meissner 3 years ago
parent
commit
e853cc09dd
4 changed files with 327 additions and 0 deletions
  1. +13
    -0
      wishbone/Makefile
  2. +39
    -0
      wishbone/wishbone_pkg.vhd
  3. +105
    -0
      wishbone/wishbone_tb.vhd
  4. +170
    -0
      wishbone/wishbone_vip.vhd

+ 13
- 0
wishbone/Makefile View File

@ -0,0 +1,13 @@
.PHONY: sim clean
wishbone_tb: wishbone_pkg.vhd wishbone_vip.vhd wishbone_tb.vhd
ghdl -a --std=08 --work=wishbone wishbone_pkg.vhd wishbone_vip.vhd
ghdl -a --std=08 wishbone_tb.vhd
ghdl -e --std=08 wishbone_tb
sim: wishbone_tb
./wishbone_tb --wave=$<.ghw --psl-report=$<.json
clean:
rm -rf *.o *.cf *.ghw *.json
rm -rf wishbone_tb

+ 39
- 0
wishbone/wishbone_pkg.vhd View File

@ -0,0 +1,39 @@
-- 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;
package wishbone_pkg is
type t_wb_syscon is record
Reset : std_logic;
Clk : std_logic;
end record;
type t_wb_master is record
Cyc : std_logic;
Stb : std_logic;
We : std_logic;
Lock : std_logic;
Adr : std_logic_vector;
Dat : std_logic_vector;
Sel : std_logic_vector;
Tgc : std_logic_vector;
Tga : std_logic_vector;
Tgd : std_logic_vector;
end record;
type t_wb_slave is record
Ack : std_logic;
Err : std_logic;
Rty : std_logic;
Dat : std_logic_vector;
Tgd : std_logic_vector;
end record;
end package wishbone_pkg;

+ 105
- 0
wishbone/wishbone_tb.vhd View File

@ -0,0 +1,105 @@
-- 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;
use std.env.all;
library wishbone;
use wishbone.wishbone_pkg.all;
entity wishbone_tb is
end entity wishbone_tb;
architecture testbench of wishbone_tb is
constant C_WB_ADDR_WIDTH : positive := 32;
constant C_WB_DATA_WIDTH : positive := 32;
constant C_WB_SEL_WIDTH : positive := 4;
constant C_WB_TGA_WIDTH : positive := 4;
constant C_WB_TGC_WIDTH : positive := 4;
constant C_WB_TGD_WIDTH : positive := 4;
signal s_wb_syscon : t_wb_syscon := ('1', '1');
signal s_wb_master : t_wb_master(Adr(C_WB_ADDR_WIDTH-1 downto 0),
Dat(C_WB_DATA_WIDTH-1 downto 0),
Sel(C_WB_SEL_WIDTH-1 downto 0),
Tgc(C_WB_TGC_WIDTH-1 downto 0),
Tga(C_WB_TGA_WIDTH-1 downto 0),
Tgd(C_WB_TGD_WIDTH-1 downto 0));
signal s_wb_slave : t_wb_slave(Dat(C_WB_DATA_WIDTH-1 downto 0),
Tgd(C_WB_TGD_WIDTH-1 downto 0));
signal s_wb_slave_resp : std_logic_vector(2 downto 0);
alias s_clk is s_wb_syscon.Clk;
alias s_reset is s_wb_syscon.Reset;
begin
s_clk <= not s_clk after 1 ns;
s_reset <= '0' after 4 ns;
s_wb_slave_resp <= s_wb_slave.Rty & s_wb_slave.Err & s_wb_slave.Ack;
wb_master_p : process is
begin
s_wb_master.Cyc <= '0';
s_wb_master.Stb <= '0';
wait until s_reset = '0';
-- simple reads
for i in 0 to 2 loop
wait until rising_edge(s_clk);
s_wb_master.Cyc <= '1';
s_wb_master.Stb <= '1';
s_wb_master.We <= '0';
wait until s_wb_slave_resp(i) = '1' and rising_edge(s_clk);
report "Master: end simple read cycle";
s_wb_master.Cyc <= '0';
s_wb_master.Stb <= '0';
end loop;
wait for 10 ns;
stop(0);
end process wb_master_p;
wb_slave_p : process is
variable v_resp : std_logic_vector(2 downto 0) := "000";
begin
(s_wb_slave.Rty, s_wb_slave.Err, s_wb_slave.Ack) <= v_resp;
wait until s_reset = '0';
-- simple read
for i in 0 to 2 loop
wait until (s_wb_master.Cyc and s_wb_master.Stb) = '1' and rising_edge(s_clk);
v_resp(i) := '1';
(s_wb_slave.Rty, s_wb_slave.Err, s_wb_slave.Ack) <= v_resp;
wait until not s_wb_master.Stb;
v_resp(i) := '0';
(s_wb_slave.Rty, s_wb_slave.Err, s_wb_slave.Ack) <= v_resp;
end loop;
wait;
end process wb_slave_p;
i_wishbone_vip : entity wishbone.wishbone_vip
generic map (
MODE => "CLASSIC"
)
port map (
WbSysCon => s_wb_syscon,
WbMaster => s_wb_master,
WbSlave => s_wb_slave
);
end testbench;

+ 170
- 0
wishbone/wishbone_vip.vhd View File

@ -0,0 +1,170 @@
-- 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;
-- RULE 3.20
STB_RESET_a : assert always Reset -> not WbMaster.Stb;
CYC_RESET_a : assert always Reset -> not WbMaster.Cyc;
-- RULE 3.25
STB_CYC_a : assert always WbMaster.Stb -> WbMaster.Cyc;
-- 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 or s_wb_slave_resp -> WbMaster.Stb;
DAT_STABLE_STB_a : assert always WbMaster.Stb and s_wb_slave_resp = "000" ->
next (WbMaster.Dat = s_wb_master.Dat);
end generate ASSERTS_G;
COVERAGE_G : if COVERAGE generate
sequence s_single_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}[+]
};
sequence s_single_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}[+]
};
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 read with ack finished";
SINGLE_WRITE_ERROR_c : cover s_single_write(WbSlave.Err)
report "Single read with error finished";
SINGLE_WRITE_RETRY_c : cover s_single_write(WbSlave.Rty)
report "Single read with retry finished";
end generate COVERAGE_G;
end architecture verification;

Loading…
Cancel
Save