VHDL: setting a constant conditionally based on another constant's value - vhdl

I need to set a constant's value using an "if-else" or "case", and select a different constant value based on another constant's value. Is this possible in VHDL? It would be a one time change of constant values at the beginning of simulation... Example:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bridge is
generic (
burst_mode :std_logic := '0'
);
end entity;
architecture rtl of bridge is
constant fifo_aw_wdata :natural := 2 when (burst_mode = '0') else 5;
begin
-- fifo: entity work myfifo
-- generic map(
-- aw => fifo_aw_wdata
-- )
-- port map(
-- ...
-- );
end architecture;
The above VHDL code gives the error message:
Error ';' is expected instead of 'when'
In Verilog, Its very easy to do this type of thing...so I assume VHDL has a away to do this as well? Verilog example:
module #(parameter burst_mode = 1'b0) bridge;
localparam fifo_aw_wdata = (!burst_mode) ? 2 : 5;
// fifo myfifo #(.aw(fifo_aw_wdata)) ( ...);
endmodule;

This solution is a little bit strange, but it works:
architecture rtl of bridge is
function setup1(s:std_logic; i0:integer; i1:integer)
return integer is
begin
if s = '1' then
return i1;
else
return i0;
end if;
end function;
constant fifo_aw_wdata :natural := setup1(burst_mode, 2, 5);
begin
-- fifo: entity work myfifo
-- generic map(
-- aw => fifo_aw_wdata
-- )
-- port map(
-- ...
-- );
end architecture;

Correct answers have been posted, but there are also one-line alternatives.
The simplest solution is to change the datatype of burst_mode to integer with range 0 to 1, and then use some math:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bridge is
generic (
burst_mode :integer range 0 to 1 := 0
);
end entity;
architecture rtl of bridge is
constant fifo_aw_wdata :natural := 2 + burst_mode * 3;
begin
If the datatype of burst_mode cannot be changed, then you can also do it with a type conversion:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bridge is
generic (
burst_mode :std_logic := '0'
);
end entity;
architecture rtl of bridge is
constant fifo_aw_wdata :natural := 2 + to_integer(unsigned('0' & burst_mode)) * 3;
begin

Though pico posted an answer already, it is a very relevant question worthy of elaboration.
The declaration of the function may be similar to "conditional expressions" or "ternary if" in other languages like Python with res_true if cond else res_false or C with cond ? res_true : res_false.
The condition is then a boolean, and the result for true comes before the result for false. The declaration could be like:
function tif(cond : boolean; ref_true, ref_false : integer) return integer is
begin
if cond then
return res_true;
else
return res_false;
end if;
end function;
And having multiple functions with different result types, a version for real could also be defined like:
function tif(cond : boolean; res_true, res_false : real) return real is
begin
if cond then
return res_true;
else
return res_false;
end if;
end function;

Related

VHDL enumerator relational operators

