VHDL infinite loop - vhdl

I'm writing a small piece of code to take a 32 bit input and output 2 bits at a time. I believe I'm having infinite loop problems from the while loop, based on simulation attempts. Everything looks right to me, compared to other examples of loops I've looked at. Any clue what I could be doing wrong?
library ieee;
use ieee.std_logic_1164.all;
entity regA is
port(mpcnd: in std_logic_vector(31 downto 0);
clk: in std_logic;
twobits: out std_logic_vector(1 downto 0));
end regA;
architecture behavior of regA is
begin
process
variable count: integer;
begin
count := 0;
while (count < 32) loop
if rising_edge(clk) then
twobits(0) <= mpcnd(count);
twobits(1) <= mpcnd(count+1);
count := count + 2;
end if;
end loop;
end process;
end behavior;

for a process you need either a sensitivity list or a wait statement within. a (not synthesisable but simulatable) version of your process could look as follows:
process
variable count: integer;
begin
count := 0;
while (count < 32) loop
wait until rising_edge(clk);-- if rising_edge(clk) then
twobits(0) <= mpcnd(count);
twobits(1) <= mpcnd(count+1);
count := count + 2;
--end if;
end loop;
end process;

Related

Use alias-like variable in for loops

Is it possible to create an alias variable/signal to improve readability of for loops in VHDL processes?
For instance, consider the following module which contains a process with inner for loops (code is for example purpose, I haven't test it):
library ieee;
use ieee.std_logic_1164.all;
entity MyModule is
port (
clk : in std_logic;
inData : in std_logic_vector(7 downto 0);
outData : out std_logic_vector(7 downto 0));
end MyModule;
architecture functional of MyModule is
type sample_vector is array (natural range <>) of std_logic_vector(9 downto 0);
type data_t is record
samples : sample_vector(3 downto 0);
-- other elements...
end record data_t;
type data_vector is array (natural range <>) of data_t;
signal data : data_vector(1 downto 0);
begin -- functional
process (clk)
begin -- process
if clk'event and clk = '1' then
-- Set outData(N) to '1' if at least 1 of the last 10 values of inData(N) was '1'
for d in data'RANGE loop
for s in data(0).samples'RANGE loop
data(d).samples(s)(9 downto 1) <= data(d).samples(s)(8 downto 0);
data(d).samples(s)(0) <= inData(d * 4 + s);
outData(d * 4 + s) <= '0';
for b in data(d).samples(s)'RANGE loop
if data(d).samples(s)(b) = '1' then
outData(d * 4 + s) <= '1';
end if;
end loop;
end loop;
end loop;
end if;
end process;
end functional;
Having to use data(d).samples(s) every time I need to reference that signal is cumbersome, so I'd rather use an alias-like variable, something like that instead (inspired from generate syntax, idx part is just a bonus):
-- Set outData(N) to '1' if at least 1 of the last 10 values of inData(N) was '1'
for d in data'RANGE loop
for s in data(0).samples'RANGE loop
alias sample : std_logic_vector(9 downto 0) is data(d).samples(s);
constant idx : integer := d * 4 + s;
begin
sample(9 downto 1) <= sample(8 downto 0);
sample(0) <= inData(idx);
outData(idx) <= '0';
for b in sample'RANGE loop
if sample(b) = '1' then
outData(idx) <= '1';
end if;
end loop;
end loop;
end loop;
Of course, this does not work. So, is there any way to achieve something like that in VHDL, or do we always have to specify the full signal "path" each time?
I could replace the loop body with a procedure, but having to declare the procedure code in a (far away) different place of the file reduces readability even more. I could also use a for ... generate construct, but this will create 1 process for each iteration and prevent me from using common process variables inside the iteration.
As indicated in question comments, this can be achieve using process variables:
process (clk)
variable sample : std_logic_vector(9 downto 0);
variable idx : integer;
begin -- process
if clk'event and clk = '1' then
-- Set outData(N) to '1' if at least 1 of the last 10 values of inData(N) was '1'
for d in data'RANGE loop
for s in data(0).samples'RANGE loop
-- Helpers
sample := data(d).samples(s);
idx := d * 4 + s;
outData(idx) <= '0';
for b in sample'RANGE loop
if sample(b) = '1' then
outData(idx) <= '1';
end if;
end loop;
sample(9 downto 1) <= sample(8 downto 0);
sample(0) <= inData(idx);
-- Do not forget to apply changes
data(d).samples(s) <= sample;
end loop;
end loop;
end if;
end process;
Of course, using process variables implies changing the operations order to get the same behavior.
Since process variables are read and written in the loops, I was worried the synthesis tools would believe the result of iteration N was dependent on the result of iteration N-1, and make implements the iterations in series (instead of in parallel). However, after unrolling the loop (which is what synthesis tools do), it gets clear the synthesis tools will see sample and idx values are not re-used between iterations.

Counting down unsigned numbers is missing the 9 and 8 every 10

I don't know where I am going wrong, or how to fix it. I am basically building a state counter and it starts at 33 and counts down to 0 before resetting but 29,28,19,18,9 and 8 all miss. I am stuck on where I am going wrong.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity sequencer is
PORT(clk: IN std_logic;
count : out unsigned (5 downto 0));
End sequencer;
ARCHITECTURE behavior OF sequencer IS
SIGNAL dSig, qSig : unsigned (5 downto 0);
BEGIN
PROCESS (clk, dSig)
BEGIN
dSig <= "011011";
if rising_edge(clk) Then
qSig <= dSig;
end if;
if qSig = "000000" then
dSig <= "011011";
else
dSig <= qSig - 1 ;
End if;
count <= qSig;
End Process;
END behavior;
The whole process can be simplified to
process (clk, reset)
begin
if reset then -- use an asynchronous reset for initial value
dSig <= "011011";
elsif rising_edge(clk) Then -- keep everything else within the synchronized block
count <= dSig;
if dSig = "000000" then
dSig <= "011011";
else
dSig <= dSig - 1 ;
end if;
end if;
end process;
Work with one counter signal and keep everything within the synchronized block of your process, or is there a reason for the async output evaluation?
I suspect this is because of your mixing synchronous and asynchronous elements inside the same process, and glitches are causing the counter to skip. I suggest making it wholly synchronous.
ARCHITECTURE behavior OF sequencer IS
SIGNAL count_i : unsigned (5 downto 0) := (others => '0')
BEGIN
PROCESS (clk)
BEGIN
if rising_edge(clk) Then
count_i <= count_i + 1;
end if;
End Process;
count <= count_i;
END behavior;

VHDL ignores statement outside a process

I hope this is in the right place, but since I think it's an issue with syntax instead of actual system design maybe it is.
For some reason I have a statement that is ignored when I leave it outside a process. I can copy/paste the same statement into a process and suddenly it works. But then it has to wait on the clock signal, which messes up the whole thing.
architecture CU of CONTROL_UNIT is
type OPCODE_ARRAY is array(3 downto 0) of std_logic_vector(3 downto 0);
signal OPCODES : OPCODE_ARRAY;
begin
OPCODES(3) <= OPCODE_IN; --problem statement!
process(CLK)
begin
if rising_edge(CLK) then
for I in 0 to 2 loop
OPCODES(I) <= OPCODES(I + 1);
end loop;
end if;
end process;
--more code
end CU;
If I simulate it like this, I get this situation that I don't understand:
Notice OPCODE_IN is D but OPCODES(3) is still U.
If I move the statement inside the process, it will shift the value of OPCODE_IN into OPCODES(3) but of course it takes another clock cycle which messes up the timing of everything:
architecture CU of CONTROL_UNIT is
type OPCODE_ARRAY is array(3 downto 0) of std_logic_vector(3 downto 0);
signal OPCODES : OPCODE_ARRAY;
begin
process(CLK)
begin
if rising_edge(CLK) then
for I in 0 to 2 loop
OPCODES(I) <= OPCODES(I + 1);
end loop;
OPCODES(3) <= OPCODE_IN; --problem statement!
end if;
end process;
--more code
end CU;
Does anybody have any ideas why this is behaving this way?
You can express the shift directly and eliminate both the for...loop and the longest static prefix issue.
process(CLK)
begin
if rising_edge(CLK) then
OPCODES <= OPCODE_IN & OPCODES(3 downto 1);
end if;
end process;
Or, if you have a preference for the loop ...
architecture CU of CONTROL_UNIT is
type OPCODE_ARRAY is array(3 downto 0) of std_logic_vector(3 downto 0);
signal OPCODES : OPCODE_ARRAY;
begin
process(CLK, OPCODE_IN)
begin
OPCODES(3) <= OPCODE_IN;
if rising_edge(CLK) then
for I in 0 to 2 loop
OPCODES(I) <= OPCODES(I + 1);
end loop;
end if;
end process;
--more code
end CU;
...though I do not find it very satisfying. The assignment to OPCODES(3) does not have to be inside the clocked portion of the process.
It has an ugliness to it as it requires the extra signal in the sensitivity list and it does not offer any obvious reason for its inclusion as a solution to the static prefix problem.
To sum up answers in the comments:
Process from your first example will create drivers for all signals from the longest static prefix of OPCODES(I), which is OPCODES. So OPCODES(0) will have driver too. But in your process there is no assignment for OPCODES(0), hence it is 'U'.
When you put OPCODES(3) <= OPCODE_IN; in the process, you make assignment, and problem is solved.
When you unroll your loop, the longest static prefix for your assignments, becomes OPCODES(1), OPCODES(2), and OPCODES(3), instead of OPCODES. So you don't have driver for OPCODES(0) any more, and problem is solved again.
This is one of the quirks where VHDL becomes very counter-intuitive. It is especially confusing since other parallel processing languages don't have it.
Another solution would be to use generate-statement.
architecture CU of CONTROL_UNIT is
type OPCODE_ARRAY is array(3 downto 0) of std_logic_vector(3 downto 0);
signal OPCODES : OPCODE_ARRAY;
begin
OPCODES(3) <= OPCODE_IN; --problem statement!
some_label: for I in 0 to 2 generate
OPCODES(I) <= OPCODES(I + 1) when rising_edge(clk);
end generate;
--more code
end architecture;
Funny enough, in this case OPCODES(I) suddenly is a static expression again. Very consistent, eh? ;)

