I am in the process of trying to write some code that will simply just shift a 32 bit vector left or right, with a 5 bit input that will be used for the shift amount (shamt). The issue I am having is trying to convert an std_logic_vector to an integer. My code is this:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x : in std_logic_vector(31 downto 0);
shamt : in std_logic_vector( 4 downto 0);
y : out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
signal shift : integer;
signal temp : std_logic_vector(31 downto 0);
begin
shift <= conv_integer(unsigned(shamt));
temp <= x(shift downto 0);
y <= temp;
end beh;
The code is not complete I know, but to test some ideas I am trying to pass "00010" (2) into shamt, but shift comes out to be -2147483648. But I cannot figure out why it is doing this, nor can I find any resources online that shows anything different than what I am doing. I greatly appreciate any help.
-2147483648 (-2**31) is the default initial value for integers, being the leftmost, most negative value in its range. It suggests that the signal assignment to shift has not executed. Most likely because it is a continuous assignment and there hasn't been an event on shamt to cause it to update.
std_logic_arith is not an IEEE standard library. You should use to_integer() from ieee.numeric_std instead. It is also beneficial to keep numeric ports as unsigned or signed so that your intent is clear and to minimize type conversions. Also, you cannot directly assign the variable length slice of x to temp since their lengths do not match. You should use resize() (from numeric_std) to extend the length back to 32-bits or rethink your approach.
I fixed the obvious typo in the entity name, started the simulation (ModelSim) and forced the signal shamt to "00010". Then just after trying to run for 1 ps, ModelSim complains about:
Fatal: (vsim-3420) Array lengths do not match. Left is 32 (31 downto 0). Right is 0 (-2147483648 downto 0 (null array)).
Time: 0 ps Iteration: 0 Process: /shiftlogical/line__16 File: shiftlogical.vhdl
Fatal error in Architecture beh at shiftlogical.vhdl line 16
That is because all your concurrent statements are executed in parallel. The new signal values are scheduled for the next delta cycle within the simulation. Thus, the line
temp <= x(shift downto 0);
is executed with the old value of shift which is the initial value of this signal. The initial value of an integer is -2**31 as also Kevin pointed out.
Of course you can initialize the signal shift, but the only value which will not result in an error will be 31 because in this asignment the signal on the left and the expression on the right must match in array (std_logic_vector) size. The signal shamt must be forced to "11111" as well, so that shift keeps 31.
You cannot easily fix this, because for a left shift you must add zeros at the right (LSB) and for a right shift zeros or the sign at the left (MSB).
#Martin Zabel what I had really tested there was to see if shift would hold an integer value which it did until I tried to pass it in for temp <= x(shift downto 0); What I realized was that the signal needed to really be a variable to work as intended and as follows my code consists of:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x: in std_logic_vector(31 downto 0);
shamt: in std_logic_vector(4 downto 0);
dir: in std_logic;
y: out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
begin
process(dir)
variable shift : integer;
begin
shift := conv_integer(unsigned(shamt));
if(dir = '0') then --Left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
elsif(dir = '1') then --Right shift
y(31-shift downto 0) <= x(31 downto shift);
y(31 downto 31-shift) <= (others => '0');
else --Always left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
end if;
end process;
end beh;
Related
I have such signal:
sw : std_logic_vector(7 downto 0);
and now I want to make another one, which will have it as upper bits, 1 the rest:
std_logic_vector(31 downto 0) := (7 downto 0 => sw, others => '1');
but it won't compile. any help please? I don't want to do it bit by bit.
I'm not entirely sure where should go this smaller signal, but you probably want to do this:
signal sw: std_logic_vector(7 downto 0);
signal big: std_logic_vector(31 downto 0);
big <= sw & x"FFFFFF";
This will assign sw vector to 8 most significant bits of big vector, and '1' to rest of bits. Write in comments, if you want to do something else.
What you are trying to do is assign a signal -which is variable- to another signal during initialization. What do you expect to happen?
I.e. at the moment you define a signal, you can only initialize it. If you want to assign something to the signal, you have to write a declaration.
definition -> initialization
declaration -> assignment
So in this case you can define big a larger range, and fix the constant bits in initialization
signal big : std_logic_vector(31 downto 0) => (others => '1');
And when you want to assign sw to any part of big, do that after the begin.
big(31 downto 24) <= sw;
or
big(7 downto 0) <= sw;
etc. The bits you initialized as '1' will be overwritten by the assignment.
I have a 32 bit barrel shifter using behavior architecture. Now I need to convert it to an n-bit shifter. The problem that I'm facing is that there is some kind of restriction to the for loop that I have to put a constant as sentinel value.
Following is my Code
library IEEE;
use IEEE.std_logic_1164.all;
Entity bshift is -- barrel shifter
port (left : in std_logic; -- '1' for left, '0' for right
logical : in std_logic; -- '1' for logical, '0' for arithmetic
shift : in std_logic_vector(4 downto 0); -- shift count
input : in std_logic_vector (31 downto 0);
output : out std_logic_vector (31 downto 0) );
end entity bshift;
architecture behavior of bshift is
function to_integer(sig : std_logic_vector) return integer is
variable num : integer := 0; -- descending sig as integer
begin
for i in sig'range loop
if sig(i)='1' then
num := num*2+1;
else
num := num*2;
end if;
end loop; -- i
return num;
end function to_integer;
begin -- behavior
shft32: process(left, logical, input, shift)
variable shft : integer;
variable out_right_arithmetic : std_logic_vector(31 downto 0);
variable out_right_logical : std_logic_vector(31 downto 0);
variable out_left_logical : std_logic_vector(31 downto 0);
begin
shft := to_integer(shift);
if logical = '0' then
out_right_arithmetic := (31 downto 32-shft => input(31)) &
input(31 downto shft);
output <= out_right_arithmetic after 250 ps;
else
if left = '1' then
out_left_logical := input(31-shft downto 0) &
(shft-1 downto 0 => '0');
output <= out_left_logical after 250 ps;
else
out_right_logical := (31 downto 32-shft => '0') &
input(31 downto shft);
output <= out_right_logical after 250 ps;
end if;
end if;
end process shft32;
end architecture behavior; -- of bshift
any help will be appreciated
Your code is not a barrel shifter implementation, because a barrel shift is a mux-tree.
If you have a 32 bit BarrelShifter module, you will need a 5 bit Shift input, wherein every bit position i enables a 2^i shift operation.
So for example shift = 5d -> 00101b enables a mux in stage 1 to shift for 1 bit and a mux in stage 3 to shift 4 bits. All other mux stages are set to pass through (shift(i) = 0).
I also would not advice to mix up basic shifting with shift modes (arithmetic, logic, rotate) and directions (left, right).
arithmetic and logic is only different in the shift-in value
shift right can be done by a conversion => shiftright = reverse(shiftleft(reverse(input), n)
An open source implementation can be found here:
https://github.com/VLSI-EDA/PoC/blob/master/src/arith/arith_shifter_barrel.vhdl
I try to write programm on vhdl in ise 14.4 for crc16 calculation but dont understand why get "parse error, unexpected FOR" in it. Tried to put it into process but it dont works too.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity crc16 is port(
clk : in STD_LOGIC:='0');
end crc16;
architecture Behavioral of crc16 is
signal data:std_logic_vector(15 downto 0):="1010101010101010";
signal ext_data:std_logic_vector(31 downto 0);
signal crc16_original:std_logic_vector(15 downto 0):="1100000000000010";
signal crc16:std_logic_vector(15 downto 0);
signal position:std_logic_vector(5 downto 0);
signal crc_out:std_logic_vector(14 downto 0);
signal i:std_logic_vector(5 downto 0);
begin
for i in 1 to 15 loop
ext_data(i+16)<=data(i);
end loop;
for i in 1 to 15 loop
ext_data(i)<='0';
end loop;
while ext_data > "111111111111111" loop
for i in 0 to 31 loop
if ext_data(i)="1" position=i;
end loop;
crc16<= crc16_original srl 31-position;
ext_data<=ext_data xor crc16;
end loop;
for i in 0 to 14 loop
crc_out(i)<=ext_data(i);
end loop;
end Behavioral;
There are several issues to point out:
The for-loop must be in a process, so that is likely to cause the “parse error, unexpected FOR” that you see.
The relation compare with > may give unexpected result for std_logic_vector, so you may take a look at the numeric_std package for casting as for example unsigned(std_logic_vector) before comparison is made.
Compare ext_data(i) = "1" is illegal, since "1" is taken as std_logic_vector, where as ext_data(i) is std_logic; instead ext_data(i) = '1' will compile.
Illegal construction around if ext_data(i) = "1" position=i;, since no then etc.
There is an signal with identifier i, which i is also used as loop variable, with the result that position <= i is taken as an integer assign to std_logic_vector; use different names for signals and loop variables.
Assign to signal is not position = i but position <= i, like elsewhere.
Expression 31-position mixes integer and std_logic_vector, which can't be done with the selected packages. Use casting with unsigned.
The ext_data<=ext_data xor crc16 uses different size arguments, since ext_data is 32 bits and crc16 is 16 bits; this does probably not yield the expected result.
srl is not defined for std_logic_vector (VHDL-2002), so consider casting with unsigned for well-defined behavior.
Assuming that that your code is "sandbox" code, since it has no outputs.
Based on the above, you may consider doing some initial experiments with smaller designs, in order to get familiar with the different VHDL constructions, and learn how this simulates and maps to hardware; remember VHDL is a "Hardware Description Language" and not a programming language.
Below is some code that compiles in ModelSim, but is unlikely to give the expected result:
library ieee;
use ieee.std_logic_1164.all;
entity crc16 is port(
clk : in std_logic := '0');
end crc16;
library ieee;
use ieee.numeric_std.all;
architecture Behavioral of crc16 is
signal data : std_logic_vector(15 downto 0) := "1010101010101010";
signal ext_data : std_logic_vector(31 downto 0);
signal crc16_original : std_logic_vector(15 downto 0) := "1100000000000010";
signal crc16 : std_logic_vector(15 downto 0);
signal position : std_logic_vector(5 downto 0);
signal crc_out : std_logic_vector(14 downto 0);
signal i_sig : std_logic_vector(5 downto 0);
begin
process (clk) is
begin
if rising_edge(clk) then
for i in 1 to 15 loop
ext_data(i+16) <= data(i);
end loop;
for i in 1 to 15 loop
ext_data(i) <= '0';
end loop;
while ext_data > "111111111111111" loop
for i in 0 to 31 loop
if ext_data(i) = '1' then
position <= i_sig; -- TBD[Probably not right code, but compiles]
end if;
end loop;
crc16 <= std_logic_vector(unsigned(crc16_original) srl (31 - to_integer(unsigned(position))));
ext_data <= ext_data xor crc16;
end loop;
for i in 0 to 14 loop
crc_out(i) <= ext_data(i);
end loop;
end if;
end process;
end Behavioral;
I have an input signal from ADC convertor that is 8 bits (std_logic_vector(7 downto 0)). I have to convert them to a 16 bits signal (std_logic_vector(15 downto 0)) for 16 bits signal processing to the 16 bits system.
If the 8 bit value is interpreted as signed (2's complement), then the general and standard VHDL conversion method is to use the IEEE numeric_std library:
library ieee;
use ieee.numeric_std.all;
architecture sim of tb is
signal slv_8 : std_logic_vector( 8 - 1 downto 0);
signal slv_16 : std_logic_vector(16 - 1 downto 0);
begin
slv_16 <= std_logic_vector(resize(signed(slv_8), slv_16'length));
end architecture;
So first the std_logic_vector is converted to a signed value, then the resize is applied, which will sign extend the signed value, and the result is finally converted back to std_logic_vector.
The conversion is rather lengthy, but has the advantage that it is general and works even if the target length is changed later on.
The attribute 'length simply returns the length of the slv_16 std_logic_vector, thus 16.
For unsigned representation instead of signed, it can be done using unsigned instead of signed, thus with this code:
slv_16 <= std_logic_vector(resize(unsigned(slv_8), slv_16'length));
architecture RTL of test is
signal s8: std_logic_vector(7 downto 0);
signal s16: std_logic_vector(15 downto 0);
begin
s16 <= X"00" & s8;
end;
This handles the conversion without having to edit the widths of the zeroes if either std_logic_vector changes:
architecture RTL of test is
signal s8: std_logic_vector(7 downto 0);
signal s16: std_logic_vector(15 downto 0) := (others => '0');
begin
s16(s8'range) <= s8;
end;
For completeness, yet another way which is occasionally useful:
-- Clear all the slv_16 bits first and then copy in the bits you need.
process (slv_8)
begin
slv_16 <= (others => '0');
slv_16(7 downto 0) <= slv_8;
end process;
I've not had to do this for vectors that I can recall, but I have had need of this under more complex circumstances: copying just a few relevant signals into a bigger, more complex, record was one time.
With the newly released VHDL-2019 standard you can do
larger_vec <= extend(shorter_vec);
where extend is a function defined as follows
function extend(vec : std_logic_vector) return target_vec of std_logic_vector is
variable result : std_logic_vector(target_vec'length - 1 downto 0) := (others => '0');
begin
assert vec'length <= target_vec'length report "Cannot extend to shorter vector";
result(vec'length - 1 downto 0) := vec;
return result;
end function;
Tool support is still a bit limited but at least one simulator supports this (Riviera-PRO).
so, I'm developing an ALU for MIPS architecture and I'm trying to make a shift left and a shift right so that the ALU can shift any amount of bits.
the Idea I had is to convert the shift value to an integer and select the piece of the entry that'll be on the result(the integer is stored in X) but Quartus doesn't accept a variable value, only constants.
What could I do to make this?
(Cases are on lines "WHEN "1000" =>..." and "WHEN "1001" =>...")
Thanks.
PROCESS ( ALU_ctl, Ainput, Binput, X )
BEGIN
-- Select ALU operation
--ALU_output_mux <= X"00000000"; --padrao
CASE ALU_ctl IS
WHEN "1000" => ALU_output_mux(31 DOWNTO X) <= (Ainput( 31-X DOWNTO 0 ));
WHEN "1001" => ALU_output_mux(31-X DOWNTO 0) <= (Ainput( 31 DOWNTO X ));
WHEN OTHERS => ALU_output_mux <= X"00000000";
END CASE;
END PROCESS;
If Quartus doesn't like it you have two choices:
Write it some way that Quartus does like - you're trying to infer a barrel shifter, so you could write one out longhand and then instantiate that. Potentially expensive in time
Get a different synthesizer that will accept it. Potentially expensive in money.
I have had issues with this in Quartus as well, although your code also has some implicit latches (you are not assigning all bits of the output in your two shift cases).
The work-around I use is to define an intermediate array with all the possible results, then select one of those results using your selector. In your case, something like the following:
subtype DWORD_T is std_logic_vector( 31 downto 0);
type DWORD_A is array (natural range <>) of DWORD_T;
signal shift_L : DWORD_A(31 downto 0);
signal shift_R : DWORD_A(31 downto 0);
signal zero : DWORD_T;
...
zero <= (others=>'0');
process (Ainput)
begin
for index in Ainput'range loop
shift_L(index) <= Ainput(31 - index downto 0) & zero(index - 1 downto 0);
shift_R(index) <= zero(index - 1 downto 0) & Ainput(31 downto index);
end loop;
end process;
ALR_output_mux <= shift_L(to_integer(X)) when ALU_ctl="1000",
shift_R(to_integer(X)) when ALU_ctl="1001",
(others=>'0') when others;
You could work around this by using generate or for to create each shift/rotate level, or you can use the standard functions ({shift,rotate}_{left,right}) for shifting and rotating.