I'm currently programming a system in VHDL, and I'm using an enumerator from another package called vnir, which is defined as such:
package vnir is
type row_type_t is (ROW_NONE, ROW_NIR, ROW_BLUE, ROW_RED);
end package vnir;
I've defined my architecture as such
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vnir;
entity imaging_buffer is
port(
clock : in std_logic;
reset_n : in std_logic;
vnir_row_ready : in vnir.row_type_t
);
end entity imaging_buffer;
architecture rtl of imaging_buffer is
signal vnir_row_ready_i : vnir.row_type_t;
begin
vnir_pipeline : process (reset_n, clock) is
begin
if (reset_n = '0') then
vnir_row_ready_i <= vnir.ROW_NONE;
elsif rising_edge(clock) then
if (vnir_row_ready /= vnir.ROW_NONE) then
--do stuff
end if;
end if;
end process vnir_pipeline;
end architecture;
The internal signal vnir_row_ready_i can be assigned to no problem, however the relational operator doesn't seem to work as ModelSim throws this error when I try to compile:
# ** Error: C:/Users/nashg/Documents/iris_project/ex2_iris/vhdl/subsystems/sdram/Imaging Buffer/test.vhd(23): (vcom-1581) No feasible entries for infix operator '/='.
# ** Error: C:/Users/nashg/Documents/iris_project/ex2_iris/vhdl/subsystems/sdram/Imaging Buffer/test.vhd(23): Type error resolving infix expression "/=" as type std.STANDARD.BOOLEAN.
# ** Error: C:/Users/nashg/Documents/iris_project/ex2_iris/vhdl/subsystems/sdram/Imaging Buffer/test.vhd(28): VHDL Compiler exiting
My coworker helped me figure out how to make it work! I think that the /= operator is created in the vnir scope, but not ported over to the entity I'm working on. By writing :use work.vnir."/="; at the beginning of the file it compiles, so the full entity looks like so:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vnir;
use work.vnir."/=";
entity imaging_buffer is
port(
clock : in std_logic;
reset_n : in std_logic;
vnir_row_ready : in vnir.row_type_t
);
end entity imaging_buffer;
architecture rtl of imaging_buffer is
signal vnir_row_ready_i : vnir.row_type_t;
begin
vnir_pipeline : process (reset_n, clock) is
begin
if (reset_n = '0') then
vnir_row_ready_i <= vnir.ROW_NONE;
elsif rising_edge(clock) then
if (vnir_row_ready /= vnir.ROW_NONE) then
--do stuff
end if;
end if;
end process vnir_pipeline;
end architecture;
Alternatively it did work by including use work.vnir.all; and taking out the vnir. before the types, but that wasn't possible with the project I'm working one

How to write to console a custom array type

