VHDL ignores statement outside a process - vhdl

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? ;)

Related

Variable or signal in vhdl for shared value between different process

I need to share a value (a real) between two process, but when I try to run my code, quartus gives me an error.
library IEEE;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;
use IEEE.MATH_REAL.ALL;
entity de0nano is
port (
CLOCK_50 : in std_logic;
KEY : in std_logic_vector(1 downto 0);
SW : in std_logic_vector(3 downto 0);
LED : out std_logic_vector(7 downto 0);
GPIO : inout std_logic_vector(35 downto 0)
);
end de0nano;
architecture struct of de0nano is
--declarations
signal PN : real :=0.0 ;
signal PR : real :=0.0 ;
signal RC : integer :=1;
signal NC : integer :=1;
signal BET : integer :=1;
begin
count : process (CLOCK_50, GPIO)
begin
--A <= KEY(0);
GPIO(24) <= '1';
--functional coding
LED <= "00011000";
if (pn > pr) then
GPIO(26) <= '1';
LED <= "00000001";
else
GPIO(26) <= '0';
end if;
if (pn = pr) then
GPIO(26) <= '1';
LED <= "00000010";
else
GPIO(26) <= '0';
end if;
if (pn < pr) then
GPIO(26) <= '1';
LED <= "00000011";
else
GPIO(26) <= '0';
end if;
end process;
probabilityController : process (CLOCK_50, KEY)
begin
--stato iniziale
if((RC + NC + BET)=1) then
pr <= 0.5;
pn <= 0.5;
end if;
--sequenza rossi consecutivi
if(RC>0) then
pr <= (5)**RC;
pn <= 1- (5)**RC;
end if;
--sequenza neri consecutivi
if(NC>0) then
pr <= (5)**NC;
pn <= 1- (5)**NC;
end if;
end process;
betController : process (CLOCK_50)
begin
end process;
colorController : process (CLOCK_50, KEY)
begin
if(KEY(0)='1') then
NC<=0;
RC <= RC+1;
end if;
if(KEY(1)='1') then
RC<=0;
NC <= NC+1;
end if;
end process;
end str
How can I operate in the same signal/variable from two different processes?
VHDL is a hardware description language. A VHDL description can be simulated (executed a bit like you do with most programming languages) or synthesized (transformed in a network of interconnected simple hardware elements). Some tools are pure simulators (Mentor Graphics Modelsim, Cadence ncsim...), others are pure synthesizers (Mentor Graphics Precision RTL, Cadence RTL compiler...) and others can do both. Quartus pertains to the last category. So, the first thing to do is to decide whether you want to simulate, synthesize or both.
In case you want to simulate you must fix three errors:
the position of your signal declaration,
the way you assign it (:=) which is the variable assignment operator, not the signal assignment (<=)
and the fact that you drive it from two processes while it is of an unresolved type (real). See this other answer for resolved / unresolved VHDL types.
Your code could then look like this (but as I do not know what you are trying to do, it is probably not what you want):
architecture V1 of AOI is
Signal foobar : real := 0.0;
begin
OneTwo : process (clk)
Begin
Foobar <= foobar + 2.0;
End process;
end V1;
If you want to synthesize you will have to fix a few more problems:
You are using the real type which is the floating point VHDL type. This is not synthesizable by the synthesizers I know. Indeed, what would you expect the synthesizer to do? Instantiate a complete floating point unit? What brand? So, you will have to replace real by some other type (integers, bit vectors...).
You are assigning your signal on both edges of what I believe is your clock (clk). This is probably not what you want.
You are initializing the signal at declaration time. This is usually not synthesizable by the synthesizers I know. In fact this initialization time has a clear meaning for simulation: it is the beginning of the simulation. But what about hardware? What is the beginning of a piece of hardware? Manufacturing? Power up? So, if you want the signal to be initialized at some point you will have to add a hardware reset, driven by a reset input.
All in all you could have something like:
architecture V1 of AOI is
Signal foobar : natural range 0 to 255;
begin
OneTwo : process (clk)
Begin
if rising_edge(clk) then
if reset = '1' then
foobar <= 0;
else
foobar <= foobar + 2;
end if;
end if;
End process;
end V1;
Notes:
VHDL is case insensitive but you should try to be consistent, it will help you.
You should probably take a VHDL course or read a VHDL primer before trying to use the language. It is radically different from the programming languages you already know. Hardware and software are pretty different worlds, even if they are strongly connected at the end.