VHDL program to count upto 10 in 4 bit up counter....?

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
entity counter is
port(CLK, CLR : in std_logic;
output : inout std_logic_vector(3 downto 0));
end counter;
architecture archi of counter is
signal tmp: std_logic_vector(3 downto 0);
begin
process (CLK, CLR)
variable i: integer:=0;
begin
if (CLR='1') then
tmp <= "0000";
elsif (clk = '1') then
for i in 0 to 6 loop
tmp <= tmp + 1;
end loop;
end if;
to count upto 7 i have done for i in 0 to 10. it is not showing any error but it counts from 0000 to 1111
end process;
output <= tmp;
end architecture;
could you please suggest how to do it....sorry for wrong grammar in english
Needs to operate off one clock edge
Because your counter port has clk in it, we can assume you want the counter to count synchronous to the clock.
You're operating off of both clock edges
elsif (clk = '1') then
should be something like
elsif clk'event and clk = '1' then
or
elsif rising_edge(clk) then
These examples use the rising edge of clk. You can't synthesize something that uses both clock edges under the IEEE-1076.6 IEEE Standard for VHDL Register
Transfer Level (RTL) Synthesis. It's not a recognized clocking method.
Making a modulo 10 counter
Under the assumption you want the counter to go from 0 to 9 and rollover this
for i in 0 to 6 loop
tmp <= tmp + 1;
end loop;
Should be something like
if tmp = "1001" then # binary 9
tmp <= (others => '0'); # equivalent to "0000"
else
tmp <= tmp + 1;
end if;
And this emulates a synchronous load that takes priority over increment driven by an external 'state' recognizer. With an asynchronous clear it would emulate an 74163 4 bit counter with an external 4 input gate recognizing "1001" and producing a synchronous parallel load signal loading "0000".
What's wrong with the loop statement
The loop process as shown would result in a single increment and resulting counter rollover at "1111" like you describe. You could remove the for ... loop and end loop; statements and it would behave identically. There's only one schedule future update for a signal for each driver, and a process only has one driver for each signal it assigns. All the loop iterations occur at the same clk event. tmp won't get updated until the next simulation cycle (after the loop is completed) and it's assignment is identical in all loop iterations, the expression tmp + 1. The last loop iterated assignment would be the one that actually occurs and the value it assigns would be identical.
Using a loop statement isn't necessary when counter is state driven (state ≃ tmp). The additional state represented by i isn't needed.
entity mod10 is
Port ( d : out std_logic_vector(3 downto 0);
clr: in std_logic;
clk : in std_logic);
end mod10;
architecture Behavioral of mod10 is
begin
process(clk)
variable temp:std_logic_vector(3 downto 0);
begin
if(clr='1') then temp:="0000";
elsif(rising_edge(clk)) then
temp:=temp+1;
if(temp="1010") then temp:="0000";
end if;
end if;
d<=temp;
end process;
end Behavioral;

