Reputation: 49
I'm learning VHDL in order to describe and demonstrate the work of a superscalar-ish pipelined CPU with hazard detection and branch prediction, etc.
I'm starting small, so for practice I tried making a really simple "calculator" design, like this:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_signed.all;
entity calculator is
port(
in_A : in std_logic_vector(3 downto 0);
in_B : in std_logic_vector(3 downto 0);
add : in std_logic;
sub : in std_logic;
out_C : out std_logic_vector(3 downto 0)
);
end entity calculator;
architecture RTL of calculator is
signal next_output : std_logic_vector(3 downto 0);
begin
process(in_A, in_B, add, sub)
variable temp_x, temp_y, temp_z : integer;
begin
temp_x := conv_integer(in_A);
temp_y := conv_integer(in_B);
if(add = '1') and (sub = '0') then
temp_z := temp_x + temp_y;
next_output <= std_logic_vector(to_unsigned(temp_z, 4));
elsif(add = '0') and (sub = '1') then
temp_z := temp_x - temp_y;
next_output <= std_logic_vector(to_unsigned(temp_z,4));
else
temp_z := 0;
next_output <= std_logic_vector(to_unsigned(temp_z,4));
end if;
out_C <= next_output;
end process;
end architecture RTL;
However, I can't figure out why the output is set only after the input is changed, as is demonstrated here (the test bench code I guess is irrelevant):
I would like to know what I should do in order to make the output correct and available without delay. If add is 1, then the output should be set according to the input, without delay (well, I want it to be, the way I wrote it, its not :) )
Also, can someone explain to me when the output will be remembered in flip-flops, and if it being remembered in flip-flops the way I wrote my description.
I would also really appreciate all advice, criticism and guidance to help me out. This is only a simple ADD/SUB calculator, and I gotta describe a whole processor with an instruction set in about two months! Maybe you can point me to good learning tutorials, because the classes I had were useless :(
Thanks in advance! :)
Upvotes: 0
Views: 1024
Reputation: 15934
Signal assignment with <=
to the intermediate signal next_output
is not
visible in the same run of the process, so it takes another run of the process
until out_C <= next_output
sees the new value, hence the delay.
As David Koontz wrote, then you can move the out_C <= next_output
outside the
process.
Alternative is to get ridge of all the intermediate signals and variables, and
rewrite the code as below, including using only the IEEE standard package
numeric_std
, and skipping the Synopsys proprietary package
std_logic_signed
.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
...
architecture RTL of calculator is
begin
process(in_A, in_B, add, sub)
begin
if(add = '1') and (sub = '0') then
out_C <= std_logic_vector(signed(in_A) + signed(in_B));
elsif(add = '0') and (sub = '1') then
out_C <= std_logic_vector(signed(in_A) - signed(in_B));
else
out_C <= std_logic_vector(to_signed(0, out_C'length));
end if;
end process;
end architecture RTL;
I see David made a similar suggestion, but you can get mine anyway :-)
Upvotes: 1
Reputation:
The easiest thing to do would be to move the assignment
out_C <= next_output;
outside the process (make it a concurrent signal assignment).
You could also make next_output a variable declared in the process and leave the signal assignment where it is.
The delay happens because signal assignments don't take effect in the simulation cycle they occur in. Without a process sensitive to next_output it's new value will be seen the next time the process otherwise executes.
A concurrent signal assignment statement has an equivalent process where signals on the right hand side are in the sensitivity list.
Making next_output a variable makes it's value immediately available.
You could also re-write your process:
process(in_A, in_B, add, sub)
variable temp_x, temp_y, temp_z : integer;
begin
temp_x := conv_integer(in_A);
temp_y := conv_integer(in_B);
if(add = '1') and (sub = '0') then
temp_z := temp_x + temp_y;
elsif(add = '0') and (sub = '1') then
temp_z := temp_x - temp_y;
else
temp_z := 0;
end if;
out_C <= std_logic_vector(to_unsigned(temp_z,4));
end process;
And eliminate next_output.
Upvotes: 1