DiBosco
DiBosco

Reputation: 876

VHDL testbench for a device that uses two previously defined and tested entities

Warning: this is going to be long. Sorry if it's too verbose.

I'm just starting out on learning FPGAs and VHDL using Quartus Prime. Over the past few days I've taught myself:

What I can't work out though is how I would create a testbench that tests a new component that uses two existing components, when some of the signals that are in this new component are only internal signals.

So, here are two super-simple components that I have successfully written and tested with test benches. I realise this is not real world by the way, I'm just trying to take baby steps.

1. A four bit register

library ieee;
use ieee.std_logic_1164.all;

entity four_bit_reg is
port
    (
    bcd_in: in std_logic_vector(3 downto 0);
    clk: in std_logic;
    clr: in std_logic;
    bcd_out: out std_logic_vector(3 downto 0)
    );

end four_bit_reg;

architecture behaviour of four_bit_reg is
begin
    process (clk,clr)
        begin
        if (clr = '1') then
            bcd_out <= "0000";
        elsif rising_edge(clk) then
            bcd_out <= bcd_in;
        end if;
    end process;

end behaviour;

2. A BCD to seven segment converter

library ieee;
use ieee.std_logic_1164.all;

entity sev_seg is
    port
        (
        bcd_value : in std_logic_vector(3 downto 0);
        sev_seg_value : out std_logic_vector(6 downto 0)                                        
        );

end sev_seg;

architecture behaviour of sev_seg is
begin   
    sev_seg_process : process (bcd_value)
        begin
        case bcd_value is
            when "0000" => sev_seg_value <="0111111"; -- 0
            when "0001" => sev_seg_value <="0000110"; -- 1
            when "0010" => sev_seg_value <="0111011"; -- 2
            when "0011" => sev_seg_value <="1001111"; -- 3
            when "0100" => sev_seg_value <="1100110"; -- 4
            when "0101" => sev_seg_value <="1101101"; -- 5
            when "0110" => sev_seg_value <="1111101"; -- 6
            when "0111" => sev_seg_value <="0000111"; -- 7
            when "1000" => sev_seg_value <="1111111"; -- 8
            when "1001" => sev_seg_value <="1101111"; -- 9
            when others => sev_seg_value <= "0000000"; -- A to F should show blank      
        end case;
    end process sev_seg_process;
end behaviour;

First question: What do you call the two things above? Components? Modules? Entities? Something else?

I then use these two in another new component/entity/module (as applicable) as below:

library ieee;
use ieee.std_logic_1164.all;

entity two_modules is
    port
        (
        bcd_pins : in std_logic_vector(3 downto 0);
        sev_seg_pins : out std_logic_vector(6 downto 0)                     
        );

end two_modules;


architecture behaviour of two_modules is
-- Internal signals
signal int_clk: std_logic;
signal int_bus: std_logic_vector(3 downto 0); 

-- List any components used in the design
    component four_bit_reg is
        port
            (
            bcd_in: in std_logic_vector(3 downto 0);
            clk: in std_logic;
            clr: in std_logic;
            bcd_out: out std_logic_vector(3 downto 0)
            );
    end component;

    component sev_seg is
        port
            (
            bcd_value : in std_logic_vector(3 downto 0);
            sev_seg_value : out std_logic_vector(6 downto 0)                                        
            );

    end component;

begin -- start the instances
    fbr: four_bit_reg port map
        (
        clk => int_clk,
        bcd_in => bcd_pins,
        clr => '0',
        bcd_out => int_bus
        );
    sseg: sev_seg port map
        (
        bcd_value => int_bus,
        sev_seg_value => sev_seg_pins

        );

end behaviour;      

So, for this thing I have called two_modules, the framework for the test bench created by Quartus is as follows:

LIBRARY ieee;                                               
USE ieee.std_logic_1164.all;                                

ENTITY two_modules_vhd_tst IS
END two_modules_vhd_tst;
ARCHITECTURE two_modules_arch OF two_modules_vhd_tst IS
-- constants       

-- signals                                                   
SIGNAL bcd_pins : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL sev_seg_pins : STD_LOGIC_VECTOR(6 DOWNTO 0);
signal internal_clock : std_logic := '0';
COMPONENT two_modules
    PORT (
    bcd_pins : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
    sev_seg_pins : OUT STD_LOGIC_VECTOR(6 DOWNTO 0)
    );
END COMPONENT;
BEGIN
    i1 : two_modules
    PORT MAP (
-- list connections between master ports and signals
    bcd_pins => bcd_pins,
    sev_seg_pins => sev_seg_pins
    );

internal_clock <= not internal_clock after 500 us;

init : PROCESS                                               
-- variable declarations                                     
BEGIN                                                        
        -- code that executes only once                      
WAIT;                                                       
END PROCESS init;                                           
always : PROCESS                                              
-- optional sensitivity list                                  
-- (        )                                                 
-- variable declarations                                      
BEGIN                                                         
        -- code executes for every event on sensitivity list  
WAIT;                                                        
END PROCESS always;                                          
END two_modules_arch;

As you can see I have created an internal clock and I would like to, purely for the purposes of learning how to do this type of thing, I stress I realise this is not a complete design, join the internal_clock (that I can see works and is a waveform in the waveform editor of Model Sim) to clk in the four_bit_reg.

I think and hope once I know how to do this I'll be able to plough on and get a real world, more complicated test bench knocked up. However, after much Googling I can find no reference on how to bind together signals from subcomponents. This may be because I am using completely the wrong terminology and there may be a perfect tutorial somewhere out there.

So:

  1. How can I just for a start get my internal_clock connected to subcomponent, four_bit_reg's clk input?
  2. What is the correct teminology for when you use and knit together things like four_bit_reg and sev_seg? Subcomponents? Something else?

Many thanks if you got this far!

Upvotes: 3

Views: 1731

Answers (3)

grorel
grorel

Reputation: 1466

With the comments, I understand that you are using an internal oscillator from Altera in your CPLD.

I suggest to add a third module named "internal_oscillator" which can be described as follow :

library ieee;
  use ieee.std_logic_1164.all;

entity internal_oscillator is
port (
  CLK  : out std_logic
);
end entity;

architecture for_simulation_only of internal_oscillator is
  constant C_HALF_PERIOD : time      := 5 ns; -- 100MHz
  signal   clk_internal  : std_logic := '0';
begin

  clk_internal <= not clk_internal after C_HALF_PERIOD;
  CLK <= clk_internal;

end architecture;

You can now add this module in your design and you'll get a clock without adding a new pin on your top level entity :

osc_inst : entity work.internal_oscillator 
port map (CLK => int_clk);

Upvotes: 3

Oldfart
Oldfart

Reputation: 6259

In most cases the clock is an input to the module. Often accompanied by a reset.

If you look around on the www for example VHDL code you will notice that every module, has a clock input.

There are general two exceptions:

  1. Test-benches generate an artificial clock inside to drive the Device Under test.
  2. Modules which simulate a real clock generating circuit e.g. a Crystal oscillator.

Upvotes: 1

am9417
am9417

Reputation: 1036

In your two_models entity, add a new port for the clock signal:

entity two_modules is
    port
        (
        clk : in std_logic;
        bcd_pins : in std_logic_vector(3 downto 0);
        sev_seg_pins : out std_logic_vector(6 downto 0)                     
        );

end two_modules;

Remove the int_clk signal in the two_models architecture. Replace it with the previously defined input signal instead when you are connecting the submodules:

fbr: four_bit_reg port map
    (
    clk => clk_in,
    bcd_in => bcd_pins,
    clr => '0',
    bcd_out => int_bus
    );

In your testbench, connect the internal clock signal internal_clock into that port of the two_modules:

    PORT MAP (
-- list connections between master ports and signals
    clk_in => internal_clock,
    bcd_pins => bcd_pins,
    sev_seg_pins => sev_seg_pins
    );

Upvotes: 1

Related Questions