How to use a 'case' in VHDL blocks - vhdl

I want to re-use some code block and to make it more readable I tried to put it in a block.
The code block is used to save some data to some buffers. This also includes a case statement. This block is used in a few states in a statemachine.
someBlock: block
begin
destinationAddr <= destinationAddr_i;
sourceAddr <= sourceAddr_i
case type is
when typeA =>
someData <= dataA;
dataLength <= 1;
when typeB =>
someData <= dataB;
dataLength <= 2;
when typeC =>
someData <= dataC;
dataLength <= 3;
end case;
end block;
The code is just an example of what I'm trying to do. I want this code to be inserted in the place I call someBlock.
If I make this block Sigasi and Vivado complain about the case statement. (mismatched input 'case', expecting 'end'). I placed the block declaration after the architecture begin but not inside a process.
Is this the wrong way to use a block? Is there some other way of making a 'function' that can manipulate all signals in the architecture?
edit:
ok figured it out. I tried using a procedure before, i placed it in the architecture but not in the process. The signals weren't accessible according to vivado because it couldn't be sure there wouldn't be multiple drivers (from different processes). If I place the procedure in the process it does work.
Thanks for the help everyone :)

First of all, type is a reserved word and cannot be used for an object name. You also cannot use a case statement based on a checking an object type.
It is complaining because the inside of a Block statement is not a sequential region of the code. Case statements must be used in a sequential region, such as a process, function or procedure. In addition, blocks cannot be re-used, they are there simply to add a local region for scoping purposes.
To make it re-useable, you probably want to use a procedure instead. This would be declared in a declarative region - ie. before a "begin". Here is an example:
procedure mux(constant s : in std_logic;
constant bits : in std_logic_vector(1 downto 0);
signal o : out std_logic
) is
begin
case s is
when '1' => o <= bits(1);
when '0' => o <= bits(0);
when others => o <= 'X'; -- for simulation only
end case;
end procedure;
begin
-- create a synchronous mux
process(clk)
begin
if rising_edge(clk) then
mux(s0, ipA, opA);
end if;
end process;
-- you can call it outside a process also - this infers an async process, sensitive to s1, ipB, opB
mux(s1, ipB, opB);
end architecture;

Related

VHDL record assignment through for loop

I have a for loop in process, which works fine with std_logic arrays, but not with record arrays. I use Xilinx ISE along with ISIM and the code is vhdl-93. The target will be a Spartan 3.
Here is the record definition:
TYPE spi_rx_t IS RECORD
CS : std_logic;
MOSI : std_logic;
CLK : std_logic;
END RECORD;
constant SYNC_LATCHES : integer := 2;
Here is the array definition and declaration:
type spi_rx_array_t is array (0 to SYNC_LATCHES) of spi_rx_t;
signal spi_in_array : spi_rx_array_t;
Below is the process:
spi_in_array(0).MOSI <= SPI_MOSI;
spi_in_array(0).CLK <= SPI_CLK;
spi_in_array(0).CS <= SPI_CS;
sync_p: process (clk_100)
begin
if rising_edge(clk_100) then
-- for I in 1 to SYNC_LATCHES loop
-- spi_in_array(I) <= spi_in_array(I - 1);
-- end loop;
spi_in_array(1) <= spi_in_array(0);
spi_in_array(2) <= spi_in_array(1);
end if;
end process;
The 2 lines below the commented code works exactly as expected (allowing me to synchronize external signals to clk_100), but I'd rather implement them as a for loop (such the commented one).
However, these commented lines does not produce the same result in my ISIM test bench (spi_in_array stays in unknown state when using the for loop). Why?
Please kindly help me with this.
As commented by Morten Zilmer, this is due to the VHDL concept "longest static prefix". This SO answer is similar to my issue.
In my case, the simplest way to resolve the issue was to move the assignment of the first element of the array into the same process as the for loop. I also had to decrease SYNC_LATCHES constant from 2 to 1, because spi_in_array(0) is now latched with clk_100.
sync_p: process (clk_100)
begin
if rising_edge(clk_100) then
spi_in_array(0).MOSI <= SPI_MOSI;
spi_in_array(0).CLK <= SPI_CLK;
spi_in_array(0).CS <= SPI_CS;
for I in 1 to SYNC_LATCHES-1 loop
spi_in_array(I) <= spi_in_array(I - 1);
end loop;
end if;
end process;