VHDL - Comparing present and past inputs

I have a system that has a 3 input D_in which is read at every positive clk edge.
If say I want to see if the current input, D_in is greater then the previous D_in by at least 2, then a count will increment. How do I write this in VHDL?
if clk'event and clk = '1' then --read at positive edge
if D_in > (D_in + 010) then <---I am sure this is wrong. How to write the proper code?
Entity ABC is
Port(D_in: in std_logic_vector(2 downto 0);
Count: out std_logic_vector(2 downto 0));
Architecture ABC_1 of ABC is
signal D_last: std_logic_vector(2 downto 0);
Begin
Process(D_in)
D_last <= D_in;
if clk'event and clk = '1' then
if D_last > (D_in + 2) then
count <= count + 1;
end if;
end process;
end ABC_1;
The "good" way to write this process is as follow :
process (clk)
begin
if (rising_edge(clk)) then
-- store the value for the next time the process will be activated
-- Note that D_last value will be changed after the whole process is completed
D_last <= D_in;
-- compare the actual D_in value with the previous one stored in D_last.
-- D_last value is its value at the very beginning of the process activation
if (D_in > D_last + 2) then
-- increment the counter
count <= count + 1;
end if;
end if;
end process;
Note that D_in, D_last and count has to be declared as unsigned and not as std_logic_vector.
I suggest you to read this post which explains how a process actually works : when are signals updated and which signal value is used into the process.
Cheers
[edit] This answer should be fine for your question. But the code you show has other errors :
The signal clk has to be an input for your entity.
The signal count can't be read in your architecture because it's defined as output in the entity. Then the line "count <= count + 1" can't be resolved. You have to use an internal signal and then assign its value to "count" outside of a process :
count <= count_in;
There are several other errors in your design specification as well. This answer attempts to answer all concerns in one place.
VHDL is simulated by executing processes in simulation cycles. Every
concurrent statement can be expresses as either an equivalent process
statement or combination of process statements and block statements.
Signal assignment is to a projected output waveform queue for a specified
time. When no time is specified it's the current time, and the value will be updated
prior to executing processes in the next simulation cycle, a delta cycle, simulation
time is advanced when there are no remaining events scheduled for the
current simulation time.
To avoid confusion over when signal assignments occur, view them as
separate processes (whether you express them that way or not).
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity abc is
port (
clk: in std_logic; -- Note 1
d_in: in std_logic_vector(2 downto 0);
count: out std_logic_vector(2 downto 0)
);
end entity; -- Note 2
architecture foo of abc is
signal d_last: std_logic_vector(2 downto 0);
begin
DLAST: -- Note 3
process (clk)
begin
if rising_edge(clk) then -- Note 4
d_last <= d_in;
end if;
end process;
INC_COUNT:
process (clk)
variable cnt: unsigned(2 downto 0) := "000"; -- Note 5
begin
if rising_edge(clk) and
unsigned(d_last) > unsigned(d_in) + 2 then -- Mote 6,7
cnt := cnt + 1;
end if;
count <= std_logic_vector(cnt);
end process;
end architecture;
Notes
Missing clk from port interface
Missing end statement for entity ABC.
Conceptually view D_last
register separately from Count counter sensitive to clk. (Can be
merged as one process)
rising_edge function expresses clk'event and clk = '1' ('event
and "=" are both functions)
The counter must represent a binary value for "+" to produce a
binary result
"+" is higher priority than ">", which is higher priority than "and"
(you don't need parentheses)
Package numeric_std provide relational and adding operators for
type sign and type unsigned, requiring type conversion for D_last
and D_in.
Alternatively use Synopsys package std_logic_unsigned which
depends on Synopsys package std_logic_arith and treats
std_logic_vector as unsigned. This avoids type conversion, and
allows array types to be declared as type std_logic_vector.
The variable cnt can be done away with if port count were to be declared mode buffer and provided a default value:
count: buffer std_logic_vector(2 downto 0) :="000" -- Note 5
and
INC_COUNT:
process (clk)
begin
if rising_edge(clk) and
unsigned(d_last) > unsigned(d_in) + 2 then -- Note 6,7
count <= std_logic_vector(unsigned(count) + 1);
end if;
end process;
You can't use Count as mode out to algorithmically modify it's own value. The ability to access the value of a mode out port is intended for verification and is a IEEE Std 1076-2008 feature.
And about now you can see the value of Synopsys's std_logic_unsigned package, at least as far avoiding type conversions.
Also, i got another question. If d_in is 0 for 3 consecutive clk cycles, i want to reset count to 0. How do i write the code to represent for 3 clk cycles?
Add another pipeline signal for D_in:
signal d_last: std_logic_vector(2 downto 0) := "000";
signal d_last1: std_logic_vector(2 downto 0) := "000";
Note these also have default values, which FPGA synthesis will generally honor, it's represented by the state of the flip flop in the bistream image used for programming the FPGA.
And modify how the counter is operated:
INC_COUNT:
process (clk)
begin
if rising_edge(clk) then
if d_in = "000" and d_last = "000" and d_last1 = "000" then
count <= "000";
elsif unsigned(d_last) > unsigned(d_in) + 2 then -- Note 6,7
count <= std_logic_vector(unsigned(count) + 1);
end if;
end if;
end process;
The three incarnations of the example all analyze, they haven't been simulation and should be synthesis eligible.

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;

8 bit serial adder with accumulator

I am writing a VHDL code to impelemt 8 bit serial adder with accumulator.
When i do simulation, the output is always zeros! And some times it gives me the same number but with a shift !
I dont know what is the problem, i tried to put A,B as inout but didnt work as well. Can anybody help please.
This is the code:
entity SA is
Port ( st : in std_logic;
A,B: inout std_logic_vector ( 7 downto 0);
clk : in std_logic;
acc : out bit_vector(7 downto 0)); end SA;
architecture Behavioral of SA is
signal ps,ns: integer range 0 to 7;
signal C,D: bit_vector (7 downto 0);
signal ci,ciplus,si,sh:bit;
begin
si<=A(0) xor B(0) xor ci ;
ciplus <=(A(0) and B(0)) or (A(0) and ci ) or ( B(0) and ci );
process(ps,st)
begin
case ps is
when 0=> if(st='0')then
ns<=0;
else
ns<=1;
sh<='1';
end if;
when 1 to 6 => sh<='1';
ns<= ps+1;
when 7=> sh<='1';
ns <=0;
end case;
end process;
process(clk)
begin
if(clk 'event and clk ='1')then
ps <= ns;
ci<= ciplus;
end if;
if(sh='1') then
C<=si & A(7 downto 1) ;
D<=B(0) & B(7 downto 1);
end if;
end process;
acc<= C;
end Behavioral;
`
Your second process is written incorrectly. Prior to writing a process, you should always decide whether the process is sequential or combinatorial, and then write the process accordingly.
To help you write your code, especially when starting out with hardware description languages, please please please always draw a block diagram first, and then describe that block diagram using VHDL.
As it is, your second process:
Mixes combinatorial and sequential logic.
Is missing signals in the process sensitivity list.
Generates a latch because C and D are not assigned in all paths through the process.
Your first process has similar problems.
try initializing ps and ns see if that does the trick I am on my phone now so i cant simulate to help but usualy my problems in VHDL design are form uninitilized integers
signal ps,ns: integer range 0 to 7:=0;
you might want to check your warnings list see if that helps

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