VHDL Parametric case - vhdl

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).

Related

Overloading function in subprogram, but I it has "already been defined"

I'm trying to compile my subprogram pack and I get this error:
** Error: C:/Users/kmgrytte/Downloads/subprog_pck.vhd(16): (vcom-1295) Function "parity" has already been defined in this region.
** =====> Prior declaration of "parity" is at C:/Users/kmgrytte/Downloads/subprog_pck.vhd(12).
** Error: C:/Users/kmgrytte/Downloads/subprog_pck.vhd(20): VHDL Compiler exiting
Oveloading like this worked in my main program and I can't find any good examples of overloading in subprograms online.
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
package subprog_pck is
procedure parity;
procedure parity(
in1 : in std_logic_vector(15 downto 0);
in2 : in std_logic_vector(15 downto 0);
par : out std_logic);
function parity return std_logic;
function parity(
indata : in std_logic_vector(15 downto 0)) return std_logic;
impure function parity return std_logic;
impure function parity(
indata : in unsigned(15 downto 0)) return std_logic;
end package subprog_pck;
package body subprog_pck is
procedure parity(
in1 : in std_logic_vector(15 downto 0);
in2 : in std_logic_vector(15 downto 0);
par : out std_logic) is
begin
variable parity1, parity2 : std_logic:=0;
if (rst_n = '0') then
parity1 := '0';
parity2 := '0';
par <= '0';
elsif rising_edge(mclk) then
parity1 := '0';
for i in in1'range loop
if in1(i) = '1' then
parity1 := not parity1;
end if;
end loop;
parity2 := '0';
for j in in2'range loop
parity2 := parity2 xor in2(j);
end loop;
par <= parity1 xor parity2;
end if;
end parity;
function parity(indata : in std_logic_vector(15 downto 0)) return std_logic is
variable parity_var : std_logic := '0';
begin
for i in indata'range loop
if (indata(i) = '1') then
parity_var := not parity_var;
end if;
end loop;
return parity_var;
end function parity;
function parity(indata : in unsigned(15 downto 0))
return std_logic is
variable parity_var : std_logic := '0';
begin
for j in indata'range loop
parity_var := parity_var xor indata(j);
end loop;
return parity_var;
end function parity;
end package body subprog_pck;
Function overloading only occurs when you have the same function name with a different parameter list. Using impure does not overload another function. So you have two version of parity that takes no inputs and outputs a std_logic. Hence the compile error.
You also didn't provide a this version of parity in the package body.
There are additional errors in your package which is missing a library clause (library ieee;) in the context clause. The procedure parity has a variable declaration after begin, your initial values for parity1 and parity2 are 0 (a numeric literal), there's no declaration for rst_n or mclk, par in par <= ... is not a signal, there's no body for procedure parity or function parity with no parameters.
IEEE Std 1076-2008
12.3 Visibility
Two declarations that occur immediately within the same declarative region, other than the declarative region of a block implied by a component instantiation or the declarative region of a generic-mapped package or subprogram equivalent to a package instance or a subprogram instance, shall not be homographs, unless exactly one of them is the implicit declaration of a predefined operation or is an implicit alias of such an implicit declaration.
(There's no implicit declaration here and no predefined operation, emphasis added.)
Also in 12.3
... Each of two declarations is said to be a homograph of the other if and only if both declarations have the same designator, and they denote different named entities, and either overloading is allowed for at most one of the two, or overloading is allowed for both declarations and they have the same parameter and result type profile (see 4.5.1).
4.5 Subprogram overloading
4.5.1
Two formal parameter lists are said to have the same parameter type profile if and only if they have the same number of parameters, and if at each parameter position the corresponding parameters have the same base type. Two subprograms are said to have the same parameter and result type profile if and only if both have the same parameter type profile, and if either both are functions with the same result base type or neither of the two is a function.
You have more than one of these errors. vcom quit after the first one. The order in which errors are found are left to vagaries of the VHDL tool implementation applying semantic rules (other tools might find other errors first, explaining how the errors in the first paragraph above were found).
Modelsim has a verror tool providing more explanation:
vcom Message # 1295:
Two declarations that occur immediately within the same declarative
region must not be homographs, unless exactly one of them is the
declaration of a predefined operation.
Each of two declarations is said to be a homograph of the other if both
declarations have the same identifier, operator symbol, or character
literal, and if overloading is allowed for at most one of the two.
If overloading is allowed for both declarations, then each of the two is
a homograph of the other if they have the same identifier, operator
symbol, or character literal, as well as the same parameter and result
type profile (see 3.1.1). Overloading is defined only for subprograms
(including those those whose designator is an operator symbol) and
enumeration literals (including character literals).
[DOC: IEEE Std 1076-1993 VHDL LRM - 10.3 Visibility]
(These references are from the -1993 revision of the standard.)

VHDL-2008 to_01 conversion

I am getting some unexpected behavior when using the to_01 conversion function in VHDL-2008. My expectation would be that vector bits that can clearly be interpreted as high or low are mapped to '1' and '0' respectively. The remaining vector bits should be converted to '0' bits.
However, with the code depicted below, I get the whole vector converted to all '0's.
Is this behavior correct? Or is this a bug in the simulator software (ALDEC Riviera-PRO)?
Is there any IEEE function that meets my expectations or do I have to write my own function to achieve that?
library ieee;
use ieee.std_logic_1164.all;
entity test_to_01 is
end entity test_to_01;
architecture rtl of test_to_01 is
signal s_test_in : std_logic_vector(8 downto 0) := "UX01ZWLH-";
signal s_test_out : std_logic_vector(8 downto 0);
begin
s_test_out <= to_01(s_test_in);
end architecture rtl;
The observed behavior is the correct behavior. A little history about this follows.
In 2008, we propagated all of the strength reduction operations to all std_logic family packages. For better or worse, the historical implementation of to_01 comes from numeric_std and was implemented exactly as it is now. The following is an older implementation I was able to find on the web:
function TO_01(S : SIGNED ; xmap : STD_LOGIC:= '0') return SIGNED is
variable RESULT: SIGNED(S'length-1 downto 0);
variable bad_element : boolean := FALSE;
alias xs : SIGNED(s'length-1 downto 0) is S;
begin
for i in RESULT'range loop
case xs(i) is
when '0' | 'L' => RESULT(i):='0';
when '1' | 'H' => RESULT(i):='1';
when others => bad_element := TRUE;
end case;
end loop;
if bad_element then
assert NO_WARNING
report "numeric_std.TO_01: Array Element not in {0,1,H,L}"
severity warning;
for i in RESULT'range loop
RESULT(i) := xmap; -- standard fixup
end loop;
end if;
return RESULT;
end TO_01;
One of the prime directives of the VHDL WG is to not break old code. In this case it looks like this objective put forward an implementation that perhaps is less desirable.
If you want something different, you can always put it forward for the next revision of the standard. It would have to have a different name. Note we are currently closing on VHDL-2018 now, so it would be the revision after that.
Note that IEEE P1076 WG is an individual based working group. This means experienced users, such as yourself, are participating. Typically the amount of work done in a standards revision is overwhelming. As a result, we always need more active participants. Particularly working on the packages. See eda-twiki.org and http://www.eda-twiki.org/cgi-bin/view.cgi/P1076/WebHome
I found a workaround:
s_test_out <= to_stdlogicvector(to_bitvector(s_test_in));

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.

Unexpected if vhdl

This error has been mindfucking me for long, I don't know what to do. I get the same error in other codes, but this one is a simple one, so maybe it's easier to find out what's the problem.
It's a frequency selector, if the switch (clau) is on, the frequency changes.
library IEEE;
use IEEE.numeric_bit.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity selector_frequencia is
Port ( unHz : in bit ;
centHz : in bit ;
Clock : out bit;
clau: in bit);
end selector_frequencia;
architecture Behavioral of selector_frequencia is
begin
if (clau = "0") then Clock <= unHz;
else Clock <= centHz;
end if;
end Behavioral;
And the error I get is this one:
ERROR:HDLParsers:164 - "C:/Documents and Settings/Administrador/Escritorio/practica_digital/practica_digital/selector_frequencia.vhdl" Line 23. parse error, unexpected IF
Thank you.
I'm not really an expert in VHDL but I believe you should use the if statement inside a process:
architecture Behavioral of selector_frequencia is
begin
fqsel:PROCESS(unHz , centHz , Clock , clau)
BEGIN
if (clau = '0') then
Clock <= unHz;
else
Clock <= centHz;
end if;
END PROCESS fqsel;
end Behavioral;
As Alex pointed out, your if statement needs to be inside a process block. In addition, VHDL is not C...you are not supposed to put parens () around the conditional or it looks like a procedure/function call or a signal range ie: my_bus(7 downto 0) but it's a syntax error because if is a reserved word. Try:
process (clau, unHz, centHz)
begin
if clau = '0' then
Clock <= unHz;
else
Clock <= centHz;
end if;
end process;
Finally, outside of a process, you can just use a conditional signal assignment, which is a short-hand way of implementing the equivalent process and if statements:
Clock <= unHz when clau='0' else centHz;
You are using an assignment statement in your IF clause:
// This is assignment, you are assigning 'clau' to 0 and then checking it in 'if'
if (clau = "0") then Clock <= unHz;
// Try this, note the double '='
if (clau == "0") then Clock <= unHz;
Assignment statements should be within a PROCESS block.
Hope this helps.

VHDL operator argument type mismatch

I have a very simple operator problem in VHDL. I try to compare some inputs with logical operators but get an error message...
entity test is
port (
paddr : in std_logic_vector(15 downto 0);
psel : in std_logic;
penable : in std_logic;
pwrite : in std_logic
);
end entity test;
signal wrfifo_full : std_logic;
process (paddr, psel, penable, pwrite, wrfifo_full) is
begin
if (((paddr(8 downto 2) = "1000000")) and (psel and penable) and (pwrite and not(wrfifo_full))) then
dt_fifo_wr_i <= '1';
else
dt_fifo_wr_i <= '0';
end if;
end process;
Unfortuantely, I get then the following error message:
if (((paddr(8 downto 2) = "1000000")) and (psel and penable) and
(pwrite and not(wrfifo_full))) then
| ncvhdl_p: *E,OPTYMM (hdl/vhdl/test.vhd,523|43): operator argument type mismatch
87[4.3.3.2] 93[4.3.2.2] [7.2]
Anyway sees the problem?
Cheers
psel, penable, pwrite and wrfifo_full are all std_logic.
In vhdl, to write the test they way you have, they would need to be boolean.
Instead write the code so that you are comparing their values to 1 or zero.
(paddr(8 downto 2) = "1000000" and
psel = '1' and penable ='1' and
pwrite = '1' and wrfifo_full = '0')
As George said, you have to currently convert all your std logics to booleans.
In VHDL-2008 however, there is a new conditional operator (??) which is applied implicitly to statements such as yours, which means they will work as you hoped. You'll have to enable VHDL-2008 support on you compiler (or whinge at your supplier to get with the times :)
This book is a good read on all the new bits that VHDL2008 gives us:
VHDL-2008 Just the new stuff
Section 4.4 covers the conditional operator

Resources