I am fairly new to VHDL and I am running some snippets from a code I was given to see what it is doing. There is a custom array type I want to see in the console, but I get and error when I try to write it.
entity hello_world is
end entity hello_world;
library STD;
library IEEE;
use IEEE.std_logic_1164.all;
use STD.textio.all;
use IEEE.std_logic_textio.all;
use IEEE.numeric_std.all;
architecture test of hello_world is
type row_type is array(0 to 2) of std_logic_vector(3 downto 0);
type new_type is array(0 to 1) of row_type;
signal max_new : new_type := (others => (others => (others => '0')));
begin
my_print : process is
variable my_line : line;
begin
write(my_line, string'("Value of max_new"));
write(my_line, max_new);
writeline(output, my_line);
wait;
end process my_print;
end architecture test;
The error I get while running the simulation is:
Error: type error near 'max_new': expected type 'std_ulogic'. Error: formal 'l' of mode inout must have an associated actual. Error: formal 'value' has no actual or default value. Error: indexed name prefix type 'void' is not an array type
If I understood correctly, row type is an array of size 3, in each position I have a vector made of 4 bits. new_type is an array of size 2, in each position I have a row_type, which is an array of size 3 with a 4 bits vector in each position. Is this correct? Since it is initialized to 0, I expect to see only that.
I am using Vivado 2018.3 for the simulation.
Any help would be highly appreciated!
You could also author your own write procedure:
entity hello_world is
end entity hello_world;
-- library STD;
library IEEE;
use IEEE.std_logic_1164.all;
use STD.textio.all;
use IEEE.std_logic_textio.all;
-- use IEEE.numeric_std.all;
architecture test of hello_world is
type row_type is array(0 to 2) of std_logic_vector(3 downto 0);
type new_type is array(0 to 1) of row_type;
signal max_new : new_type := (others => (others => (others => '0')));
procedure write (l: inout line; new_type_val: in new_type) is
begin
write (l, string'("("));
for i in new_type'range loop
write (l, string'("("));
for j in row_type'range loop
write (l, string'(""""));
write(l, new_type_val(i)(j));
write (l, string'(""""));
if j /= row_type'right then
write(l, string'(","));
end if;
end loop;
write (l, string'(")"));
if i /= new_type'right then
write(l, string'(","));
end if;
end loop;
write (l, string'(")"));
end procedure;
begin
my_print:
process is
variable my_line: line;
begin
write(my_line, string'("Value of max_new = "));
write(my_line, max_new);
writeline(output, my_line);
wait;
end process my_print;
end architecture test;
ghdl -r hello_world
Value of max_new = (("0000","0000","0000"),("0000","0000","0000"))
using preexisting write procedure overloads as building blocks.
You can also use type specific conversions to strings eliminating the dependence on Synopsys package std_logic_textio as well as introducing the ability to use report statements:
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
architecture no_std_logic_textio of hello_world is
type row_type is array(0 to 2) of std_logic_vector(3 downto 0);
type new_type is array(0 to 1) of row_type;
signal max_new : new_type := (others => (others => (others => '0')));
-- For VHDL version < -2008:
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
function to_string (nt: new_type) return string is
variable l: line;
begin
write (l, string'("("));
for i in new_type'range loop
write (l, string'("("));
for j in row_type'range loop
write (l, '"' & to_string(nt(i)(j)) & '"');
if j /= row_type'right then
write(l, string'(","));
end if;
end loop;
write (l, string'(")"));
if i /= new_type'right then
write(l, string'(","));
end if;
end loop;
write (l, string'(")"));
return l.all;
end function;
begin
my_print:
process is
variable my_line: line;
begin
write (my_line, string'("value of max_new = "));
write(my_line, to_string(max_new));
writeline(output, my_line);
report LF & HT & "max_new = " & to_string(max_new);
wait;
end process my_print;
end architecture no_std_logic_textio;
And this demonstrates both writing to output and a report statement:
ghdl -r hello_world
value of max_new = (("0000","0000","0000"),("0000","0000","0000"))
hello_world.vhdl:95:9:#0ms:(report note):
max_new = (("0000","0000","0000"),("0000","0000","0000"))
The function write of std.textio can take the following arguments as value (https://www.hdlworks.com/hdl_corner/vhdl_ref/VHDLContents/TEXTIOPackage.htm) :
bit
bit_vector
boolean
character
integer
real
string
time
IEEE.std_logic_textio add std_logic and his derivated to this list but Array is not handled by write.
You can print your array like that :
my_print : process is
variable my_line : line;
begin
write(my_line, string'("Value of max_new"));
for I in 0 to 1 loop
for J in 0 to 2 loop
write(my_line, max_new(I)(J));
end loop;
end loop;
writeline(output, my_line);
wait;
end process my_print;

HDLCompiler:432 error on converting std_logic_vector to integer

I'm having the errors below on converting a std_logic_vector to integer.I've googled the problem to fix it but I didn't find an answer.
Please help me.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_arith.all;
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity packet_size is
generic(
fifo_MaxDepth:integer range 0 to 256:=16
);
port(
fifo_tlast:in std_logic_vector(fifo_MaxDepth -1 downto 0);
depth:in std_logic_vector(fifo_MaxDepth -1 downto 0);
rd_ptr,wr_ptr:in integer range 0 to fifo_MaxDepth - 1;
pckt_size:out integer range 0 to fifo_MaxDepth
);
end packet_size;
architecture Behavioral of packet_size is
signal temp:integer range 0 to 256:=0;
variable finish_flag:bit:='0';
variable PacketSize_temp:integer range 0 to fifo_MaxDepth;
begin
process (fifo_tlast,rd_ptr,wr_ptr) is
begin
temp<=to_integer(unsigned(depth)); --THE CONVERT STATEMENT IS HERE
for i in rd_ptr to temp loop
if(finish_flag='0') then
PacketSize_temp:=PacketSize_temp + 1;
if(fifo_tlast(i)='1') then
finish_flag:='1';
end if;
end if;
end loop;
end process;
end Behavioral;
and my errors are(the line 53 refers to the convert statement)
ERROR:HDLCompiler:607 - "I:\xilinx\Deficit-Round_Rrobbin\packet_size.vhd" Line 53: Multiple declarations of unsigned included via multiple use clauses; none are made directly visible
ERROR:HDLCompiler:432 - "I:\xilinx\Deficit-Round_Rrobbin\packet_size.vhd" Line 53: Formal <arg> has no actual or default value.
ERROR:HDLCompiler:541 - "I:\xilinx\Deficit-Round_Rrobbin\packet_size.vhd" Line 53: Type integer is not an array type and cannot be indexed.
ERROR:HDLCompiler:854 - "I:\xilinx\Deficit-Round_Rrobbin\packet_size.vhd" Line 45: Unit <behavioral> ignored due to previous errors.
You are using both std_logic_arith and numeric_std. You only need to use numeric_std, which is what the first error is about (as a general rule, try to solve the first error produced, before looking at subsequent errors). Having fixed this, you have another error, which is the declaration of variables in the architecture declarative region; variables cannot be declared here.
With these issues resolved, your code at least compiles:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity packet_size is
generic (
fifo_MaxDepth : integer range 0 to 256 := 16
);
port (
fifo_tlast : in std_logic_vector(fifo_MaxDepth -1 downto 0);
depth : in std_logic_vector(fifo_MaxDepth -1 downto 0);
rd_ptr, wr_ptr: in integer range 0 to fifo_MaxDepth - 1;
pckt_size : out integer range 0 to fifo_MaxDepth
);
end packet_size;
architecture Behavioral of packet_size is
signal temp : integer range 0 to 256 := 0;
signal finish_flag : bit := '0';
signal PacketSize_temp : integer range 0 to fifo_MaxDepth;
begin
process (fifo_tlast, rd_ptr, wr_ptr) is
begin
temp <= to_integer(unsigned(depth));
for i in rd_ptr to temp loop
if (finish_flag = '0') then
PacketSize_temp <= PacketSize_temp + 1;
if (fifo_tlast(i) = '1') then
finish_flag <= '1';
end if;
end if;
end loop;
end process;
end Behavioral;
I also added spaces in your assignments, and in general, to improve the readability.

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

Use a generic to determine (de)mux size in VHDL?

I want to use a generic 'p' to define how many outputs a demux will have. Input and all outputs are 1 bit. The outputs, control, and input can be something simple like:
signal control : std_logic_vector(log 2 p downto 0); -- I can use a generic for the log2..
signal input : std_logic;
signal outputs : std_logic_vector(p-1 downto 0);
But what would the mux implementation code be? Is it even possible?
No generics required:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity demux is
port(
control : in unsigned;
input : in std_logic;
outputs : out std_logic_vector
);
end entity demux;
architecture rtl of demux is
-- Check size of input vectors
assert 2**control'length = outputs'length
report "outputs length must be 2**control length"
severity failure;
-- actually do the demuxing - this will cause feedback latches to be inferred
outputs(to_integer(unsigned(control)) <= input;
end architecture;
(Untested, just typed in off the top of my head...)
This will infer latches though - is that what you want?
You need to feed log_p as generic and compute p as you go.
library ieee;
use ieee.std_logic_1164.all;
entity demux is
generic (
log_p: integer);
port(
control : in std_logic_vector(log_p downto 0);
input :in std_logic;
outputs : out std_logic_vector(2**log_p - 1 downto 0)
);
end entity demux;
You need to pass both the number of outputs and the size of the control array as generics, unless you are always using powers of two.
Outside of your (de)mux module (ie: when you instantiate), you can use code to calculate the number of bits for the control bus. I have a function in a common package I use to initialize various configuration constants and generics that get passed to code similar to your (de)mux application:
-- Calculate the number of bits required to represent a given value
function NumBits(val : integer) return integer is
variable result : integer;
begin
if val=0 then
result := 0;
else
result := natural(ceil(log2(real(val))));
end if;
return result;
end;
...which allows you to do things like:
constant NumOut : integer := 17;
signal CtrlBus : std_logic_vector(NumBits(NumOut)-1 downto 0);
my_mux : demux
generic map (
NumOut => NumOut,
NumCtrl => NumBits(NumOut) )
port map (
control => CtrlBus,
...
...

Resources