问题
I am trying to build a 16 bit barrel shifter with left and right shift capabilities. I am having some issues with how to structure the code so that it will do what I think I want to do.
I have an opcode input that decides on the direction, an input vector to be shifted, an output vector, and a position vector with 4 bits.
I am using the position vector to set a shift 'level' in a way. I want to check position(0) and if it is set to 1, shift one position. And then check position(1) and shift 2 positions, position(3) 4 positions, and position(3) 8 positions.
I think that if I run through every position in the position vector and sequentially shift the bits it should eventually get all options. I will add the other opcode when this direction works properly.
I am stuck on the assigning the intermediate vectors for the architecture. I am not sure what the proper method should be and I can not find anything in google. Perhaps a Case system would work better.
entity eds_shifter is
port ( a : in bit_vector(15 downto 0) ; --input
pos : in bit_vector(3 downto 0); -- position
opc : in bit_vector(3 downto 0); -- opcode
y : out bit_vector(15 downto 0) --output
);
end entity eds_shifter ;
architecture behavior of eds_shifter is
begin
process(a,pos,opc) -- input vectors
signal s1,s2,s3,s4 : bit_vector(15 downto 0); -- intermediate steps
begin
s1 <= a(14 downto 0) & '0' when pos(0) = '1' and opc = "0000" else -- shifting left by one
s1 <= a when pos(0) = '0' and opc = "0000" else -- carryover vector to next shift position
s2 <= s1(13 downto 0) & '0' when pos(1) = '1' and opc = "0000" else -- shift previous vector by 2
s2 <= s1 when pos(1) = '0' and opc = "0000" else
s3 <= s2(12 downto 0) & '0' when pos(2) = '1' and opc = "0000" else -- shift another 4 places
s3 <= s2 when pos(2) = '0' and opc = "0000" else
s4 <= s3(7 downto 0) & '0' when pos(3) = '1' and opc = "0000" else -- shift another 8 places
s4 <= s3 when pos(3) = '0' and opc = "0000" else
y <= s4 when opc = "0000";
end process;
end architecture behavior;
Error Message
** Error: */02/eds_shifter.vhd(14): Illegal sequential statement.
** Error: */02/eds_shifter.vhd(15): Type error resolving infix expression "<=" as type std.standard.bit_vector.
EDIT
Thank you for the detailed response. I understand that there are generic shift functions built in but I want to try to figure out how to implement it myself.
Thanks for the tip about the bit_vector. From what I understand bit types are only ok to use when you are sure that the input is not multisourced. In this case it should probably be ok, but I will go ahead and keep it in mind for the future.
I think the concept I want to try is sound. If you check each bit in position for a 1 and shift by the appropriate amount at the end the number of bits shifted will equal the value of the position vector.
a = "1111 1111 1111 1111" and pos = "1010" so we need to shift by decimal 10 places. So we do the first iteration and it has no change, the second shifts by 2 bits, third iteration shifts by 0 bits, and the fourth shifts by 8 bits for a total of 10 bits shifted to get a="1111 1100 0000 0000".
My issue is not with the specific shifting operation (perhaps it is wrong and if so will use a different method, right now I am simply curious about how to implement my idea), my issue is writing code that will update the vector and then check the next position in the position vector. I was looking at what you posted about the delta cycle and sensitivity list. VHDL can be confusing since you have to describe the real world in terms of operations rippling through a processor. And it requires a different thinking than with standard programming.
I tried the below code but it only changes and shifts in my test bench once. I set up a test bench that runs through all combinations of positions but with the following code it only shifts at pos = 1000 and then it shifts 8 places. Is there any of forcing the code to check at each if statement, not only the last one?
entity eds_shifter is
port ( a : in bit_vector(15 downto 0) ; --input
pos : in bit_vector(3 downto 0); -- position
opc : in bit_vector(3 downto 0); -- opcode
y : out bit_vector(15 downto 0) --output
);
end entity eds_shifter ;
architecture behavior of eds_shifter is
begin
process(a,pos,opc) -- input vectors
begin
if pos(0) = '1' and opc = "0000" then -- shifting left by one
y <= a(14 downto 0) & "0";
else
y <= a;
end if;
if pos(1) = '1' and opc = "0000" then -- shifting left by two
y <= a(13 downto 0) & "00";
else
y <= a;
end if;
if pos(2) = '1' and opc = "0000" then -- shifting left by four
y <= a(11 downto 0) & "0000";
else
y <= a;
end if;
if pos(3) = '1' and opc = "0000" then -- shifting left by eight
y <= a(7 downto 0) & "00000000";
else
y <= a;
end if;
end process;
end architecture behavior;
Test Bench
entity eds_shifter_tb is
end eds_shifter_tb;
architecture behavior of eds_shifter_tb is
signal opc: bit_vector(3 downto 0);
signal pos: bit_vector(3 downto 0);
signal Y : bit_vector (15 downto 0);
signal a: bit_vector (15 downto 0);
begin
dut: entity work.eds_shifter(behavior)
port map(opc => opc,
pos => pos,
Y => Y,
a => a); -- assigns all ports to entity spec
a <= (others => '1'),
(others => '1') after 30 ns;
opc <= "0000",
"0001" after 30 ns;
pos <= "0000",
"0001" after 2 ns,
"0010" after 4 ns,
"0011" after 6 ns,
"0100" after 8 ns,
"0101" after 10 ns,
"0110" after 12 ns,
"0111" after 14 ns,
"1000" after 16 ns,
"1001" after 18 ns,
"1010" after 20 ns,
"1011" after 22 ns,
"1100" after 24 ns,
"1101" after 26 ns,
"1110" after 28 ns,
"1111" after 30 ns,
"0000" after 32 ns,
"0001" after 34 ns,
"0010" after 36 ns,
"0011" after 38 ns,
"0100" after 40 ns,
"0101" after 42 ns,
"0110" after 44 ns,
"0111" after 46 ns,
"1000" after 48 ns,
"1001" after 50 ns,
"1010" after 52 ns,
"1011" after 54 ns,
"1100" after 56 ns,
"1101" after 58 ns,
"1110" after 60 ns,
"1111" after 62 ns;
end behavior;
回答1:
I think you're missing a complete understanding of how hardware description differs from writing software and how processes work in VHDL. That said, you can use several concurrent assignments to do what you want (a cascade style barrel shifter). See the model below:
-- note, entirely untested!
library ieee;
use ieee.std_logic_1164.all;
entity eds_shifter is
port ( a : in std_logic_vector(15 downto 0) ; --input
pos : in std_logic_vector(3 downto 0); -- position
opc : in std_logic_vector(3 downto 0); -- opcode
y : out std_logic_vector(15 downto 0) --output
);
end entity eds_shifter ;
architecture behavior of eds_shifter is
signal s1,s2,s3,s4 : std_logic_vector(15 downto 0); -- intermediate steps
begin
--opcode 0000 is shift left, else is shift right
s1 <= a(14 downto 0) & '0' when pos(0) = '1' and opc = "0000" else --maybe shift by 1 place
'0' & a(15 downto 1) when pos(0) = '1' and opc /= "0000" else
a;
s2 <= s1(13 downto 0) & "00" when pos(1) = '1' and opc = "0000" else --maybe shift 2 places
"00" & s1(15 downto 2) when pos(1) = '1' and opc /= "0000" else
s1;
s3 <= s2(11 downto 0) & x"0" when pos(2) = '1' and opc = "0000" else --maybe shift 4 places
x"0" & s2(15 downto 4) when pos(2) = '1' and opc /= "0000" else
s2;
s4 <= s3(7 downto 0) & x"00" when pos(3) = '1' and opc = "0000" else --maybe shift 8 places
x"00" & s3(15 downto 8) when pos(3) = '1' and opc /= "0000" else
s3;
y <= s4;
end architecture behavior;
The recommended method of accomplishing shifting in general remains using the built-in functions, and they will likely turn into the same hardware post-synthesis if the optimizer is doing its job. While exercises like this are good for understanding how hardware works, realize that this is no more efficient, and it isn't useful as a small component of a larger project because it will increase code size and reduce readability for no benefit.
回答2:
There are several issues in the code:
when
can't be used as sequential statement (in process; before VHDL-2008), and theelse
part also looks like a statement, which is not correct syntaxsignal
can't be declared in processThe new value of a
signal
take a delta cycle before it is available, so thes*
must be in the sensitivity list for the value to ripple throughVHDL provides standard shift functions, which should be used, instead of the home build (that even looks wrong). Note that VHDL shift in-fix operators (before VHDL-2008) are known to give unexpected results, so use the functions instead; read more here.
So based on this the code with process can be updated to:
library ieee;
use ieee.numeric_bit.all;
architecture behavior of eds_shifter is
begin
process(a, pos, opc) -- input vectors
begin
if opc = "0000" then -- Shift left
y <= bit_vector(shift_left(unsigned(a), to_integer(unsigned(pos))));
else -- Assuming shift right
y <= bit_vector(shift_right(unsigned(a), to_integer(unsigned(pos))));
end if;
end process;
end architecture behavior;
Or with concurrent when
, then process can be replaced with:
y <= bit_vector(shift_left(unsigned(a), to_integer(unsigned(pos)))) when opc = "0000" else
bit_vector(shift_right(unsigned(a), to_integer(unsigned(pos))));
Note bit_vector
is not widely used, so consider updating to use
std_logic_vector
instead, whereby the code can be:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity eds_shifter is
port (a : in std_logic_vector(15 downto 0); --input
pos : in std_logic_vector(3 downto 0); -- position
opc : in std_logic_vector(3 downto 0); -- opcode
y : out std_logic_vector(15 downto 0) --output
);
end entity eds_shifter;
architecture behavior of eds_shifter is
begin
y <= std_logic_vector(shift_left(unsigned(a), to_integer(unsigned(pos)))) when (opc = "0000") else
std_logic_vector(shift_right(unsigned(a), to_integer(unsigned(pos))));
end architecture behavior;
回答3:
In your modified code:
process(a,pos,opc) -- input vectors
begin
if pos(0) = '1' and opc = "0000" then -- shifting left by one
y <= a(14 downto 0) & "0";
else
y <= a;
end if;
if pos(1) = '1' and opc = "0000" then -- shifting left by two
y <= a(13 downto 0) & "00";
else
y <= a;
end if;
...
You are overwriting the assignment to y
with each new if block. Signal assignment in processes is scheduled for the end of the process, not performed immediately. Your original code, with intermediate signals, would have worked had you fixed the syntax and added the intermediate signals to the sensitivity list as Morten suggested. Alternately, you could use a variable, as follows (note that in this version, the else
in each block would have been redundant):
process (a, pos, opc)
variable result : std_logic_vector(15 downto 0);
begin
result := a;
if pos(0) = '1' and opc = "0000" then
result := result(14 downto 0) & '0';
end if;
if pos(1) = '1' and opc = "0000" then
result := result(13 downto 0) & "00";
end if;
...
y <= result;
end process;
Unless you eventually want to pipeline your shifter, in which case you should go back to intermediate signals, and you'd also need to pipeline your other inputs to match. But then maybe we're getting ahead of ourselves...
来源:https://stackoverflow.com/questions/23891811/structure-of-vhdl-code-for-barrel-shifter-with-behavior-architecture