I am making a generic N-bit ALU in VHDL. I am having trouble assigning the value for the carry for addition, or borrow for subtraction. I have tried the following:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity alu is
generic(n: integer :=1); --Default to 1
port (
a : in std_logic_vector(n-1 downto 0);
b : in std_logic_vector(n-1 downto 0);
op : in std_logic_vector(1 downto 0);
output : out std_logic_vector(n-1 downto 0);
carryborrow: out std_logic
);
end alu;
architecture Behavioral of alu is
signal result: std_logic_vector(n downto 0);
begin
process( a, b, op )
begin
case op is
when "00" =>
result(n) <= '0';
result(n-1 downto 0) <= a and b; --and gate
output <= result(n-1 downto 0);
carryborrow <= '0';
when "01" =>
result(n) <= '0';
result(n-1 downto 0) <= a or b; --or gate
output <= result(n-1 downto 0);
carryborrow <= '0';
when "10" =>
result(n) <= '0';
result(n-1 downto 0) <= std_logic_vector(signed(a) + signed(b)); --addition
output <= result(n-1 downto 0);
carryborrow <= result(n);
when "11" =>
result(n) <= '0';
result(n-1 downto 0) <= std_logic_vector(signed(a) - signed(b)); --subtraction
output <= result(n-1 downto 0);
carryborrow <= result(n);
when others =>
NULL;
end case;
end process;
end Behavioral;
This seems to set the carryborrow bit to always be 0. How can I assign it to what it should be without type errors?
There are bugs in your code:
i) You have not taken into account the fact that signals are not updated immediately. Consequently, the following lines will not do as I think you are expecting:
result(n) <= '0';
result(n-1 downto 0) <= a and b; --and gate
output <= result(n-1 downto 0);
Instead, you need to take the lines driving output and carryborrow outside the combinational process, as you can see below.
ii) Assuming you wish this code to be synthesisable, simply putting NULL in your always branch will result in latches being inferred. You need to drive result in the others branch, too.
So, making an assumption about how your carry output is to behave with the and and or operations, this is how I would have written your code:
architecture Behavioral of alu is
signal result: std_logic_vector(n downto 0);
begin
process( a, b, op )
begin
case op is
when "00" =>
result <= '0' & (a and b); --and gate
when "01" =>
result <= '0' & (a or b); --or gate
when "10" =>
result <= std_logic_vector(resize(signed(a), n+1) + resize(signed(b), n+1)); --addition
when "11" =>
result <= std_logic_vector(resize(signed(a), n+1) - resize(signed(b), n+1)); --subtraction
when others =>
result <= (others => 'X');
end case;
end process;
output <= result(n-1 downto 0);
carryborrow <= result(n);
end Behavioral;
I normally do this:
result <= std_logic_vector(signed(a(n-1) & a) + signed(b(n-1) & b));
result <= std_logic_vector(signed(a(n-1) & a) - signed(b(n-1) & b));
Sign extend and then do the operation to take care of overflow, when the result is one extra bit long.
Hmm, consider this in a 4 bit environment, say a="0101" and b="1001". Adding them shall give the output="1110", with NO carry.
However, sign extending with resize(signed(a), n+1) and resize(signed(b), n+1) will set a="00101" and b="11001" and hence result="11110" and carryborrow='1', which is wrong!
By sign extending vectors a and b, the numeral range has increased to 5 bits, and thus result needs to be 6 bits to be able to hold carry, and we're back to square one.
Vectors a and b should only be zero extended, that is '0' & a and '0' & b before adding them to result, and then carryborrow, as MSB(Most Significant Bit) of result, will get the correct value.
Related
This code works except for the add and subtract operations denoted by opcode 010 and 110 respectively. When I try to add the numbers the result looks as though a and b are being XOR'd and subtracting does A XNOR B. I have no idea why this is happening pls help. Also I am not allowed to use arithmetic plus or minus in my code the point of it is to add logically.
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;
USE ieee.std_logic_unsigned.ALL;
USE ieee.numeric_std.ALL;
ENTITY Lab3ALU IS
PORT(
opcode :IN STD_LOGIC_VECTOR(2 DOWNTO 0);--INPUT
a :IN STD_LOGIC_VECTOR(31 DOWNTO 0);--INPUT
b :IN STD_LOGIC_VECTOR(31 DOWNTO 0);--INPUT
Cout :OUT STD_LOGIC;
Zero :OUT STD_LOGIC;
q :OUT STD_LOGIC_VECTOR(31 DOWNTO 0));--OUTPUT
END Lab3ALU;
ARCHITECTURE description of Lab3ALU IS
SIGNAL Reg1, Reg2, Reg3, Result : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL Cin, Sum, Carry : STD_LOGIC;
BEGIN
-- Update the register output on the clock's rising edge
process (a,b, opcode)
begin
Cin <= opcode(2);
Reg1 <= a;--temporarirly store A in Reg1 local variable
Reg2 <= b;--temporarily store B in Reg2 local variable
Reg3 <= NOT b;
case opcode is
When "000" => Result <= Reg1 AND Reg2;--AND
When "001" => Result <= Reg1 OR Reg2;--OR
When "010" =>
addloop: for i in 0 to 31 loop
Result(i) <= ((Reg1(i) XOR Reg2(i)) XOR Cin);
Cin <= (((Reg1(i) XOR Reg2(i))AND Cin)OR (Reg1(i) AND Reg2(i)));
end loop addloop;
When "110" =>
subloop: for i in 0 to 31 loop
Result(i) <= ((Reg1(i) XOR Reg3(i)) XOR Cin);
Cin <= (((Reg1(i) XOR Reg3(i))AND Cin)OR (Reg1(i) AND Reg3(i)));
end loop subloop;
When "100" => Result(31 downto 1) <= reg1(30 downto 0);
Result(0) <= '0';
Cin <= '0';
When "101" => Result(30 downto 0) <= reg1(31 downto 1);
Result(31) <= '0';
Cin <= '0';
When others => Result <= "00000000000000000000000000000000";
end case;
if Result = "00000000000000000000000000000000" then
Zero <= '1';
else
Zero <= '0';
end if;
q<= Result;
Cout<= Cin;
end process;
END description;```
I am trying to create a component for division in VHDL, below is my code. I dont know where i am going wrong. My logic is:
At every step,
• shift divisor right and compare it with current dividend
• if divisor is larger, shift 0 as the next bit of the quotient
• if divisor is smaller, subtract to get new dividend and shift 1
as the next bit of the quotient.
I have used '-' sign here but in actual i have to use gates so either i have to use my subtraction component or just create a subtractor here.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
ENTITY divprog IS
PORT(
a: IN std_logic_vector(3 downto 0);
b: IN std_logic_vector(3 downto 0);
err: OUT std_logic;
reslow: OUT std_logic_vector(3 downto 0);
reshigh: OUT std_logic_vector(3 downto 0));
END divprog;
architecture behaviour of divprog is
signal ax,bx,bsub,res :std_logic_vector(7 downto 0) := (others => '0');
signal quo: std_logic_vector(3 downto 0) := (others => '0');
signal intcarry: std_logic_vector(8 downto 0):= (others => '0');
BEGIN
--sub1: subtractor PORT MAP(aa,bb,x,ss);
Process is
variable i : POSITIVE := 1;
BEGIN
ax <= "0000" & a;
bx <= b & "0000";
if(b > "0000") then
while (i <=3) loop
bx <= '0'&bx(7 downto 1);
IF (ax < bx) then
quo <= quo(2 downto 0)& '0';
--bx <= '0'&bx(7 downto 1);
res <=ax;
elsif(ax >= bx) then
res <= ax - bx;
quo <=quo(2 downto 0)& '1';
end if;
i := i + 1;
ax <= res;
end loop;
reshigh <= quo;
reslow <= res(3 downto 0);
end IF;
wait for 100 ns;
END PROCESS;
end behaviour;
Can please someone help me with this?
Thanks
The functional problem is related to variable i. It gets stuck at 4 after the first 100ns. It should be set to 1 between BEGIN and END PROCESS.
I am writing a code for a 4 bit ALU and I have a problem when I want to write for shift left operation. I have two inputs (operandA and operandB ). I want to convert the operandB into decimal (for example "0010" into '2') and then shift operandA 2 times to the left. my code is compiled but I am not sure that it is true. Thank you in advance.
entity ALU is
port(
reset_n : in std_logic;
clk : in std_logic;
OperandA : in std_logic_vector(3 downto 0);
OperandB : in std_logic_vector(3 downto 0);
Operation : in std_logic_vector(2 downto 0);
Start : in std_logic;
Result_Low : out std_logic_vector(3 downto 0);
Result_High : out std_logic_vector(3 downto 0);
Ready : out std_logic;
Errorsig : out std_logic);
end ALU;
architecture behavior of ALU is
signal loop_nr : integer range 0 to 15;
begin
process (reset_n, clk, operation)
variable tempHigh : std_logic_vector(4 downto 0);
begin
if (reset_n = '0') then
Result_Low <= (others => '0');
Result_High <= (others => '0');
Errorsig <= '0';
elsif (clk'event and clk = '1') then
case operation is
when "001" =>
for i in 0 to loop_nr loop
loop_nr <= to_integer(unsigned(OperandB));
Result_Low <= OperandA(2 downto 0)&'0';
Result_High <= tempHigh(2 downto 0) & OperandA(3);
end loop;
Ready <= '1';
Errorsig <= '0';
when "010" =>
Result_Low <= OperandB(0)& OperandA(3 downto 1);
Result_High <= OperandB(3 downto 1);
Ready <= '1';
when others =>
Result_Low <= (others => '0');
ready <= '0';
Errorsig <= '0';
end case;
end if;
end process;
end behavior;
For shifting left twice the syntax should be the following:
A <= A sll 2; -- left shift logical 2 bits
I don't quite understand why is it required to convert operand B in decimal. It can be used as a binary or decimal value or for that matter hexadecimal value at any point of time irrelevant of the base it was saved in.
The operator sll may not always work as expected before VHDL-2008 (read more
here),
so consider instead using functions from ieee.numeric_std for shifting, like:
y <= std_logic_vector(shift_left(unsigned(OperandA), to_integer(unsigned(OperandB))));
Note also that Result_High is declared in port as std_logic_vector(3 downto
0), but is assigned in line 41 as Result_High <= OperandB(3 downto 1), with
assign having one bit less than size.
Assumption for code is that ieee.numeric_std is used.
The reason you've been urged to use the likes of sll is because in general
synthesis tools don't support loop statements with non-static bounds
(loop_nr). Loops are unfolded which requires a static value to determine how
many loop iterations are unfolded (how much hardware to generate).
As Morten points out your code doesn't analyze, contrary to you assertion
that it compiles.
After inserting the following four lines at the beginning of your code we see
an error at line 41:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--(blank, a spacer that doesn't show up in the code highlighter)
ghdl -a ALU.vhdl
ALU.vhdl:41:26: length of value does not match length of target
ghdl: compilation error
Which looks like
Result_High <= '0' & OperandB(3 downto 1);
was intended in the case statement, choice "010" (an srl equivalent hard
coded to a distance of 1, presumably to match the correct behavior of the sll
equivalent). After which your design description analyzes.
Further there are other algorithm description errors not reflected in VHDL
syntax or semantic errors.
Writing a simple test bench:
library ieee;
use ieee.std_logic_1164.all;
entity alu_tb is
end entity;
architecture foo of alu_tb is
signal reset_n: std_logic := '0';
signal clk: std_logic := '0';
signal OperandA: std_logic_vector(3 downto 0) :="1100"; -- X"C"
signal OperandB: std_logic_vector(3 downto 0) :="0010"; -- 2
signal Operation: std_logic_vector(2 downto 0):= "001"; -- shft right
signal Start: std_logic; -- Not currently used
signal Result_Low: std_logic_vector(3 downto 0);
signal Result_High: std_logic_vector(3 downto 0);
signal Ready: std_logic;
signal Errorsig: std_logic;
begin
DUT:
entity work.ALU
port map (
reset_n => reset_n,
clk => clk,
OperandA => OperandA,
OperandB => OperandB,
Operation => Operation,
Start => Start,
Result_Low => Result_Low,
Result_High => Result_High,
Ready => Ready,
Errorsig => Errorsig
);
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 100 ns then
wait;
end if;
end process;
STIMULUS:
process
begin
wait for 20 ns;
reset_n <= '1';
wait;
end process;
end architecture;
Gives us a demonstration:
The first thing that sticks out is that Result_High gets some 'U's. This is
caused by tempHigh not being initialized or assigned.
The next thing to notice is that the shift result is wrong (both Result_Low
and Result_High). I'd expect you'd want a "0011" in Result_High and "0000" in
Result_Low.
You see the result of exactly one left shift - ('U','U','U','1') in
Result_High and "1000" in Result_Low.
This is caused by executing a loop statement in delta cycles (no intervening
simulation time passage). In a process statement there is only one driver for
each signal. The net effect of that is that there is only one future value
for the current simulation time and the last value assigned is going to be
the one that is scheduled in the projected output waveform for the current
simulation time. (Essentially, the assignment in the loop statement to a
signal occurs once, and because successive values depend on assignment
occurring it looks like there was only one assignment).
There are two ways to fix this behavior. The first is to use variables
assigned inside the loop and assign the corresponding signals to the
variables following the loop statement. As noted before the loop bound isn't
static and you can't synthesis the loop.
The second way is to eliminate the loop by executing the shift assignments
sequentially. Essentially 1 shift per clock, signaling Ready after the last
shift occurs.
There's also away to side step the static bounds issue for loops by using a
case statement (or in VHDL 2008 using a sequential conditional signal
assignment of sequential selected signal assignment should your synthesis
tool vendor support them). This has the advantage of operating in one clock.
Note all of these require having an integer variable holding
to_integer(unsigned(OperandB)).
And all of this can be side stepped when your synthesis tool vendor supports
sll (and srl for the other case) or SHIFT_LEFT and SHIFT_RIGHT from package
numeric_std, and you are allowed to use them.
A universal (pre VHDL 2008) fix without using sll or SHIFT_LEFT might be:
begin
process (reset_n, clk, operation)
variable tempHigh : std_logic_vector(4 downto 0);
variable loop_int: integer range 0 to 15;
begin
if (reset_n = '0') then
Result_Low <= (others => '0');
Result_High <= (others => '0');
Errorsig <= '0';
elsif (clk'event and clk = '1') then
case operation is
when "001" =>
loop_int := to_integer(unsigned(OperandB));
case loop_int is
when 0 =>
Result_Low <= OperandA;
Result_High <= (others => '0');
when 1 =>
Result_Low <= OperandA(2 downto 0) & '0';
Result_High <= "000" & OperandA(3);
when 2 =>
Result_Low <= OperandA(1 downto 0) & "00";
Result_High <= "00" & OperandA(3 downto 2);
when 3 =>
Result_Low <= OperandA(0) & "000";
Result_High <= "0" & OperandA(3 downto 1);
when 4 =>
Result_Low <= (others => '0');
Result_High <= OperandA(3 downto 0);
when 5 =>
Result_Low <= (others => '0');
Result_High <= OperandA(2 downto 0) & '0';
when 6 =>
Result_Low <= (others => '0');
Result_High <= OperandA(1 downto 0) & "00";
when 7 =>
Result_Low <= (others => '0');
Result_High <= OperandA(0) & "000";
when others =>
Result_Low <= (others => '0');
Result_High <= (others => '0');
end case;
-- for i in 0 to loop_nr loop
-- loop_nr <= to_integer(unsigned(OperandB));
-- Result_Low <= OperandA(2 downto 0)&'0';
-- Result_High <= tempHigh(2 downto 0) & OperandA(3);
-- end loop;
Ready <= '1';
Errorsig <= '0';
Which gives:
The right answer (all without using signal loop_nr).
Note that all the choices in the case statement aren't covered by the simple
test bench.
And of course like most things there's more than two ways to get the desired
result.
You could use successive 2 to 1 multiplexers for both Result_High and
Result_Low, with each stage fed from the output of the previous stage (or
OperandA for the first stage) as the A input the select being the appropriate
'bit' from OperandB, and the B input to the multiplexers the previous stage
output shifted by 1 logically ('0' filled).
The multiplexers can be functions, components or procedure statements. By
using a three to one multiplexer you can implement both symmetrical shift
Operation specified operations (left and right). Should you want to include signed shifts,
instead of '0' filled right shifts you can fill with the sign bit value. ...
You should also be assigning Ready <= '0' for those cases where valid
successive Operation values can be dispatched.
And because your comment on one of the answers requires the use of a loop with an integer value:
process (reset_n, clk, operation)
variable tempHigh : std_logic_vector(4 downto 0);
variable tempLow: std_logic_vector(3 downto 0); --added
variable loop_int: integer range 0 to 15; --added
begin
if (reset_n = '0') then
Result_Low <= (others => '0');
Result_High <= (others => '0');
Errorsig <= '0';
elsif (clk'event and clk = '1') then
case operation is
when "001" =>
tempLow := OperandA; --added
tempHigh := (others => '0'); --added
loop_int := to_integer(unsigned(OperandB)); --added
-- for i in 0 to loop_nr loop
-- loop_nr <= to_integer(unsigned(OperandB));
-- Result_Low <= OperandA(2 downto 0)&'0';
-- Result_High <= tempHigh(2 downto 0) & OperandA(3);
-- end loop;
-- More added:
if loop_int /= 0 then
for i in 1 to loop_int loop
tempHigh (3 downto 0) := tempHigh (2 downto 0) & tempLow(3);
-- 'read' tempLow(3) before it's updated
tempLow := tempLow(2 downto 0) & '0';
end loop;
Result_Low <= tempLow;
Result_High <= tempHigh(3 downto 0);
else
Result_Low <= OperandA;
Result_High <= (others => '0');
end if;
Ready <= '1';
Errorsig <= '0';
Which gives:
And to demonstrate both halves of Result are working OperandA's default value has been changed to "0110":
Also notice the loop starts at 1 instead of 0 to prevent you from having an extra shift and there's a check for non-zero loop_int to prevent the for loop from executing at least once.
And is it possible to make a synthesizable loop in these circumstances?
Yes.
The loop has to address all possible shifts (the range of loop_int) and test whether or not i falls under the shift threshold:
process (reset_n, clk, operation)
variable tempHigh : std_logic_vector(4 downto 0);
variable tempLow: std_logic_vector(3 downto 0); --added
subtype loop_range is integer range 0 to 15;
variable loop_int: integer range 0 to 15; --added
begin
if (reset_n = '0') then
Result_Low <= (others => '0');
Result_High <= (others => '0');
Errorsig <= '0';
elsif (clk'event and clk = '1') then
case operation is
when "001" =>
tempLow := OperandA; --added
tempHigh := (others => '0'); --added
loop_int := to_integer(unsigned(OperandB)); --added
for i in loop_range loop
if i < loop_int then
tempHigh (3 downto 0) := tempHigh (2 downto 0) & tempLow(3);
-- 'read' tempLow(3) before it's updated
tempLow := tempLow(2 downto 0) & '0';
end if;
end loop;
Result_Low <= tempLow;
Result_High <= tempHigh(3 downto 0);
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;
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.
There are several issues in the code:
when can't be used as sequential statement (in process; before VHDL-2008), and
the else part also looks like a statement, which is not correct syntax
signal can't be declared in process
The new value of a signal take a delta cycle before it is available, so
the s* must be in the sensitivity list for the value to ripple through
VHDL 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;
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...
I am designing a 16-bit ALU which does few operations. I have a syntax error:
"Can't determine the definition of operator "+"".
The following code does Signed & Unsigned addition and subtraction and shift operation. It does a few other operations like OR, XOR etc., which I am not showing, as they doesn't have any problem.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity ALU16 is port
( A: in std_logic_vector (15 downto 0);
B: in std_logic_vector (15 downto 0);
AluOp: in std_logic_vector (4 downto 0);
shamt: in std_logic_vector (2 downto 0);
Zero: out std_logic;
Overflow: out std_logic;
R: out std_logic_vector (15 downto 0)
);
end ALU16;
architecture RTL of ALU16 is
signal temp : std_logic_vector( 16 downto 0);
signal usgnA, usgnB, Reg1 : unsigned(15 downto 0);
signal sgnA, sgnB, Reg2 : signed(15 downto 0);
begin
process(AluOp)
variable p : integer range 0 to 15;
begin
--usgnA <= unsigned(A);
--usgnB <= unsigned(B);
sgnA <= signed(A);
sgnB <= signed(B);
case AluOp is
when "00000" =>
--Reg1 <= usgnA + usgnB;
temp <= ('0' & A) + ('0' & B);
Overflow <= temp(16);
--temp <= A + B;
R<=temp(15 downto 0);
--Overflow <= A(15) and B(15);
-- when "00001" =>
-- --Reg1 <= usgnA - usgnB;
-- R<=A-B;
-- if (A < B) then Overflow<= '1';
-- else Overflow<= '0';
-- end if;
--
-- when "00010" =>
-- Reg2 <= sgnA + sgnB;
-- R<=std_logic(Reg2);
-- Overflow <= A(14) and B(14);
--
-- when "00011" =>
-- R <= sgnA - sgnB;
-- R<=std_logic(Reg2);
-- if (sgnA < sgnB) then Overflow<= '1';
-- else Overflow<= '0';
-- end if;
--
-- when "01011" =>
-- temp <= A;
-- temp <= shift_right(A,to_integer(shamt));
-- p :=to_integer(shamt);
-- for i in 1 to 3 loop
-- temp(i-1) <= '0';
-- end loop;
-- R<= temp;
--
when others =>
NULL;
-- if( R = "0000000000000000" ) then
-- Zero <= '1';
-- else Zero <='0';
-- end if;
end case;
end process;
end RTL;
As you are using numeric_std (which you should be), you will need to either change the type of temp to unsigned or cast the result of the addition to std_logic_vector. For signed addition, you can detect overflow by comparing the input signs with the output sign. If the input signs match and the output sign is different, you have overflow. Otherwise, you don't. I might also recommend using variables instead of signals for all intermediate results (so you don't run into any problems with sequential signal assignment):
process (AluOp)
variable Temp : std_logic_vector(15 downto 0);
begin
...
when "00010" =>
Temp := std_logic_vector(sgnA + sgnB);
R <= Temp;
Overflow <= (sgnA(15) xnor sgnB(15)) and (sgnA(15) xor Temp(15));
You are doing sum of to std_logic_vector.
and you have not used ieee.std_logic_arith.all, So it is showing the error.
but in one hdl file you can not use use IEEE.NUMERIC_STD.ALL and ieee.std_logic_arith.all.
It will make the compiler confused.
so better tryout temp <= std_logic_vector(unsigned(A) + unsigned(B));
It might solve your problem.
try out different combinations like this.