I keep forgetting and its difficult to search for the answer in a textbook or the Internet.
Well, <= is assignment.
signal <= A or B;
=> is syntax used for case statements like so:
(Stolen from http://www.cs.umbc.edu/portal/help/VHDL/sequential.html)
case my_val is
when 1 => -- This is kind of like how the : operator is used for switch in many languages
a:=b;
when 3 =>
c:=d;
do_it;
when others =>
null; -- do nothing
end case;
end case;
=> can also be used in array assignments
myVector <= (1=>'1', OTHERS=>'0'); -- assigns ('0','1','0','0') to "myVector"
Source: http://www.eda.org/comp.lang.vhdl/html3/gloss_example.html
A means to memorize when to use => and when to use <= is to think as follow.
<= as an assignment for signal as target (for variable it is :=).
Examples:
y <= a + b + c; --y is a signal
v := a + b +c; --v is a variable
=> as mapping.
Example for component explicit mapping (recommended style IMHO):
my_instance : my_component
port map(
port1 => my_signal1
);
Example for function explicit mapping (useful when parameters are not trivial):
my_signal <= my_function(parameter1 => something1, parameter2 => something2);
Example for array explicit mapping
type array_type is array(0 to 1) of std_logic_vector(7 downto 0);
constant my_array : array_type := (0 => x"AB", 1 => x"CD");
Example for record explicit mapping
type record_type is record
a : natural;
b : std_logic_vector(2 downto 0);
end record;
constant my_record: record_type := (a => 0, b => "101");
The advantage is this style allows you to do the mapping in the order of your choice (not necessarily the order in the definition of the component/function...). Moreover in the particular case of array with only one item, it is required.
Finally, with the =>, the keyword others allows to map all the remaining stuff that hasn't already mapped.
Example to assign array:
type array_type is array(0 to 5) of std_logic_vector(7 downto 0);
constant my_array : array_type := (0 => x"AB", 1 => x"CD", others => (others => '0'));
<= represents the assignment operator while => is used in the case statement, for example:
case sel is
when "01" => line <= "1";
when others => line <= "0";
end case
sets line to "1" in case sel is "01" and to "0" otherwise.
=> is also used in structural code in port maps.
The operator <= is known as a
signal assignment operator to highlight its true purpose. The signal assignment operator specifies a relationship between signals. In other words, the signal on the left side of the signal assignment operator is dependent upon the signals on the right side of the operator.
(Source: Digital_Mclogic_Design by Bryan Mealy, Section: The Signal Assignment Operator: “<=”, page 339)
I couldn't find anything specific on the => operator.
Related
In the VHDL language a common way to init a memory is:
type mem0_type (0 to MEM0_SIZE-1) of std_logic_vector(DATA_WIDTH-1 downto 0);
signal mem0 : mem0_type;
For ease of use later in a memory and register adressnig table, I am considering:
type mem0_type (MEM0_ADDR to MEM0_ADDR+MEM0_SIZE-1) of std_logic_vector(DATA_WIDTH-1 downto 0);
signal mem0 : mem0_type;
To be able to do something like this:
case switch is
when mem0'range => mem0(switch) <= data;
when mem1'range => mem1(switch) <= data;
when mem2'range => mem2(switch) <= data;
when mem3'range => mem3(switch) <= data;
when REG0_ADDR => reg0 <= data;
when REG1_ADDR => reg1 <= data;
when REG2_ADDR => reg2 <= data;
...
end case;
Instead of something like:
case switch is
when MEM0ADDR to MEM0ADDR+MEM0_SIZE-1 => mem0(switch-MEM0ADDR) <= data;
when MEM1ADDR to MEM1ADDR+MEM1_SIZE-1 => mem1(switch-MEM1ADDR) <= data;
when MEM2ADDR to MEM2ADDR+MEM2_SIZE-1 => mem2(switch-MEM2ADDR) <= data;
when REG0_ADDR => reg0 <= data;
when REG1_ADDR => reg1 <= data;
when REG2_ADDR => reg2 <= data;
...
end case;
Is there any downside of using a none zero index as the start adress if my synthesis tool allows it?
Thank you for taking the time, I'd love to see more HDL activity on stack <3
You can do as suggested, but - since synthesis rules are not strictly standarised - I wouldn't bet on each and every synthesis tool to reliably detect and infer memory from your construct.
This appears to be a perfect use case for an alternative construct using an alias:
entity mem is
generic
(
MEM_SIZE : natural;
DATA_WIDTH : natural;
START_ADDRESS : unsigned(31 downto 0)
);
port
(
...
);
end entity mem;
architecture alias_architecture of mem is
type mem_type is array (natural range <>) of std_ulogic_vector(DATA_WIDTH - 1 downto 0);
signal mem : mem_type(0 to MEM_SIZE - 1);
alias amem : mem_type(to_integer(START_ADDRESS) to to_integer(START_ADDRESS) + MEM_SIZE - 1) is mem;
begin
...
This way you still have the luxury of convenient addressing with the only place you need to deal with the offset is the alias definition. It probably does not guarantee every tool available will be able to guess what you meant but I'd assume it will at least increase the likelyhood.
[P.S.: tried that out of curiosity in Quartus II and unfortunately, it appears it can't be bothered to infer RAM blocks through the aliased array. YMMV with other synthesis tools.]
Is there a data type in VHDL that is an array like a "std_logic_vector", but instead of having all having 9 possible states:
'U': uninitialized. This signal hasn't been set yet.
'X': unknown. Impossible to determine this value/result.
'0': logic 0
'1': logic 1
'Z': High Impedance
'W': Weak signal, can't tell if it should be 0 or 1.
'L': Weak signal that should probably go to 0
'H': Weak signal that should probably go to 1
'-': Don't care.
has only two possible states:
'0': logic 0
'1': logic 1
The reason why I ask this is because i'm looking for the VHDL equivalent of the verilog case statement. Verilog Example:
module m1(input a, input b, output reg[7:0] q);
wire [1:0] sel = {a, b};
always #* begin
case(sel)
2'b00: q = 8'd1;
2'b01: q = 8'd2;
2'b10: q = 8'd3;
2'b11: q = 8'd4;
endcase
end
endmodule
In VHDL, I can do this with no problems:
entity m1 is
port(
a :in std_logic;
b :in std_logic;
q :out std_logic_vector(7 downto 0)
);
end entity;
architecture rtl of m1 is
signal sel :std_logic_vector(1 downto 0);
begin
sel <= a & b;
process(sel)
begin
case sel is
when "00" => q <= 1;
when "01" => q <= 2;
when "10" => q <= 3;
when "11" => q <= 4;
end case;
end process;
end architecture;
The problem with this is that both Xilinx ISE and Modelsim refuse to compile this code saying that I didn't cover the states for 'X', 'U', 'L', 'H', etc...
so i need to add a "when others => q <= 'X';" statement to my VHDL....
Then, when I compile the code with Vivado, it says, "WARNING: you have a default case eventhough your full case was covered." so then I delete the "when others=>" clause of the case...
Well, this is just annoying... is there a way to get it to work in every tool without generating either an ERROR message or a bogus warning message?
My idea was to just use an array type that can be only "0" or "1" like an integer... but instead more like std_logic_vector without supporting all the other logic states that mess up the case select and require the "when others =>" clause....
possible? its there a VHDL data type like this already built in? an array of only '0' or '1' and nothing else specifically for catatentating together and being used as a case selection? integer types don't have 'U' or 'X', but are perfectly ok to use in a VHDL case... i'm wondering if the same holds for an array type of ('0', '1')?
You should stick with std_logic and std_logic_vector, an other post is presenting the differences: When to use STD_LOGIC over BIT in VHDL
I think your problem comes (also) from the fact that you are putting an integer into a std_logic_vector. You should use the conversion functions:
to_unsigned(arg: natural, size: natural) return unsigned
std_logic_vector(arg: signed or unsigned) return std_logic_vector
Which leads you to:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all; --DO NOT FORGET THIS LIBRARY TO USE THE CONVERSION FUNCTION
entity m1 is
port(
a :in std_logic;
b :in std_logic;
q :out std_logic_vector(7 downto 0)
);
end entity;
architecture rtl of m1 is
signal sel :std_logic_vector(1 downto 0);
begin
sel <= a & b;
process(sel)
begin
case sel is
when "00" => q <= std_logic_vector(to_unsigned(1,q'length));
when "01" => q <= std_logic_vector(to_unsigned(2,q'length));
when "10" => q <= std_logic_vector(to_unsigned(3,q'length));
when "11" => q <= std_logic_vector(to_unsigned(4,q'length));
when others => q <= std_logic_vector(to_unsigned(1,q'length));
end case;
end process;
end architecture;
Try VHDL Predefined Types from the package standard:
type bit is ('0', '1');
type bit_vector is array (natural range <>) of bit;
funciton to_stdlogicvector (b :bit_vector) return std_logic_vector;
function to_bitvector (s :std_ulogic_vector) return bit_vector;
architecture rtl of m1 is
signal sel :std_logic_vector(1 downto 0);
signal bv :bit_vector(1 downto 0);
begin
sel <= a & b;
bv <= to_bitvector(sel);
process(bv)
begin
case bv is
when "00" => q <= 1;
when "01" => q <= 2;
when "10" => q <= 3;
when "11" => q <= 4;
end case;
end process;
end architecture;
I am designing a simple LFSR with a variable polynomial for a randomizer. The lfsr length is being defined as a generic. I need to initialize the starting value constant as something other than zeros/ones. I've found the answer to this before, but I can't seem to find the answer again. Here is what I'm trying to do:
entity GaloisLfsr is
generic
(
g_LFSR_LENGTH : integer := 5
);
...
end entity GaloisLfsr;
architecture zGaloisLfsr of GaloisLfsr is
constant c_INITIAL : std_logic_vector((g_LFSR_LENGTH - 1) downto 0) := ((others => '0'), '1');
What is the proper syntax for defining a constant with varying size to something that a pure '(others => '0')' can't capture?
Assuming one would like to initialize the 5-bit constant c_INITIAL to "00001", then the declaration of the constant would be:
constant c_INITIAL : std_logic_vector((g_LFSR_LENGTH - 1) downto 1) := ((others => '0'), 0 => '1');
You may convert natural/integer to vector
use IEEE.NUMERIC_STD.ALL;
...
constant c_INITIAL : std_logic_vector((g_LFSR_LENGTH - 1) downto 0) := std_logic_vector(to_unsigned(g_polynomial , g_LFSR_LENGTH));
I am having some trouble using aggregates in my VHDL test bench (short hand shown below).
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all
entity TB is
end entity;
architecture RTL of TB is
-- constant(s)
constant CLK_PERIOD : time := 10 ns; -- 100 MHz
-- signal(s)
signal CLK : std_logic := '0';
signal nRST : std_logic := '1';
signal CONFIG_REG : std_logic_vector(7 downto 0) := (others => '0');
begin
-- clock driver
CLK <= NOT CLK after (CLK_PERIOD / 2.0);
-- main process
process
begin
-- reset driver...
nRST <=
'1',
'0' after (CLK_PERIOD * 1);
-- set initial configuration...
CONFIG_REG <= (
6 => '1',
3 downto 2 => "01",
7 | 0 => '1',
others => '0'
);
-- do test-bench stuff...
-- update configuration...
CONFIG_REG <= (
6 => '0',
3 downto 2 => "10",
7 | 0 => '1',
others => '0'
);
-- do more test-bench stuff...
end process;
end architecture;
I really want to 'name' the parts of the configuration register so that it actually reads well.
So I want to say:
Bit[6] = ENABLE
Bit[3:2] = MODE
Bit[7|0] = READY_DONE
I know that I can use a constant for the 6:
constant ENABLE : integer := 6;
and then my code looks like this:
CONFIG_REG <= (
ENABLE => '1',
3 downto 2 => "01",
7 | 0 => '1',
others => '0'
);
But I've been stumped to try and get the range 3 downto 2 and the 7|0 named so that the code looks like:
CONFIG_REG <= (
ENABLE => '1',
MODE => "01",
READY_DONE => '1',
others => '0'
);
I thought I might be able to accomplish this using aliasing and I've been looking at the VHDL Golden Reference Guide (p.15) which has been pretty helpful as far as understanding aliasing and ranges go, but I still cannot figure out how to name a range itself or an 'or'(|) of values.
Currently I have the below 'hack', which I'm not really fond of...
constant ENABLE : integer := 6;
alias MODE is CONFIG_REG(3 downto 2);
-- what to do about the OR though???
CONFIG_REG <= (
ENABLE => '1',
MODE'RANGE => "01",
7 | 0 => '1',
others => '0'
);
I really want to make my test-bench readable so that when I look at it 6 mo. from now, I'll know what it's doing without having to go and figure out "Now what was bit[6] again???" or in the event I have to hand off my code to another developer, they can easily get an idea of what I was trying to accomplish.
Any help / advice would be appreciated on how to do this.
Thanks for reading.
EDIT: Fixed the 7 | 0 to be valid:
Invalid:
7 | 0 => "10",
Valid:
7 | 0 => '1',
Beware, your code is not valid: the aggregate notation 7 | 0 stands for groups of indices, not vectors. It should be associated std_logic values, not std_logic_vector. Moreover, in VHDL versions prior 2008, the aggregate notation 3 downto 2 should also be associated std_logic values:
-- set initial configuration...
CONFIG_REG <= (
6 => '1',
3 downto 2 => '1',
7 | 0 => '0',
others => '0'
);
In VHDL 2008 the association between choices that are discrete ranges and expressions of the type of the aggregate are now supported. So, the 3 downto 2 => "01" is OK in VHDL 2008. But as VHDL 2008 is still not fully supported by many synthesizers, you should probably be careful, unless this code is not supposed to be synthesized, of course.
Anyway, using records instead of vectors could be an option for your problem. And in case you also need a vector version of the data, you could very easily write conversion functions between vector and record types. Example:
package foo is
type config_type is record
ready: std_ulogic;
enable: std_ulogic;
foobar: std_ulogic_vector(1 downto 0);
mode: std_ulogic_vector(1 downto 0);
reserved: std_ulogic;
done: std_ulogic;
end record;
function rec2vec(v: config_type) return std_ulogic_vector;
function vec2rec(v: std_ulogic_vector) return config_type;
end package foo;
package body foo is
function rec2vec(v: config_type) return std_ulogic_vector is
begin
return v.ready & v.enable & v.foobar & v.mode & v.reserved & v.done;
end function rec2vec;
function vec2rec(v: std_ulogic_vector) return config_type is
constant vv: std_ulogic_vector(7 downto 0) := v;
begin
return (ready => vv(7), enable => vv(6), foobar => vv(5 downto 4),
mode => vv(3 downto 2), reserved => vv(1), done => vv(0));
end function vec2rec;
end package body foo;
You could then use the aggregate notation to assign records:
signal config_reg: config_type;
...
config_reg <= (
ready => '1',
enable => '1',
foobar => "--",
mode => "01",
others => '0'
);
And convert to-from vectors:
signal config_reg_v: std_ulogic_vector(7 downto 0);
...
config_reg_v <= rec2vec(config_reg);
...
config_reg <= vec2rec(config_reg_v);
...
config_reg <= vec2rec(X"ff");
Note: I used std_ulogic and std_ulogic_vector instead of the resolved std_logic and std_logic_vector. There are good reasons for that but it is another question.
I prefer to define full width constants in my package:
subtype ConfigRegType is std_logic_vector(7 downto 0) ;
constant CFG_ENABLE : ConfigRegType := B"0_1_000000" ;
constant CFG_MODE0 : ConfigRegType := B"0000_00_00" ;
constant CFG_MODE1 : ConfigRegType := B"0000_00_00" ;
constant CFG_MODE2 : ConfigRegType := B"0000_10_00" ;
constant CFG_MODE3 : ConfigRegType := B"0000_11_00" ;
constant CFG_READY : ConfigRegType := B"1_0000000" ;
constant CFG_DONE : ConfigRegType := B"0000000_1" ;
. . .
Now when you are ready to write to it, simply "or" the value set you want:
CONFIG_REG <= CFG_ENABLE or CFG_MODE1 or CFG_READY or CFG_DONE ;
I have played with other ways, however, like you are noting they seem to require knowledge of details of the implementation.
I'm a student learning VHDL and the example code from my textbook shows lines similar to the following in several places;
when "000" => tmp_result <= a and b;
when "001" => tmp_result <= a or b;
...
when others => tmp_result <= (others => '0');
I find the syntax of VHDL very unintuitive overall, but I really don't "get" this line at all.
I'm really confused why the above line isn't just:
when others => tmp_result <= '0'
Why is it like that?
I've tried Googling but haven't been able to find an explanation.
STD_LOGIC_VECTOR has a fixed size. So, when you are assigning a value to it, instead of defining each bit explicitly, you can just use
(others => '0')
to denote you want the remaining bits to be set to 0. Since the variable has a fixed size, your compiler will know how many bits to set. You could mix this with a bunch of other statements, e.g.
tmp_result <= (1=>'1', OTHERS => '0');
A circumstance where it could come in handy is this:
ENTITY test IS
GENERIC (n : INTEGER := 7);
PORT (a : OUT STD_LOGIC_VECTOR (n DOWNTO 0)
);
END test;
You see, we may have to change the size each time and that's why we are defining a generic variable. Using (others => '0') to set it to 0 will save us from having to change the whole program all over again.
This is because tmp_result is defined as std_logic_vector (instead of simply std_logic).
tmp_result <= '0'; -- tmp_result is std_logic (single-quotes)
tmp_result <= "0000000"; -- tmp_result is std_logic_vector (double quotes)
tmp_result <= (others => '0'); -- same as previous line, but does not need to know length of tmp_result
When assigning all the bits of a std_logic_vector to the same value ('0', in this case), it is common practice to use the syntax (others => '0'), which basically translate to "give me a std_logic_vector the same length as tmp_result filled with '0'". This is better because the line is still valid when the length of tmp_result changes, such as if its length depends on a generic.