VHDL: button debounce inside a Mealy State Machine

Hi I'm trying to implement a mealy machine using VHDL, but I'll need to debounce the button press. My problem is I'm not sure where should I implement the debouncing. My current work is like this:
process(clk)
begin
if(clk' event and clk = '1') then
if rst = '1' then
curr_state <= state0;
else
curr_state <= next_state;
end if;
end if;
end process;
process(curr_state, op1,op0,rst) --here op1,op0 and rst are all physical buttons and I need to debounce op1 and op0
begin
if rst = '1' then
...some implementation
else
...implement the debounce logic first
...process some input
case curr_state is
when state0=>...implementation
...similar stuff
end case;
end process;
I'm not sure whether I'm doing in the right way or not. In the second process, should I put the rst processing like this, or should I put it inside when state0 block? Also, as the processing of debounce requires counting, do I put it outside the case block like this? Thank you!
I would use a completely separate block of code to debounce any button signals, allowing your state machine process to focus on just the state machine, without having to worry about anything else.
You could use a process like this to debounce the input. You could of course exchange variables for signals in this example (with associated assignment operator replacements).
process (clk)
constant DEBOUNCE_CLK_PERIODS : integer := 256; -- Or whatever provides enough debouncing
variable next_button_state : std_logic := '0'; -- Or whatever your 'unpressed' state is
variable debounce_count : integer range 0 to DEBOUNCE_CLK_PERIODS-1 := 0;
begin
if (rising_edge(clk)) then
if (bouncy_button_in /= next_button_state) then
next_button_state := bouncy_button_in;
debounce_count := 0;
else
if (debounce_count /= DEBOUNCE_CLK_PERIODS-1) then
debounce_count := debounce_count + 1;
else
debounced_button_out <= next_button_state;
end if;
end if;
end if;
end process;
Another option would be to sample the bouncy_button_in at a slow rate:
process (clk)
constant DEBOUNCE_CLK_DIVIDER : integer := 256;
variable debounce_count : integer range 0 to DEBOUNCE_CLK_DIVIDER-1 := 0;
begin
if (rising_edge(clk)) then
if (debounce_count /= DEBOUNCE_CLK_DIVIDER-1) then
debounce_count := debounce_count + 1;
else
debounce_count := 0;
debounced_button_out <= bouncy_button_in;
end if;
end if;
end process;
The advantage of the first method is that it will reject glitches in the input. In either case, you would use the debounced_button_out (or whatever you want to call it, perhaps rst) in your state machine, whose code then contains only the core state machine functionality.
If you wanted even more debouncing, you could use another counter to create an enable signal for the processes above, to effectively divide down the clock rate. This could be better than setting the division constant to a very high number, because you may not be able to meet timing if the counter gets beyond a certain size.
You could even create a debounce entity in a separate file, which could be instantiated for each button. It could have a generic for the constant in the above process.
There's also hardware debouncing, but I suppose that's outside the scope of this question.
In the second process, should I put the rst processing like this, or
should I put it inside when state0 block?
Only put it in the State0 block
Also, as the processing of
debounce requires counting, do I put it outside the case block like
this?
Counting needs to be done in a clocked process. Since you are doing a two process statemachine, you cannot do it in the case block. I typically put these sort of resources in a separate clocked process anyway.
For states, you need: IS_0, TO_1, IS_1, TO_0.
The TO_1 and TO_0 are your transition states. I transition from TO_1 to IS_1 when I see a 1 for 16 ms. I transition from TO_0 to IS_0 when I see a 0 for 16 ms. Run your counter when you are in the TO_1 or TO_0 state. Clear your counter when you are in the IS_1 or IS_0 state.
This should get you stated.

Procedure call in loop with non-static signal name

In some testbench code I use a procedure to do something with a signal. I then use this procedure multiple times in sequence on different signals. This works fine as long as I explicitly define the signal; as soon as I index signals in a loop it fails with
(vcom-1450) Actual (indexed name) for formal "s" is not a static signal name.
Why is this not possible and how can I work around it?
Probably I could move this to a for ... generate, but then I want do_something to be called in a nicely defined sequence.
library ieee;
use ieee.std_logic_1164.all;
entity test is
end test;
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
begin
dummy: process is
procedure do_something (
signal s : out std_logic
) is begin
s <= '1';
report "tic";
wait for 1 ns;
-- actually we would do something more interesting here
s <= '0';
report "toc";
end procedure;
begin
-- This works well, but requires manual loop-unrolling
do_something(foo(0));
do_something(foo(1));
-- This should do the same
for i in foo'range loop
-- This is the offending line:
do_something(foo(i));
end loop;
wait; -- for ever
end process dummy;
end architecture tb;
I'm using ModelSim 10.4 PE.
Interestingly, if foo is a variable local to the process, (and s is adjusted to suit) ghdl compiles this. Which highlights the problem in the original version. The "for" loop is required to drive the whole of foo all the time because you can't make signal drivers appear or disappear at will - it can't be ambivalent about which bits it's driving, (and as you can see, the procedure tries to drive different bits at different times).
So if you can readjust your application to allow variable update semantics, and make foo a variable local to the process, that will work. (You would have to copy its value to a signal before every "wait" if you wanted to see the effect!)
Alternatively, pass the entire foo signal and the index to the subprogram, so that the latter always drives all of foo as follows...
(I've also added the missing bits and fixed the spurious concurrent "wait" : in future, PLEASE check your code example actually compiles before posting!)
library ieee;
use ieee.std_logic_1164.all;
entity test is
end test;
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
begin
dummy: process is
procedure do_something (
signal s : out std_logic_vector(1 downto 0);
constant i : in natural
) is begin
s <= (others => '0');
s(i) <= '1';
report "tic";
wait for 1 ns;
-- actually we would do something more interesting here
s(i) <= '0';
report "toc";
end procedure;
begin
-- This works well, but requires manual loop-unrolling
do_something(foo,0);
do_something(foo,1);
-- This should do the same
for i in foo'range loop
-- This is the offending line:
do_something(foo,i);
end loop;
wait; -- for ever
end process dummy;
end architecture tb;
I share your feelings about this being a silly limitation of the language. Minus the wait and report statements your example certainly has a valid hardware implementation, let alone well defined simulation behavior.
I think this situation can be avoided in most cases. For example, in your simple example you could just copy the contents of the procedure into the process body, or pass the whole vector as Brian proposed. If you really need to do it, this is one workaround:
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
signal t : std_logic;
signal p : integer := 0;
begin
foo(p) <= t;
dummy: process is
procedure do_something (
signal s : out std_logic
) is begin
s <= '1';
wait for 1 ns;
s <= '0';
end procedure;
begin
for i in foo'range loop
p <= idx;
do_something(t);
wait for 0 ns;
end loop;
wait;
end process dummy;
end architecture tb;
This only works in simulation and will result in one delta cycle delay per iteration, compared to unrolling the loop which finishes in zero time when the procedure contains no wait statements.

VHDL Parametric case

I've some problem with my synthesis tool. I'm writing a module and I'm tryng to make it parametric and scalable. In my design I've a FSM and some counters. The counters have a parametric width ( they are function of the width of the datapath ). The problem is that I'm using that counter to drive a case statements. The synthesizer gives me back this error :
2049990 ERROR - (VHDL-1544) array type case expression must be of a locally static subtype
I've also tried to use subtype, but it doesnt work. The declaration is :
constant LENGTH_COUNTER_WORD : integer := integer(ceil(log2(real(WIDTH_DATA/WIDTH_WORD))));
subtype type_counter_word is std_logic_vector( LENGTH_COUNTER_WORD - 1 downto 0);
signal counter_word : std_logic_vector( LENGTH_COUNTER_WORD - 1 downto 0);
The case :
case type_counter_word'(counter_word) is
when (others => '1') =>
do_stuff();
when others =>
do_other_stuff();
end case;
I cannot switch to VHDL-2008. I've read I can use variable, but I'd like to find a different solution, if it exists. I cannot imagine there isn't any way to give parameters to synthesizer before the synthesis.
This is fixed in VHDL-2008. You can only work around it in earlier standards by using cascaded if statements (with the attendant priority logic). Variables don't make a difference when determining if choices are locally static.
I'm not sure how complicated your do_stuff() and do_other_stuff() operations are, but if you are just doing simple signal assignments, you could look into the and_reduce() function in the ieee.std_logic_misc library.
As an example:
output <= '1' when and_reduce(type_counter_word'(counter_word)) = '1' else '0';
Otherwise, as Kevin's answer suggests, a process block using if statements might be your best option.
About the time of Kevin's good enough answer, I had written this to demonstrate:
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
entity counterword is
generic (
WIDTH_DATA: positive := 16;
WIDTH_WORD: positive := 8
);
end entity;
architecture foo of counterword is
constant LENGTH_COUNTER_WORD : integer :=
integer(ceil(log2(real(WIDTH_DATA/WIDTH_WORD))));
subtype type_counter_word is
std_logic_vector( LENGTH_COUNTER_WORD - 1 downto 0);
signal counter_word : std_logic_vector( LENGTH_COUNTER_WORD - 1 downto 0);
procedure do_stuff is
begin
end;
procedure do_other_stuff is
begin
end;
begin
UNLABELLED:
process (counter_word)
begin
-- case type_counter_word'(counter_word) is
-- when (others => '1') =>
-- do_stuff;
-- when others =>
-- do_other_stuff;
-- end case;
if counter_word = type_counter_word'(others => '1') then
do_stuff;
else
do_other_stuff;
end if;
end process;
end architecture;
Note because type_counter_word is a subtype you can provide the subtype constraints in a qualified expression for the aggregate:
if counter_word = type_counter_word'(others => '1') then
From IEEE Std 1076-2008:
9.3.5 Qualified expressions
A qualified expression is a basic operation (see 5.1) that is used to explicitly state the type, and possibly the subtype, of an operand that is an expression or an aggregate.
This example analyzes, elaborates and simulates while doing nothing in particular. It'll call the sequential procedure statement do_other_stuff, which does nothing.
(For do_stuff and do_other stuff, empty interface lists aren't allowed).

Continuous assignment seemingly not working

I'm working on a FIR filter, specifically the delay line. x_delayed is initialized to all zeros.
type slv32_array is array(natural range <>) of std_logic_vector(31 downto 0);
...
signal x_delayed : slv32_array(0 to NTAPS-1) := (others => (others => '0'));
This does not work:
x_delayed(0) <= x; -- Continuous assignment
DELAYS : process(samp_clk)
begin
if rising_edge(samp_clk) then
for i in 1 to NTAPS-1 loop
x_delayed(i) <= x_delayed(i-1);
end loop;
end if; -- rising_edge(samp_clk)
end process;
But this does:
DELAYS : process(samp_clk)
begin
if rising_edge(samp_clk) then
x_delayed(0) <= x; -- Registering input
for i in 1 to NTAPS-1 loop
x_delayed(i) <= x_delayed(i-1);
end loop;
end if; -- rising_edge(samp_clk)
end process;
The problem with this "solution" is that the first element in x_delayed is delayed by one sample, which it should not be. (The rest of the code expects x_delayed(0) to be the current sample).
I'm using Xilinx ISE 13.2, simulating with ISim, but this was also confirmed simulating with ModelSim.
What gives?
Edit:
The problem was essentially that, even though x_delayed(0) didn't appear to be driven inside the process, it was.
After implementing Brian Drummond's idea it works perfectly:
x_delayed(0) <= x;
-- Synchronous delay cycles.
DELAYS : process(samp_clk)
begin
-- Disable the clocked driver, allowing the continuous driver above to function correctly.
-- https://stackoverflow.com/questions/18247955/#comment26779546_18248941
x_delayed(0) <= (others => 'Z');
if rising_edge(samp_clk) then
for i in 1 to NTAPS-1 loop
x_delayed(i) <= x_delayed(i-1);
end loop;
end if; -- rising_edge(samp_clk)
end process;
Edit 2:
I took OllieB's suggestion for getting rid of the for loop. I had to change it, since my x_delayed is indexed from (0 to NTAPS-1), but we end up with this nice looking little process:
x_delayed(0) <= x;
DELAYS : process(samp_clk)
begin
x_delayed(0) <= (others => 'Z');
if rising_edge(samp_clk) then
x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1);
end if; -- rising_edge(samp_clk)
end process;
Edit 3:
Following OllieB's next suggestion, it turns out the x_delayed(0) <= (others => 'Z') was unnecessary, following his previous change. The following works just fine:
x_delayed(0) <= x;
DELAYS : process(samp_clk)
begin
if rising_edge(samp_clk) then
x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1);
end if;
end process;
In the first case, the x_delayed(0) actually has two drivers, out outside the
process, being x_delayed(0) <= x, and an implicit one inside the DELAY
process.
The driver inside the process is a consequence of a VHDL standard concept
called "longest static prefix", described in VHDL-2002 standard (IEEE Std
1076-2002) section "6.1 Names", and the loop construction with a loop variable
i, whereby the longest static prefix for x_delayed(i) is x_delayed.
The VHDL standard then further describes drives for processes in section
"12.6.1 Drivers", which says "... There is a single driver for a given scalar
signal S in a process statement, provided that there is at least one signal
assignment statement in that process statement and that the longest static
prefix of the target signal of that signal assignment statement denotes S ...".
So as a (probably surprising) consequence the x_delayed(0) has a driver in
the DELAY process, which drives all std_logic elements to 'U' since unassigned,
whereby the std_logic resolution function causes the resulting value to be 'U',
no matter what value is driven by the external x_delayed(0) <= x.
But in the case of your code, there seems to be more to it, since there actually are some "0" values in the simulation output for x_delayed(0), for what I can see from the figures. However, it is hard to dig further into this when I do not have the entire code.
One way to see that the loop is the reason, is to manually roll out the loop by
replacing the for ... loop with:
x_delayed(1) <= x_delayed(1-1);
x_delayed(2) <= x_delayed(2-1);
...
x_delayed(NTAPS) <= x_delayed(NTAPS-1);
This is of course not a usable solution for configurable modules with NTAPS as
a generic, but it may be interesting to see that the operation then is as
intuitively expected.
EDIT: Multiple solutions are listed in "edit" sections after the question above, based on comments. A solution with variable, which allows for complex expressions if required, is shown below. If complex expression is not required, then as per OllieB's suggestion it is possible to reduce the assign to x_delayed(1 to x_delayed_dir'high) <= x_delayed(0 to x_delayed_dir'high-1):
x_delayed(0) <= x;
DELAYS : process(samp_clk)
variable x_delayed_v : slv32_array(1 to NTAPS-1);
begin
if rising_edge(samp_clk) then
for i in 1 to NTAPS-1 loop
x_delayed_v(i) := x_delayed(i-1); -- More complex operations are also possible
end loop;
x_delayed(1 to x_delayed_dir'high) <= x_delayed_v;
end if; -- rising_edge(samp_clk)
end process;
During elaboration, drivers are created for all elements in x_delayed, regardless of the range of loop iterator. Hence, x_delayed(0) has two drivers associated with it. Std_Logic and Std_Logic_Vector are resoved types(i.e., when multiple drivers are associated with the signal with these types, the resolved function will determine the value of the signal by looking up a table in std package. Please refer to VHDL Coding Styles and Methodologies for more details.
the reason you have a problem is that the logic thinks you have two things assigning into the same signal simultaneously - both the continues assignment and the register assignment loop.
keep with the register implementation.
edit
if you have modelsim, you can use the 'trace x' option and see where it comes from.
might be that the other simulator also have this feature, but for modelsim i'm certain it works
In you not working example
x_delayed(0) <= x;
is aquvalent to
process(x)
begin
x_delayed(0) <= x;
end process;
So the process will assign x_delayed(0) only when x changes. Because this is a signal asignment the x_delayed(0) will not change immediatly, it will change after a delta cycle. Therefore, when process DELAYS is called assignment for x_delayed(0) is not happened yet!
Use a variable for x_delayed in your process, if you could.
x_delayed(0) := x;

Resources