VHDL if condition not working properly - vhdl

I'm having some difficulties determining why my code is not working properly. I'm trying to create an ALU with a 3-bit op-code.
All but one condition doesn't work properly; op code 011 (SEQ). It's defined as if(a==b) z<='0' and output<='0'. a and b are the inputs, and z is the zero flag. I expected to get this functionality with the following VHDL code
....
BEGIN
result <= dummy_result;
PROCESS (a, b, op)
VARIABLE carry: STD_LOGIC:='0';
--DEFINE ALIAS TO SEPERATE ALU-OP SIGNAL
alias NEG_TSEL : STD_LOGIC IS op(2);
alias ALU_SELECT : STD_LOGIC_VECTOR(1 downto 0) IS op(1 downto 0);
BEGIN
if ALU_SELECT="11" THEN
if NEG_TSEL='0' THEN -- SEQ
if a = b THEN
dummy_result <="00000";
end if;
elsif NEG_TSEL='1' THEN --SCO
cout <= '1';
result <= "XXXXX";
end if;
elsif ALU_SELECT="00" THEN...
With this code, when op = 011, results is always set to zero.
When I change the code to:
.....
if a = b THEN
dummy_result <="00000";
else
dummy_result <= "10101";
end if;
.....
it works fine, but results must not change so instead of the "10101" vector, I change it to "dummy_result <= dummy_result;" but that gives me the same results as the original case gives me.
Any suggestions? Am I doing something wrong?

Here are my issues with your code:
Personally, I feel that on every cycle you should be outputting something to result, cout, and zero. Currently, you always output to zero, but you only conditionally output to the other two ports. This likely is creating latches, which is probably not what you want. So, for example, the SCO operation, should also push something to cout, and the SCO operation should push something to the dummy_result signal.
Your subtraction implementation is not working how you might expect.
when "110" => -- SUB
tmp_b <= NOT b;
carry := '1';
for i in 0 to 4 loop
dummy_result(i) <= carry XOR a(i) XOR tmp_b(i);
carry := (a(i) AND tmp_b(i)) OR (tmp_b(i) AND carry) OR (carry AND a(i));
end loop;
cout <= carry;
tmp_b is a signal. The logic that happens there will happen concurrently with everything else in this process, not sequentially. You likely want that to be a variable, just like carry is.
I also wanted to let you know about case statements (versus if chains). Your code could look like this:
PROCESS (a, b, op)
VARIABLE carry: STD_LOGIC:='0';
BEGIN
case op is
when "011" => -- SEQ
dummy_result <= "00000";
when "111" => -- SCO
cout <= '1';
when "000" => -- AND
dummy_result <= a AND b;
...
when others =>
dummy_result <= "00000";
cout <= '0';
end case;
end process;
To get back to the original problem, SEQ, your original code looked like:
when op = "011" =>
if a = b then
dummy_result <= "00000";
end if;
The problem here, as I mentioned above, is that this is likely a latch. You need to output what you expect the value to be when a /= b, and that can't just be dummy_result <= dummy_result. What do you expect that to become if you pushed it to physical wires and chips?
Instead, you should pass into this entity the value of the last dummy_result, or if a particular operation should hold the value of result, you should output "00000" and also output an additional signal saying that whatever is holding the previous value (in a register), shouldn't update it.

The intent here is that unless otherwise assigned, dummy_result is intended to retain the previous value of "result". Unfortunately, this unit has been implemented as a combinational process, without a clock.
Therefore the storage cannot be reliably implemented in this unit.
Therefore it must be implemented outside this unit.
It almost certainly already is; in a register implemented as a clocked process.
So, bring that register's output back in as a new input port "prev_result" and use a default assignment to dummy_result. That will overcome not only the specific failure you have found so far, but all the other missing assignments to "dummy_result" (there is another) preserving the old value for "result" in a synchronous manner.
PROCESS (a, b, op, prev_result)
-- declarations here
BEGIN
-- default assignment
dummy_result <= prev_result;
if ALU_SELECT="11" THEN
if NEG_TSEL='0' THEN -- SEQ
if a = b THEN
dummy_result <="00000";
end if;
...
END PROCESS;
I think you would be better restructuring the design to make the ALU a clocked process, but if you are under instructions not to, then you will have to adopt this (or similar) solution.

