Reputation: 1
The program contains two source files: 8bit_PU.vhd
(entity bit_PU) and 8bit_Tb.vhd
. Final version of the program is supposed to read some amount (in this testbench clock frequency is 100Hz) of 3-bit operation codes to operation
, decode them, apply it to 8-bit std_logic_vectors
operand1
and operand2
(they also change in time) and write the result to 8-bit std_logic_vector
result
. The code I have now describes only an adding operation, so the operation
vector is useless for now.
Here is 8bit_PU.vhd
code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bit_PU is
port(operation : in std_logic_vector (2 downto 0);
Clk : in std_logic;
operand1 : in std_logic_vector (7 downto 0);
operand2 : in std_logic_vector (7 downto 0);
result : out std_logic_vector(7 downto 0)
);
end bit_PU;
architecture proc of bit_PU is
function Add (op1 : std_logic_vector (7 downto 0);
op2 : std_logic_vector (7 downto 0)) return std_logic_vector is
variable res: std_logic_vector (7 downto 0);
begin
res := std_logic_vector((unsigned(op1)+unsigned(op2)) mod 256);
return res;
end function;
begin
process(Clk) is
begin
if rising_edge(Clk) then
result <= Add(operand1, operand2);
end if;
end process;
end architecture;
Here is 8bit_Tb.vhd
code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bit_Tb is
end bit_Tb;
architecture proc of bit_Tb is
component bit_PU is
port(operation : in std_logic_vector (2 downto 0);
Clk : in std_logic;
operand1 : in std_logic_vector (7 downto 0);
operand2 : in std_logic_vector (7 downto 0);
result : out std_logic_vector(7 downto 0)
);
end component bit_PU;
signal Clk : std_logic := '0';
constant Freq : integer := 100;
constant PeriodTime : time := 1000 ms / Freq;
signal operation : std_logic_vector (2 downto 0) := "000";
signal result : std_logic_vector (7 downto 0);
signal operand1 : std_logic_vector (7 downto 0) := (others => '0');
signal operand2 : std_logic_vector (7 downto 0) := (others => '0');
begin
i_bit_PU: component bit_PU
port map(Clk => Clk,
operation => operation,
operand1 => operand1,
operand2 => operand2,
result => result);
Clk <= not Clk after PeriodTime / 2;
process (Clk) is
begin
if rising_edge(Clk) then
if unsigned(operand1) < unsigned(operand2) or (operand1 = x"FF" and operand2 = x"00") then
operand1 <= std_logic_vector((unsigned(operand1)+1) mod 256);
else
operand2 <= std_logic_vector((unsigned(operand2)+1) mod 256);
end if;
end if;
end process;
end architecture;
Analysis and compilation process:
$ ghdl -s 8bit_PU.vhd
$ ghdl -s 8bit_Tb.vhd
$ ghdl -a 8bit_PU.vhd
$ ghdl -a 8bit_Tb.vhd
$ ghdl -e bit_PU
$ ghdl -r bit_PU --vcd=2nd_circuit.vcd
Execution:
$ gtkwave 2nd_circuit.vcd
GTKWave Analyzer v3.3.118 (w)1999-2023 BSI
[0] start time.
[0] end time.
As you can see, program has 0 sec runtime.
I tested both files separately (testbench simulation in 8bit_PU.vhd file; testbench run only) and they worked correctly, so I suppose, that there is some problem in the way I import PU's ports in the testbench. Then I tried to import PU's ports using work
library:
---
architecture proc of bit_Tb is
signal Clk : std_logic := '0';
constant Freq : integer := 100;
constant PeriodTime : time := 1000 ms / Freq;
signal operation : std_logic_vector (2 downto 0) := "000";
signal result : std_logic_vector (7 downto 0);
signal operand1 : std_logic_vector (7 downto 0) := (others => '0');
signal operand2 : std_logic_vector (7 downto 0) := (others => '0');
begin
i_bit_PU: entity work.bit_PU(proc) --here
port map(Clk => Clk,
operation => operation,
operand1 => operand1,
operand2 => operand2,
result => result);
---
But, that also didn't help.
Upvotes: 0
Views: 92
Reputation: 3983
Your testbench process currently is generating waveforms forever. You would be better served by a test case generator that is more algorithmic. Such as:
process
begin
for i in 1 to 512 loop
if i mod 2 = 1 then
operand2 <= std_logic_vector((unsigned(operand2)+1) mod 256);
else
operand1 <= std_logic_vector((unsigned(operand1)+1) mod 256);
end if ;
wait until rising_edge(clk) ;
end loop ;
-- stop your test case
std.env.stop ;
end process ;
If you did this, you would not need the --stoptime
with GHDL as it would simply run until it hit the stop.
In your testbenches, if you are doing math on std_logic_vector, I recommend that you use numeric_std_unsigned
instead of all the type conversion gymnastics. Also as @user16145658 mentioned, you don't need the mod 256 as numeric_std family of packages results are always the same size as the largest argument. This will reduce your code to:
process
begin
for i in 1 to 512 loop
if i mod 2 = 1 then
operand2 <= operand2 + 1;
else
operand1 <= operand1 + 1 ;
end if ;
wait until rising_edge(clk) ;
end loop ;
-- stop your test case
std.env.stop ; -- VHDL-2008, so be sure to enable it.
end process ;
This sort of thinking will get you started toward thinking about how to write test cases.
Upvotes: 0