Type enumeration in VHDL - vhdl

What is the type enumeration in the VHDL?
where can I use it, to make the code shorter and more understandable?
for example, consider a bellow statement:
TYPE st_State IS (st_Idle, st_CheckHeader1, st_CheckHeader2, st_ReceiveData)
when must to use it.

Your example is only a declaration of a type with name st_State and this type contains four elements. Each element gets a number from 0 to Elements - 1. This is similar to a C typedef with an C enum.
Please check this explanation for more detailed information.
A typical application for this is a state machine to name the different states:
architecture Top_Arch of Top is
type State_Type is (S0, S1, S2, S3);
signal CurrentState : State_Type := S0;
begin
process(Clock)
begin
if(rising_edge(Clock)) then
case CurrentState is
when S0 => ...
when S1 => ...
when S2 => ...
when S3 => ...
end case;
end if;
end Top_Arch;
Using this method result in a more readable and cleaner code, but it is equivalent to this approach (untested):
architecture Top_Arch of Top is
signal CurrentState : INTEGER RANGE 0 to 3 := 0;
begin
process(Clock)
begin
if(rising_edge(Clock)) then
case CurrentState is
when 0 => ...
when 1 => ...
when 2 => ...
when 3 => ...
end case;
end if;
end Top_Arch;
NOTE: Check the range statement. You have to use it, because you have to declare each value for your state machine. So you have to use when others or reduce the integer to 2 bits only. Otherwise you have to declare 2^32 - 1 states.
So you need at least a type declaration with type <YourType> is ... to declare your custom type and a signal to use your type (CurrentState in the above example).

Enumerated types have many other uses than just states in state machines.
You can use them as index types in arrays, loop variables, etc. For example,
type channel is (R,G,B);
Colour : array(channel) of byte;
constant Black : Colour := (R => 0, G => 0, B => 0);
signal VGA_Out : Colour;
-- in a process
for c in channel loop
VGA_Out(c) <= A(c) + B(c); -- mix video signals A and B
end loop;
and so on

Related

In the below vhdl code though i have specified the range of variable it is counting endlessly. How to over come this problem

the temp variable is storing data out of its range. The range is used to store the maximum final value but it is holding the previous value and goes on incrementing. The functionality of for loop which is condition based is not satisfingenter image description here
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity counter is
Port (clk,rst:in std_logic;
o:out integer range 0 to 15
);
end counter;
architecture Behavioral of counter is
signal temp2:integer range 1 to 15:=0;
begin
process(clk) is
begin
if rising_edge(clk) then
if rst='1' then
temp2<=0;
else
for i in 1 to 15
loop
temp2<=temp2+1;
end loop;
end if;
end if;
end process;
o<=temp2;
end Behavioral;
Range puts a constraint on an object (here the signal temp2) that says it is illegal, and hence, fail if this object receives a value that is outside of the range.
Your code then must take the actions (such as mod) to make this so.
Since your code assigns the value 0, I am assuming that you need to update your declaration as follows:
signal temp : integer range 0 to 15 ;
. . .
temp2<= (temp2+1) mod 16;

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

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;

How to use a 'case' in VHDL blocks

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;

Converting VHDL logic vectors to user-defined strings for simulation

I'm using active-hdl to simulate my FPGA designs and I'd like to know if it's possible to use dynamically generated strings to represent my signals in the simulator. For example, let's say I have a 4-bit std_logic_vector containing an op-code, I'd like the simulator to display the op-code strings "nop", "add", "sub" etc instead of the vector value.
I tried declaring a custom enumeration type at first but quickly discovered that you don't get to choose the values of the individual elements. My next solution was to use the enumeration for simulation display only and convert with a translation function:
type op_code_type is (nop, add, sub, unknown); -- not in order
signal op_code_str: op_code_type;
signal op_code: std_logic_vector(3 downto 0);
function to_string(op_code : std_logic_vector(3 downto 0))
return op_code_type is
begin
case op_code is
when "0000" => return nop;
when "0010" => return add;
when "0011" => return sub;
when others => return unknown;
end case;
end to_string;
begin
----- testbench -----
process
begin
op_code <= "0000";
wait for 1ns;
op_code <= "0001";
wait for 1ns;
op_code <= "0010";
wait for 1ns;
op_code <= "0011";
wait for 1ns;
end process;
op_code_str <= to_string(op_code);
end architecture;
This actually works quite well, and is probably adequate for most things I want to do:
The main problem though is I'm stuck with string constants, so it'll be too impractical for more complex stuff like mov acc,x and all the many other variants a real-world design would have.
Are there ways to construct dynamic simulation identifiers like this? Or is it a fundamental limitation of HDLs?
In Modelsim, you can use virtual types and functions. For example, consider the following vector:
signal opcode : std_logic_vector(2 downto 0);
You can then at the Modelsim command line define a virtual type, such as:
virtual type {{0 nop} {1 load} {2 store} {3 invalid}} opcode_type
This is a type known only to the simulator. You can then create a virtual signal based on this type to convert the vector, such as:
virtual function {(opcode_type)opcode} opcode_str
Then wave opcode_str, and it will give you a custom formatted string..
I don't know if you can do the same with Active-HDL.
Now, as for doing it dynamically, the only possibility might be if the returned string is defined by a TCL function, such as:
# TCL code to read a file, or otherwise dynamically generate opcodes
# returning the appropriately formatted virtual type
proc generate_opcode_type {} {
...
}
virtual type [generate_opcode_type] opcode_type
virtual function {(opcode_type)opcode} opcode_str
Then wave opcode_str.
For posterity, and at the request of #B. Go, here is my previous answer:
#Paebbels has it. We use this frequently, especially when doing post place-and-route simulations to convert state codes to their equivalent enumerated type. So for completeness, I'll show you how we do it. The example below considers a case where binary encoding is used. If trying to convert from grey or one-hot, things are a bit different. For one-hot, I tend to use a function.
Consider an 3-bit vector with associated names:
|-----------|----------|
| 000 | Idle |
| 001 | Start |
| 010 | Running |
| 011 | Paused |
| 100 | Done |
| 101 - 111 | Invalid |
|-----------|----------|
So, if you have a signal, such as:
signal opcode : std_logic_vector(2 downto 0);
Then you want to convert to an enumerated type, which will show up cleanly in your waveform viewer. First, create the enumerated type and associated signal:
type opcode_names is (idle, start, running, paused, done, invalid);
signal opcode_name : opcode_names;
Then it is a simple with/select:
with to_integer(unsigned(opcode)) select
opcode_name <= idle when 0,
start when 1,
running when 2,
paused when 3,
done when 4,
invalid when others;
Though if you have a complete set, it is a bit simpler. Consider a 2-bit vector with names "idle, start, running, done".
type opcode_names is (idle, start, running, done);
signal opcode_name : opcode_names;
...
opcode_name <= opcode_names'image(to_integer(unsigned(opcode));
For more complex vectors with unusual, non-contiguous values, I typically use a function, such as:
signal opcode : std_logic_vector(31 downto 0);
type opcode_names is (idle, start, running1, running2, paused, done, invalid);
signal opcode_name : opcode_names;
function get_opcode_name(opcode : in std_logic_vector) return opcode_names is
variable ret : opcode_names;
begin
case to_integer(unsigned(opcode)) is
when 0 =>
ret := idle;
when 13 =>
ret := start;
when 87 =>
ret := running1;
when 131 =>
ret := running2;
when 761 =>
ret := paused;
when 3213 =>
ret := done;
when others =>
ret := invalid;
end case;
return ret;
end function get_opcode_name;
...
opcode_name <= get_opcode_name(opcode);

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

Resources