Related

Multiplier via Repeated Addition

I need to create a 4 bit multiplier as a part of a 4-bit ALU in VHDL code, however the requirement is that we have to use repeated addition, meaning if A is one of the four bit number and B is the other 4 bit number, we would have to add A + A + A..., B number of times. I understand this requires either a for loop or a while loop while also having a temp variable to store the values, but my code just doesn't seem to be working and I just don't really understand how the functionality of it would work.
PR and T are temporary buffer standard logic vectors and A and B are the two input 4 bit numbers and C and D are the output values, but the loop just doesn't seem to work. I don't understand how to loop it so it keeps adding the A bit B number of times and thus do the multiplication of A * B.
WHEN "010" =>
PR <= "00000000";
T <= "0000";
WHILE(T < B)LOOP
PR <= PR + A;
T <= T + 1;
END LOOP;
C <= PR(3 downto 0);
D <= PR(7 downto 4);
This will never work, because when a line with a signal assignment (<=) like this one:
PR <= PR + A;
is executed, the target of the signal assignment (PR in this case) is not updated immediately; instead an event (a future change) is scheduled. When is this event (change) actioned? When all processes have suspended (reached wait statements or end process statements).
So, your loop:
WHILE(T < B)LOOP
PR <= PR + A;
T <= T + 1;
END LOOP;
just schedules more and more events on PR and T, but these events never get actioned because the process is still executing. There is more information here.
So, what's the solution to your problem? Well, it depends what hardware you are trying to achieve. Are you trying to achieve a block of combinational logic? Or sequential? (where the multiply takes multiple clock cycles)
I advise you to try not to think in terms of "temporary variables", "for loops" and "while loops". These are software constructions that can be useful, but ultimately you are designing a piece of hardware. You need to try to think about what physical pieces of hardware can be connected together to achieve your design, then how you might describe them using VHDL. This is difficult at first.
You should provide more information about what exactly you want to achieve (and on what kind of hardware) to increase the probability of getting a good answer.
You don't mention whether your multiplier needs to operate on signed or unsigned inputs. Let's assume signed, because that's a bit harder.
As has been noted, this whole exercise makes little sense if implemented combinationally, so let's assume you want a clocked (sequential) implementation.
You also don't mention how often you expect new inputs to arrive. This makes a big difference in the implementation. I don't think either one is necessarily more difficult to write than the other, but if you expect frequent inputs (e.g. every clock cycle), then you need a pipelined implementation (which uses more hardware). If you expect infrequent inputs (e.g. every 16 or more clock cycles) then a cheaper serial implementation should be used.
Let's assume you want a serial implementation, then I would start somewhere along these lines:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity loopy_mult is
generic(
g_a_bits : positive := 4;
g_b_bits : positive := 4
);
port(
clk : in std_logic;
srst : in std_logic;
-- Input
in_valid : in std_logic;
in_a : in signed(g_a_bits-1 downto 0);
in_b : in signed(g_b_bits-1 downto 0);
-- Output
out_valid : out std_logic;
out_ab : out signed(g_a_bits+g_b_bits-1 downto 0)
);
end loopy_mult;
architecture rtl of loopy_mult is
signal a : signed(g_a_bits-1 downto 0);
signal b_sign : std_logic;
signal countdown : unsigned(g_b_bits-1 downto 0);
signal sum : signed(g_a_bits+g_b_bits-1 downto 0);
begin
mult_proc : process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
out_valid <= '0';
countdown <= (others => '0');
else
if in_valid = '1' then -- (Initialize)
-- Record the value of A and sign of B for later
a <= in_a;
b_sign <= in_b(g_b_bits-1);
-- Initialize countdown
if in_b(g_b_bits-1) = '0' then
-- Input B is positive
countdown <= unsigned(in_b);
else
-- Input B is negative
countdown <= unsigned(-in_b);
end if;
-- Initialize sum
sum <= (others => '0');
-- Set the output valid flag if we're already finished (B=0)
if in_b = 0 then
out_valid <= '1';
else
out_valid <= '0';
end if;
elsif countdown > 0 then -- (Loop)
-- Let's assume the target is an FPGA with efficient add/sub
if b_sign = '0' then
sum <= sum + a;
else
sum <= sum - a;
end if;
-- Set the output valid flag when we get to the last loop
if countdown = 1 then
out_valid <= '1';
else
out_valid <= '0';
end if;
-- Decrement countdown
countdown <= countdown - 1;
else
-- (Idle)
out_valid <= '0';
end if;
end if;
end if;
end process mult_proc;
-- Output
out_ab <= sum;
end rtl;
This is not immensely efficient, but is intended to be relatively easy to read and understand. There are many, many improvements you could make depending on your requirements.

