Monday, 28 March 2011

VHDL Test Bench: Default Generated Structure

Looking over the Documentation I noticed that the structure of the test bench is not really detailed. If a user did not use the ttb_gen application they may not know what the structure of the test bench looks like. (In the way I use it.) The following text gives a code example of a default test bench structure.

The default test bench structure is an external test bench is wrapped around an entity. The wrapping function is performed by the top level test bench (ttb). I have a preference to putting the entity declaration and architecture declaration in separate files. So the top level entity is just empty with generic pointing to the stimulus file. As shown below:

library IEEE;
--library dut_lib;
use IEEE.STD_LOGIC_1164.all;
--use dut_lib.all;

entity spi_master_ttb is
generic (
stimulus_file: string := "stm/stimulus_file.stm"
);
end spi_master_ttb;

The top level structure file connects the DUT architecture to the test bench architecture. As shown below:

architecture struct of spi_master_ttb is

component spi_master
port (
mspi_reset_n : in std_logic;
mspi_clk_in : in std_logic;
mspi_sen : out std_logic;
mspi_sclk : out std_logic;
mspi_sdio : inout std_logic;
mspi_sdo : in std_logic;
mspi_acc_done : out std_logic;
stm_add : in std_logic_vector(31 downto 0);
stm_dat : inout std_logic_vector(31 downto 0);
stm_rwn : in std_logic;
stm_req_n : in std_logic;
stm_ack_n : out std_logic
);
end component;

component spi_master_tb
generic (
stimulus_file: in string
);
port (
mspi_reset_n : buffer std_logic;
mspi_clk_in : buffer std_logic;
mspi_sen : in std_logic;
mspi_sclk : in std_logic;
mspi_sdio : inout std_logic;
mspi_sdo : buffer std_logic;
mspi_acc_done : in std_logic;
stm_add : buffer std_logic_vector(31 downto 0);
stm_dat : inout std_logic_vector(31 downto 0);
stm_rwn : buffer std_logic;
stm_req_n : buffer std_logic;
stm_ack_n : in std_logic
);
end component;

--for all: spi_master use entity dut_lib.spi_master(str);
for all: spi_master_tb use entity work.spi_master_tb(bhv);

signal temp_mspi_reset_n : std_logic;
signal temp_mspi_clk_in : std_logic;
signal temp_mspi_sen : std_logic;
signal temp_mspi_sclk : std_logic;
signal temp_mspi_sdio : std_logic;
signal temp_mspi_sdo : std_logic;
signal temp_mspi_acc_done : std_logic;
signal temp_stm_add : std_logic_vector(31 downto 0);
signal temp_stm_dat : std_logic_vector(31 downto 0);
signal temp_stm_rwn : std_logic;
signal temp_stm_req_n : std_logic;
signal temp_stm_ack_n : std_logic;

begin

dut: spi_master
port map(
mspi_reset_n => temp_mspi_reset_n,
mspi_clk_in => temp_mspi_clk_in,
mspi_sen => temp_mspi_sen,
mspi_sclk => temp_mspi_sclk,
mspi_sdio => temp_mspi_sdio,
mspi_sdo => temp_mspi_sdo,
mspi_acc_done => temp_mspi_acc_done,
stm_add => temp_stm_add,
stm_dat => temp_stm_dat,
stm_rwn => temp_stm_rwn,
stm_req_n => temp_stm_req_n,
stm_ack_n => temp_stm_ack_n
);

tb: spi_master_tb
generic map(
stimulus_file => stimulus_file
)
port map(
mspi_reset_n => temp_mspi_reset_n,
mspi_clk_in => temp_mspi_clk_in,
mspi_sen => temp_mspi_sen,
mspi_sclk => temp_mspi_sclk,
mspi_sdio => temp_mspi_sdio,
mspi_sdo => temp_mspi_sdo,
mspi_acc_done => temp_mspi_acc_done,
stm_add => temp_stm_add,
stm_dat => temp_stm_dat,
stm_rwn => temp_stm_rwn,
stm_req_n => temp_stm_req_n,
stm_ack_n => temp_stm_ack_n
);

end struct;

The above shows a test bench component spi_master_tb, with opposite pin directions with the same name. A DUT component definition as derived from the entity. A temporary signal for each pin, and the port mapping of each component using those signals.

The test bench entity, tb_ent, definition is just a reflection of the DUT, with every DUT output being a test bench input. A little editing and the file looks like this:

library IEEE;
--library ieee_proposed;
--library tb_pkg;
--possible users libs;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use work.STD_LOGIC_1164_additions.all;
use std.textio.all;
use work.tb_pkg.all;
--possible users use statement;

entity spi_master_tb is
generic (
stimulus_file: in string
);
port (
mspi_reset_n : buffer std_logic;
mspi_clk_in : buffer std_logic;
mspi_sen : in std_logic;
mspi_sclk : in std_logic;
mspi_sdio : inout std_logic;
mspi_sdo : buffer std_logic;
mspi_acc_done : in std_logic;
stm_add : buffer std_logic_vector(31 downto 0);
stm_dat : inout std_logic_vector(31 downto 0);
stm_rwn : buffer std_logic;
stm_req_n : buffer std_logic;
stm_ack_n : in std_logic
);
end spi_master_tb;

The edits made after generation were to fix up the library definitions to meet the environment.

All the above code was generated by the TTB Gen GUI provided with the package download. It basically saves the user a lot of the mindless typing that structure files contain. Consider a 1000 pin device ... I would rather use a generation program than to type that by hand. The above also shows the code that would create the structure described in the documentation, Default Test Bench Structure.

The architecture of the test bench, tb_bhv, is the container of all objects connected to the DUT, the script parsing process, clock driver process and possibility many others. The tb_bhv file is the only file I add things too, I do not add objects to any other test bench file. This is because the others can be regenerated if there are significant pin changes to the DUT. But you can optionally generate the tb_bhv file because that is where all the hand generated code resides, you do not want to generate a new one.

Below is the entity that was used to generate the above structure. This entity and it's BFM will be redesigned and presented in future posts about BFM's.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.all;
use std.textio.all;


entity spi_master is
port(
MSPI_RESET_N : in std_logic;
MSPI_CLK_IN : in std_logic;
-- interface pins
MSPI_SEN : out std_logic;
MSPI_SCLK : out std_logic;
MSPI_SDIO : inout std_logic;
MSPI_SDO : in std_logic;
MSPI_ACC_DONE : out std_logic;
-- env access port
STM_ADD : in std_logic_vector(31 downto 0);
STM_DAT : inout std_logic_vector(31 downto 0);
STM_RWN : in std_logic;
STM_REQ_N : in std_logic;
STM_ACK_N : out std_logic
);
end spi_master;

The code was included as text, and not a picture, because it was not easy to make it pretty and fit. Also pictures are hard copy code from.

Sckoarn

1 comment: