Reputation: 876
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:
Many thanks if you got this far!
Upvotes: 3
Views: 1731
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
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:
Upvotes: 1
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