Unsigned Addition with Counter Doesn't Work

I'm building a counter that counts rising edges from an input channel. I've simplified my design to include two states, one and two, where counting is done. For some reason, whenever I try to add 1 to counter_reg, or try to assign any number at all to it, the signal becomes red with an X in ModelSim. The code and picture of what happens to the signal are provided below.
I have included the IEEE.NUMERIC_STD.ALL, so I should be able to do unsigned addition. I am not sure what is wrong with counter_reg. Is there anything I'm doing wrong with the counter?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity photon_counter is
Port ( clk,reset : in STD_LOGIC;
arm,shifter,channel : in STD_LOGIC;
start : in STD_LOGIC);
end photon_counter;
architecture fsm_arch of photon_counter is
type state_type is (idle,zero,one);
type array_type is array (1 downto 0) of UNSIGNED (15 downto 0);
signal state_reg,state_next : state_type;
signal arm_prev,shifter_prev,channel_prev : STD_LOGIC;
signal counter : array_type;
signal counter_reg,counter_next : UNSIGNED (15 downto 0);
begin
--------------------------------------
--State Register
--------------------------------------
process(clk,reset)
begin
if reset='1' then
state_reg <= zero;
counter_reg <= (others => '0');
counter <= (others => (others => '0'));
elsif rising_edge(clk) then
state_reg <= state_next;
counter_reg <= counter_next;
arm_prev <= arm;
shifter_prev <= shifter;
channel_prev <= channel;
end if;
end process;
--------------------------------------
--Next-State Logic/Output Logic
--------------------------------------
process(clk,reset,state_reg,start,counter_reg,shifter_prev,shifter,arm,channel_prev,channel)
begin
--default actions
state_next <= state_reg;
counter_next <= counter_reg;
counter_reg <= counter_reg;
case state_reg is
when idle =>
counter_reg <= (others => '0');
counter <= (others => (others => '0'));
if start = '1' then
state_next <= zero;
end if;
when zero =>
if (shifter = '1') and (shifter_prev = '0') then
state_next <= one;
counter(0) <= counter_reg;
end if;
if (channel = '1') and (channel_prev = '0') then
counter_next <= counter_reg + 1;
end if;
when one =>
if arm = '1' then
state_next <= zero;
counter(1) <= counter_reg;
end if;
if (channel = '1') and (channel_prev = '0') then
counter_reg <= counter_reg + 1;
end if;
end case;
end process;
end fsm_arch;
As shown below, counter_reg and counter_next start off with a value of 0 until I try to add 1 to counter_next. The moment channel_prev rises, both counter_reg and counter_next become X (error) and turn red.
Your counter_reg signal is assigned in two different processes. This is what we call a "multiple drive" situation. It is usually undesirable, just like any short circuit, because when the two processes disagree about the value to assign things are getting very bad.
Solution: drive your counter from one single process.
A bit more about this: if this is bad, why didn't you get an error when compiling or when launching your simulation? Because most people do not know or care about unresolved/resolved types in VHDL. By default, a VHDL type is unresolved. This means that, if you try to drive a signal of this type from more than one process you will get an error at compilation or elaboration time that basically says "I cannot decide what value to assign if your processes disagree, this is forbidden". And this is a very nice feature because such accidental short circuits can have serious consequences. You can try this and see the errors by replacing your unsigned (resolved) counter by a natural (unresolved) one:
signal counter_reg,counter_next : natural 0 to 2**16 - 1;
adapt the rest of your code, and see what happens when compiling.
Sometimes, rarely, it is useful to drive a signal from more than one process (high impedance shared bus, bi-directional RAM data bus...) So VHDL allows to define a resolution function that computes the resulting value of several drivers. This function can be used to define the resolved subtype of a unresolved parent type. If you can find the source code of ieee.std_logic_1164 you will see the declaration of the unresolved, 9-valued std_ulogic type (u for unresolved), the resolution function, and the declaration of the resolved subtype std_logic (see? no u).
But when using resolved types you must yourself take care of not creating short-circuits. There is no compiler error any more, no seatbelt. When one of your driving processes drives a strong value ('0' or '1'), all the others must drive a weak value ('Z' for high impedance). Else, you will get unknown resulting values, represented in red by Modelsim, as you saw.
Unfortunately, most people do not really know what the U stands for in std_Ulogic. So, in order to simplify they always use std_logic instead of what they should use: std_ulogic. Moreover, vendors of logic synthesisers push in the same direction because they frequently favour std_logic (when they do not simply force you to use it). And the people who standardized the ieee.numeric_std package did the same: they declared the unsigned and signed types as resolved types (if fact, they have the same declaration as std_logic_vector). This is as unfortunate as driving full speed, at night, wearing sunglasses, without light and without your seatbelt fasten.
Finally, someone realized how unfortunate this was and the current version of ieee.numeric_std now also declares UNRESOLVED_UNSIGNED (alias U_UNSIGNED) and UNRESOLVED_SIGNED (alias U_SIGNED). Alas, this is a bit too late, most designers will never change their existing code or habits, and I wonder how many bugs could have been avoided if the first choice had been different.
My advices:
never drive a signal from several processes if you do not really intend to have multiple physical drivers, manually avoid short circuits, and so on,
never use a resolved type if you do not need it, so that the tools will raise an error if you accidentally create a multiple drive situation,
in your case, drive counter_reg from one single process, declare it as U_UNSIGNED or NATURAL, and declare all your other signals as STD_ULOGIC, not STD_LOGIC.

sensitivity list VHDL process

I'm trying to learn VHDL using Peter Ashenden's book 'The Designer's Guide to VHDL', but can't seem to shake the feeling that I have missed a fundamental item related to sensitivity lists.
for example a question is "Write a model that represents a simple ALU with integer inputs and output, and a function select input of type bit. if the function select is '0', the ALU output should be the sum of the inputs otherwise the output should be the difference of the inputs."
My solution to this is
entity ALU is
port (
a : in integer; -- A port
b : in integer; -- B port
sel : in bit; -- Fun select
z : out integer); -- result
end entity ALU;
architecture behav of ALU is
begin -- architecture behav
alu_proc: process is
variable result : integer := 0;
begin -- process alu_proc
wait on sel;
if sel = '0' then
result := a + b;
else
result := a - b;
end if;
z <= result;
end process alu_proc;
end architecture behav;
with the test bench
entity alu_test is
end entity alu_test;
architecture alu_tb of alu_test is
signal a, b, z : integer;
signal sel : bit;
begin -- architecture alu_tb
dut: entity work.alu(behav)
port map (a, b, sel, z);
test_proc: process is
begin -- process test_proc
a <= 5; b <= 5; wait for 5 ns; sel <= '1'; wait for 5 ns;
assert z = 0;
a <= 10; b <= 5; wait for 5 ns; sel <= '0'; wait for 5 ns;
assert z = 15;
wait;
end process test_proc;
end architecture alu_tb;
my issue has to do with the sensitivity list in the process. Since it is sensitive to changes of the select bit I must do the functions sequentially, first an subtraction, then an addition then a subtraction again in the test bench. In the question I get the feeling that you should be able to do several additions sequentially, no subtraction between. Of course I can add an enable signal and have the process be sensitive to that but I think that should be told in the questions then. Am I missing something in the language or is my solution "correct"?
The problem with the ALU process is that the wait on sel; does not include
a and b, thus the process does not wake up and the output is not
recalculated at changes to these inputs. One way to fix this is to add a and
´b´ to the wait statement, like:
wait on sel, a, b;
However, the common way to write this for processes is with a sensitivity list,
which is a list of signals after the process keyword, thus not with the
wait statement.
Ashendens book 3rd edition page 68 describes that a sensitivity list:
The process statement includes a sensitivity list after the keyword process.
This is a list of signals to which the process is sensitive. When any of
these signals changes value, the process resumes and executes the sequential
statements. After it has executed the last statement, the process suspends
again.
The use of sensitivity list as equivalent to wait statement is also described
in Ashendens book on page 152.
If the process is rewritten to use a sensitivity list, it will be:
alu_proc: process (sel, a, b) is
begin -- process alu_proc
if sel = '0' then
z <= a + b;
else
z <= a - b;
end if;
end process alu_proc;
Note that I removed the result variable, since the z output can just as
well be assigned directly in this case.
The above will recalculate z when any of the values used in the calculation
changes, since all the arguments for calculating z are included in the
sensitivity list. The risk of doing such continuous calculations in this way,
is that if one or more of the arguments are forgotten in the sensitivity list,
a new value for z is not recalculated if the forgotten argument changes.
VHDL-2008 allows automatic inclusion of all signals and ports in the
sensitivity list if all is used like:
alu_proc: process (all) is
A final comment, then for a simple process doing asynchronous calculation, like
for the shown ALU, it is possible to do without a process, if the generation of
z is written like:
z <= (a + b) when (sel = '0') else (a - b);
Using a concurrent assignment, like the above, make it possible to skip the
sensitivity list, and thus the risk of forgetting one of the signals or ports
that are part of the calculation.

VHDL Shift Register Program different results when using signals and variables

So I've been using VHDL to make a register, where it loads in the input X if LOAD is '1' , and outputs the data in serial fashion , basically a parallel in serial out register. The input X is a 4 bit ( 3 downto 0 ) input , what I want to make the program do is constantly output 0 when the register has successfully output all the btis in the input.
It works when "count" is defined as a signal , however , when count is defined as a variable , the output is a constant 0 , regardless of whether load is '1' or not. My code is as shown:
entity qn14 is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
LOAD : in STD_LOGIC;
X : in STD_LOGIC_VECTOR (3 downto 0);
output : out STD_LOGIC);
end qn14;
architecture qn14_beh of qn14 is
type states is ( IDLE , SHIFT );
signal state : states;
signal count: STD_LOGIC_VECTOR(1 downto 0);
begin
process(clk , reset)
variable temp: STD_LOGIC;
variable data: STD_LOGIC_VECTOR(3 downto 0);
begin
if reset = '1' then
state <= IDLE;
count <= "00";
output <= '0';
elsif clk'event and clk = '1' then
case state is
when IDLE =>
if LOAD = '1' then
data := X;
output <= '0';
state <= SHIFT;
elsif LOAD = '0' then
output <= '0';
end if;
when SHIFT =>
if LOAD ='1' then
output <= '0';
elsif LOAD = '0' then
output <= data( conv_integer(count) );
count <= count + 1;
if (count >= 3) then
state <= IDLE ;
end if;
end if;
end case;
end if;
end process;
end qn14_beh;
Hoping to seek clarification on this.
Thank you.
This may not fully answer your question, but I will cover several issues that I see.
The elsif LOAD = '0' then could just be else unless you're trying to cover the other states (X,U...) but you would still want an else to cover those.
count = 3 is clearer than count >= 3. count is a 2-bit vector, so it can never be greater than 3.
Although you output 0 when LOAD is asserted while in the SHIFT state, you don't actually load a new value. Did you intend to?
Changing count to a variable without changing the position of the assignments will cause your first X -> output sequence to abort a cycle early (you increment count before you test it against 3). It will cause subsequent X -> output sequences to go "X(3), X(0), X(1), X(2)"
The variable temp is never used. The variable data would work just as well as a signal. You do not need the properties of variables for this use. This also brings up the question of why you tried count as variable; unless you need the instant assignments of variables, it is typically better to use a signal because signals are easier to view in (most) simulators and harder to make mistakes with. I hope that you aren't trying to end up with count as a variable, but just have an academic curiosity why it doesn't work.
Have you looked at this in a simulator? Are you changing states properly? Are all the bits of all your inputs strongly driven to a defined value ('1' or '0')?
I don't see anything that would cause the failure you described merely from changing count to a variable from a signal, but the change would cause the undesired behavior described above. My best guess is that your symptom arises from an issue with how you drive your inputs.

