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.
Related
I would have just put a comment in the sourced post below but I don't have that privilege yet so I thought I might just ask a question so that I can get some clarification.
how to delay a signal for several cycles in vhdl
Basically I need to implement 2 clock cycle delay to this process located in the behavioral of my VHDL project (the code for which is shown below):
process(font_address(0), font_address(1), font_address(2), font_address(3),font_address(4), font_address(5), font_address(6), font_address(7),vga_hcount(0), vga_hcount(1),vga_hcount(2),CLK)
begin
--if (CLK'event and CLK = '1') then
-- a_store <= a_store(1 downto 0) & a;
-- a_out <= a_store(1 downto 0);
--end if;
if (CLK'event and CLK = '1') then
case vga_hcount(2 downto 0) is
when "000" => font_bit <= font_data(7);
when "001" => font_bit <= font_data(6);
when "010" => font_bit <= font_data(5);
when "011" => font_bit <= font_data(4);
when "100" => font_bit <= font_data(3);
when "101" => font_bit <= font_data(2);
when "110" => font_bit <= font_data(1);
when "111" => font_bit <= font_data(0);
when others => font_bit <= font_data(0);
end case;
end if;
end process;
As you can see I have made it such that it takes a single clock cycle delay before the signal assignments in the process are made as provided by the if statement wrapped around the signal assignments but I cannot seem to create a synthesize-able 2 clock pulse delay despite reading the answered question linked above
When I comment the if statement wrapped around the case and uncomment the following block of code
if (CLK'event and CLK = '1') then
a_store <= a_store(1 downto 0) & a;
a_out <= a_store(1 downto 0);
end if;
Which was taken from the link given at the beginning of this question I get the following error:
[Synth 8-690] width mismatch in assignment; target has 2 bits, source has 3 bits ["U:/Computer organisation lab/vga/vga_prac.vhd":304]
the target being referred to in this error message is the a_store vector and the source is the concatenation of a_store and a.
This is after I assigned logic 1 to a and created a_store and a_out as std_logic_vectors with 2 elements (as I want a delay of two clock cycles). I think the reason I am getting this error is because even after reading over this question for hours I still can't seem to understand how it actually is supposed to generate a 2 clock cycle delay.
I thought at first it might be that a 1 bit gets iterated through the a_store vector until the MSB is one and then this vector is applied to a_out but looking at the fact that it is in all in an if statement I cannot see how these two lines of code would even execute more than once. If this were even true I would have to have some test to make sure that a_out has a 1 in its MSB.
Usually I would have moved on but after extensive searching I couldn't find a simpler solution than this despite the fact I don't fully understand how it is supposed to work.
If somebody could clarify this or suggest a modification to my program which will generate the required delay that would be great.
Thanks in advance,
Simon.
First off, the first code is not that efficient, and could be reduced to
use ieee.numeric_std.all;
[...]
process(CLK)
begin
if rising_edge(CLK) then
font_bit <= font_data(7 - to_integer(unsigned(vga_hcount(2 downto 0))));
end if;
end process;
For the second part, the error says everything. You say a_store has 2 bits (or "elements" as you call it), then you can imagine that a_store(1 downto 0) & a is two bits of a_store + 1 bit of a = 3 bits. You cannot assign 3 bits to 2 bits. How would that fit? Same problem for assigning a_out: How can 2 bits fit into 1 bit?
Thus:
if (CLK'event and CLK = '1') then
a_store <= a_store(0) & a;
a_out <= a_store(1);
end if;
For the sake of consistency and ease of maintenance, I would like to make some constants using sequential statements, e.g. in process.
I have defined a range using:
subtype FIELD is natural range 3 downto 0;
A process that makes the value could then look like:
process is
begin
reg <= (others => '0');
reg(FIELD) <= (others => '1');
wait; -- Error in Xilinx ISE
end process;
However, the wait is not accepted by Xilinx ISE synthesis tool.
One way is of course to use a non-used signal in a process list, like a clock, but that is a kind of ugly.
The concurrent style would be like:
reg <= (FIELD => (others => '1'), others => '0');
But FIELD can't be used like that in VHDL.
Is there a way to make constants using sequential statements, but where the wait is not required in a process?
You could use a function to do this. Note, I don't do any error checking on the range, but isn't difficult to do.
-- subtypes
subtype FIELD is natural range 3 downto 0;
-- functions
function test_func(a: std_logic_vector) return std_logic_vector is
variable result : std_logic_vector(a'left downto a'right) := a;
begin
result(FIELD) := (others => '1');
return result;
end function;
-- constants
constant ALL_ZEROS : std_logic_vector(7 downto 0) := (others => '0');
-- signals
signal reg : std_logic_vector(7 downto 0) := test_func(ALL_ZEROS);
This might be a stupid question, but I'd like to insert a 8 bit vector into a 16 bit vector before shifting it out.
I currently have this:
data <= "000" & DATA_IN & "00000";
Which works perfectly, but I want to be able to select the place where the data is placed with generics (or maybe in the future dynamically).
I tried:
data <= ((15 - (start_from_output-1)) DOWNTO (15 - (start_from_output-1) - (channels_in_use-1)) => DATA_IN , OTHERS => '0');
but this gives the error:
ERROR:HDLCompiler:1728 - "E:/Projects/VHDL/PHASED_ARRAY_0-4/switch.vhd" Line 69: Type error near data_in ; current type std_logic_vector; expected type std_ulogic
If I simplify it to
data <= (7 DOWNTO 0 => DATA_IN, others => '0');
the same error occurs.
Does someone have any suggestions how to solve this?
You can do an assignment like:
data <= (OTHERS => '0');
data((15 - (val-1)) DOWNTO (15 - (val-1) - (val2-1)) <= data_in;
If I understand you correctly it will do the same job, but it will work only inside a process. Outside the process you'll get multiple driver error.
I tried to implement and addition of two signed numbers. The first one is 32 bit and the second one is also 32 bit, but correspond the addition of the earlier operation. The code VHLD is below :
Entity Sum_Position is
port
(
Clk: in std_logic;
Reset: in std_logic;
Raz_position: in std_logic;
Position_In: in std_logic_vector(31 downto 0);
Position_Out: out std_logic_vector(31 downto 0)
);
end Sum_Position;
Architecture Arch_position of sum_Position is
-- create locale signals
signal position_before: signed (31 downto 0):= (OTHERS => '0');
-- both signals have one more bit than the original
signal Position_s : SIGNED(Position_In'length downto 0):= (OTHERS => '0');
signal Position_Before_s : SIGNED(Position_In'length downto 0):= (OTHERS => '0');
signal Sum_Pos_s : SIGNED(Position_In'length downto 0):= (OTHERS => '0');
Begin -- begin of architecture
-- convert type and perform a sign-extension
Position_s <=SIGNED(Position_In(31) & Position_In);
Position_Before_s<=resize(signed(position_before), Position_Before_s'length);
Sum_of_position: process(Clk, Reset)
begin
IF (Reset='0') THEN -- when reset is selected
-- initialize all values
Sum_Pos_s<= (OTHERS => '0');
ELSIF (Clk'event and Clk = '1') then
-- addition of two 33 bit values
Sum_Pos_s <= Position_s + Position_Before_s;
END IF;
end process Sum_of_position;
-- resize to require size and type conversion
position_before <= (OTHERS => '0') WHEN Raz_position='1' else
signed(resize(Sum_Pos_s, position_before'length));
-- Resize and output the result
Position_Out <= (OTHERS => '0') WHEN Raz_position='1' else
std_logic_vector(resize(Sum_Pos_s, Position_Out'length));
end Arch_position;
But, i have overflow because the result is very strange. Can you please suggest me a solution?
Best regards;
First of all your code is quite unclear.
Secondly, there is no reason for position_before(_s) to be asynchronous, it should be clocked, e.g. (summarized):
begin
IF (Reset='0') THEN -- when reset is selected
-- initialize all values
Sum_Pos_s<= (OTHERS => '0');
ELSIF (Clk'event and Clk = '1') then
Position_Before_s <= Sum_Pos_s
Sum_Pos_s <= Position_s + Position_Before_s;
END IF;
end process Sum_of_position;
Thirdly, the answer to your question. You pass floats to your VHDL engine. Interprete them as signed and add them. You should look at IEEE754 floats. There is a fixed field for the sign bit, one for the exponent and one for the mantissa. You can't just add everything up.
Step 1 is to express both on the same exponent basis. Then add the adjusted mantissas and keep the exponent. Then rescale the mantissa for the most significant bit to correspond to 0.5.
What you to is the following:
0.4 + 40 = (0.1) * 4 + (10) * 4
mantissas are both 4
exponents are -1 and 1. without fields overflowing, your result becomes an exponent of 0 and a mantissa of 8, so 8.
Most modern VHDL tools have Integer types (signed and unsigned).
These are usually 32 bits wide unless you use the Range modifier.
I suggest you consider using integers rather than std_logic_vector.
You can convert between types like casts in C.
This is my favourite diagram on casting/ converting VHDL types. I have printed it out and put it on my wall http://www.bitweenie.com/listings/vhdl-type-conversion
A page in integers in VHDL http://vhdl.renerta.com/mobile/source/vhd00039.htm
Given a bit number, I am trying to set that bit in a std_logic_vector. This is for toggling various clock outputs one at a time.
First of all, I've completely given up on sll, or SHIFT_LEFT which seems to be the obvious way to do it, but which totally doesn't work at all.
variable v_cmd_clk_1: std_logic_vector(11 downto 0);
...
--- set bit number "s_proc_chan", plus 4, in v_cmd_clk_1
v_cmd_clk_1 := "0000" & "0000" & "0000";
v_cmd_clk_1( to_integer ( unsigned(s_proc_chan(2 downto 0))) + 4 ) := '1';
...
-- And then later on in the process assign it to an actual signal
cmd_clk <= v_cmd_clk_0;
Is there a better or cleaner syntax for doing this?
Thanks.
Three suggestions for you. First one uses aggregates:
v_cmd_clk_1 <= (to_integer(unsigned(s_proc_chan(2 downto 0)))+4) => '1', others => '0');
Second one uses integer to unsigned conversion:
v_cmd_clk_1 <= std_logic_vector(to_unsigned(2**(to_integer(unsigned(s_proc_chan(2 downto 0)))+4)); -- No guarantee on parentheses matching
Third one, using shift_left:
v_cmd_clk_1 <= std_logic_vector(shift_left(resize(unsigned'("1"), v_cmd_clk_1'length), to_integer(unsigned(s_proc_chan(2 downto 0)))+4));
The principle of setting a single bit given by index, as you already done, is fine, and it shows the intention of the code, which is setting a bit given by an index.
It would be possible to eliminate the + 4 offset through use of other std_logic_vector ranges, but a decent synthesis tool eliminates the offset, so an add operation is not implemented.
Anyhow, as answer to the comment, the + 4 can be eliminated if a std_logic_vector is addressed directly into 0 to 7, instead of addressing 4 to 11, and the last 4 '0's can just be postpended, like:
variable v_cmd_clk_1 : std_logic_vector(11 downto 0);
variable v_cmd_clk_upper: std_logic_vector( 7 downto 0);
...
v_cmd_clk_upper := (others => '0');
v_cmd_clk_upper(to_integer(unsigned(s_proc_chan(2 downto 0)))) := '1';
v_cmd_clk_1 := v_cmd_clk_upper & "0000";
The aggregate suggested by Jonathan Drolet looks nice, but for example Altera Quartus II won't allow this for synthesis, since it requires constant choice values in aggregates. Using shift or 2** will synthesize.
Note that initial clearing is more general with:
v_cmd_clk_1 := (others => '0');