vhdl asynchronous assignment in for loop

I am doing something like this:
x : in STD_LOGIC_VECTOR(15 downto 0);
signal x_d: std_logic_vector(15 downto 0);
type inp_concat_array is array (0 to 15) of std_logic_vector(1 downto 0);
signal inp_concat : inp_concat_array;
process (clk, reset)
begin
if (rising_edge(clk)) then
if (reset = '1') then
for i in 0 to 15 loop
x_d(i) <= '0';
end loop;
else
for i in 0 to 15 loop
x_d(i) <= x(i);
end loop;
end if;
end if;
end process;
for j in 0 to 15 loop
inp_concat(j) <= x(j) & x_d(j);
end loop;
Xilinx ISE 14.2 gives following errors
Syntax error near "for"
Syntax error near "loop"
Can i use asynchronous assignments in FOR loop?
The concurrent for loop must be made with a generate statement like:
inp_concat_loop : for j in 0 to 15 generate
inp_concat(j) <= x(j) & x_d(j);
end generate;
or in a process as described in David Koontzs answer.
Without seeing an entire design description answering your question could be a bit risky. You present us with a code fragment and no line numbers for the syntax error. The code fragment contains three for loops.
Now if this fragment represents a continuous segment extracted from a design unit (an architecture) it would appear that you are trying to use a loop statement (the for loop, a sequential statement appropriate for a process or subprogram) in a place appropriate for a concurrent statement (the architecture body).
Providing missing bits for something that might analyze:
library ieee;
use ieee.std_logic_1164.all;
entity asyn is
port (
x : in STD_LOGIC_VECTOR(15 downto 0);
clk: in std_logic;
reset: in std_logic
);
end entity;
architecture foo of asyn is
signal x_d: std_logic_vector(15 downto 0);
type inp_concat_array is array (0 to 15) of std_logic_vector(1 downto 0);
signal inp_concat : inp_concat_array;
begin
process (clk, reset)
begin
if (rising_edge(clk)) then
if (reset = '1') then
for i in 0 to 15 loop
x_d(i) <= '0';
end loop;
else
for i in 0 to 15 loop
x_d(i) <= x(i);
end loop;
end if;
end if;
end process;
for j in 0 to 15 loop
inp_concat(j) <= x(j) & x_d(j);
end loop;
end architecture;
And using a different tool yields:
ghdl -a async.vhdl
async.vhdl:32:5: a generate statement must have a label
async.vhdl:32:22: 'generate' is expected instead of 'loop'
In a place appropriate for a concurrent statement in an architecture body the only statement that can have a for keyword is a generate statement, which requires a label.
There is no requirement in VHDL to look ahead to disambiguate syntax errors (which is why you have a vague error message).
A different tool provides a bit better illustration:
nvc -a async.vhdl
** Error: syntax error, unexpected for, expecting process
File async.vhdl, Line 32
for j in 0 to 15 loop
^^^
So if you put the for loop in a process instead it just might analyze:
NEW_PROCESS:
process (x,x_d)
begin
for j in 0 to 15 loop
inp_concat(j) <= x(j) & x_d(j);
end loop;
end process;
Below is a suggestion for a simpler, neater solution. Simulation results follow.
-----------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
-----------------------------------------------
entity test is
port (
clk, reset: in std_logic;
x: in std_logic_vector(15 downto 0);
--test signals:
test: out std_logic_vector(1 downto 0);
test_index: in natural range 0 to 15);
end entity;
-----------------------------------------------
architecture test of test is
signal x_d: std_logic_vector(15 downto 0);
type inp_concat_array is array (0 to 15) of
std_logic_vector(1 downto 0);
signal inp_concat: inp_concat_array;
begin
process (clk, reset)
begin
if rising_edge(clk) then
if reset = '1' then
x_d <= (others => '0');
else
x_d <= x;
end if;
end if;
end process;
gen: for i in 0 to 15 generate
inp_concat(i) <= x(i) & x_d(i);
end generate;
test <= inp_concat(test_index);
end architecture;
-----------------------------------------------
The problem is that your asynchronous for loop is not inside a process, and needs to be: This should do it
process(x,x_d)
begin
for j in 0 to 15 loop
inp_process(j) <= x(j) & x_d(j);
end loop;
end process;

Resources