Why use concurrent statements in VHDL?

I am just starting with learning vhdl.
Consider the code here : - http://esd.cs.ucr.edu/labs/tutorial/jkff.vhd
I can't understand what are concurrent statements and why are they needed here?
Will it be correct if we modify Q and Qbar directly in process p without using internal signal 'state'? Also why are J,K not in sensitivity list of process p in the snippet?
Concurrent statements, as you may know, in a pure functional sense (i.e. not considering hardware implementation) do not incur any delay. So when you write
Q <= state;
Functionally, Q exactly follows state without any delay.
I am going to guess that the reason an intermediate signal state was used, instead of directly assigning Q inside the process, is that if you directly assign one of your outputs Q in the process, then you cannot "read" the output to derive your Qbar signal.
That is, you couldn't do this:
Qbar <= not Q;
This is because it is not strictly allowable to read an output signal in VHDL. By using "state" you have an internal signal from which you can derive both Q and Qbar.
An alternative, equivalent implementation to this would be to assign both outputs Q and Qbar in each of the cases in the state machine, and eliminate the intermediate state signal completely. However, this seems a bit more complicated since you will have nearly twice as many lines of code for an equivalent functionality.
To answer your second question: J,K are not in the sensitivity list because the process p is a synchronous process. You are describing a memory element (JK FlipFlop), which by definition only updates its outputs when clock or reset change. Input signals J and K can change and the process will not update its outputs. Every time there is a clock edge, or reset is asserted, the process "wakes up" and evaluates inputs, and determines what the output should be. Even in J,K were included in the sensitivity list, provided your ouputs were only updated on rising_edge(clock), then the overall function would be the same (although your code would be confusing).
There is no reason not to have the Q and Qbar assignments inside the process. You need to be slightly careful though.
Whenever a signal is assigned to, the value does not update until the simulator moves on to the next "delta-cycle". This means that within processes, when you assign to a signal, you are axtually only cheduling and update and if you read the signal you will get the "old" value. In order to have the sort of sequential updates you might expect, you use a variable. So you could model the JKFF like this:
architecture behv of JK_FF is
begin
p : process(clock, reset) is
variable state : std_logic;
variable input : std_logic_vector(1 downto 0);
begin
if (reset = '1') then
state := '0';
elsif (rising_edge(clock)) then
input := J & K;
case (input) is
when "11" =>
state := not state;
when "10" =>
state := '1';
when "01" =>
state := '0';
when others =>
null;
end case;
end if;
Q <= state;
Qbar <= not state;
end process;
end behv;
A synthesis note: the assignments to Q and Qbar occur outside of the if rising_edge(clk) so will be interpreted as just like concurrent drivers.

Resources