I have a code as such below that is designed to do subtraction and addition. Basically, when Binv is set, it should subtract, and Binv is 0, it should add. Unfortunately, it seems to be adding when Binv is set sometimes, and subtracting when it isn't set sometimes. Here is a snapshot of the simulation:
entity ADD_SUB is
Port ( A : in STD_LOGIC_VECTOR (31 downto 0);
B : in STD_LOGIC_VECTOR (31 downto 0);
Binv : in STD_LOGIC;
C_in: in STD_LOGIC;
S : out STD_LOGIC_VECTOR (31 downto 0);
TEST : out STD_LOGIC_VECTOR (31 downto 0);
C_out : out STD_LOGIC
);
end ADD_SUB;
architecture ADD_SUB_ARCH of ADD_SUB is
signal S_wider : std_logic_vector(32 downto 0);
begin
process (A,B,C_in,Binv)
begin
if Binv = '0' then
S_wider <= ( A(31) & A) + ( B(31) & B) + C_in;
elsif Binv = '1' then
S_wider <= (A(31)& A) + ('1'& not B) + '1';
else
S_wider <= std_logic_vector(to_signed(0,32));
end if;
S <= S_wider(31 downto 0);
C_out <= S_wider(32);
end process;
I am getting nonsensical results which make no sense. In the first case, you can see that I tried to do (50 - 30) (Binv is 1). I get 80 which is wrong. You can see however that it works on (30 - 50) where I get -20. Second problem is where I try to do (30 + (-50)), however it shows up as 20.
The results are completely off and I can't see where I am going wrong
Jim is absolutely correct.
There are a couple of points that may be worth making.
First, the + C_in or + not C_in implies two 32 bit adds, one of which gets optimized away during synthesis leaving just the carry in to the remaining add.
Second, you are really only manipulating B and C_in using Binv. Subtraction is the equivalent of adding the two's complement, for B the one's complement + X"00000001. Note that Jim inverts C_in with Binv which allows C_in to be used for daisy chain operations (e.g. a 64 bit add or subtract with a 32 bit ALU).
Both points are illustrated with the following code, which also only uses numeric_std.unsigned and and only needs the unsigned numeric_std."+":
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity add_sub is
port (
a: in std_logic_vector (31 downto 0);
b: in std_logic_vector (31 downto 0);
binv: in std_logic;
c_in: in std_logic;
s: out std_logic_vector (31 downto 0);
test: out std_logic_vector (31 downto 0);
c_out: out std_logic
);
end entity;
architecture foo of add_sub is
begin
UNLABELLED:
process (a,b,c_in,binv)
variable x,y,z: std_logic_vector (33 downto 0);
begin
x := a(31) & a & '1'; -- this '1' generates a true carry in to z(1)
-- z(0) is optimized away as unused it's carry
-- retained as carry in to the next MS bit.
if binv = '0' then
y := b(31) & b & c_in;
elsif binv = '1' then
y := not b(31) & not b & not c_in;
else
y := (others => 'X'); -- 'X' on binv is propagated from b onto y
end if;
z := std_logic_vector( unsigned(x) + unsigned(y)); -- only one add
c_out <= z(33);
s <= z(32 downto 1);
end process;
end architecture;
This above example connects C_in a bit more directly to the adder stage with the LS bits of A and B and gives:
(The image is can be clicked to open)
(Synthesis software is generally smart enough to do all this with using Jim's form modified to either add or subtract based on Binv and A and B extended to 33 bits without any direct bit or bitfield manipulation, our synthesis tools have had more than 25 years to get it right.)
The waveform was produced with the following test bench:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_add_sub is
end entity;
architecture foo of tb_add_sub is
signal a: std_logic_vector (31 downto 0) := (others =>'0');
signal b: std_logic_vector (31 downto 0) := (others =>'0');
signal binv: std_logic := '0';
signal c_in: std_logic := '0';
signal s: std_logic_vector (31 downto 0);
signal test: std_logic_vector (31 downto 0);
signal c_out: std_logic;
begin
DUT:
entity work.add_sub
port map (
a => a,
b => b,
binv => binv,
c_in => c_in,
s => s,
test => test,
c_out => c_out
);
STIMULUS:
process
begin
wait for 100 ns;
a <= std_logic_vector(to_signed(50,a'length));
b <= std_logic_vector(to_signed(30,b'length));
wait for 100 ns;
binv <= '1';
wait for 100 ns;
binv <= '0';
a <= std_logic_vector(to_signed(30,a'length));
b <= std_logic_vector(to_signed(-50,b'length));
wait for 100 ns;
binv <= '1';
b <= std_logic_vector(to_signed(50,b'length));
wait for 600 ns;
wait;
end process;
end architecture;
enter code hereYour equation for subtraction is not correct. Like #neodelphi suggested, it should be:
A - B = A + (not B) + 1
However, this does not account for carry in and what to do with it. If I remember right, the borrow is subtracted:
A - B - C_in = A + (not B) + 1 - C_in = A + (not B) + (1 - C_in)
Now note that:
(1 - C_in) = not C_in
Now, to convert it to VHDL. If I overlook the fact that you are doing signed math with the package, std_logic_unsigned (Ahem), you could write (similar to #neodelphi):
S_wider <= (A(31)& A) + (not B(31) & not B) + not C_in ;
Note in the package std_logic_unsigned as well as numeric_std with VHDL-2008, there are no issues with adding with a std_ulogic.
My suggestion about types and packages is very simple. If you are doing math, use a math type like, signed (matching your math here) or unsigned (for other cases). I consider these part of the documentation.
Furthermore, using the appropriate type is important as the math packages allow you to add two array values that are different sizes. If you use the appropriate type, they do the appropriate extension replicate sign bit for signed or '0' fill for unsigned.
Hence, had you used type signed, then you could have used the first argument (A) to size the result and been lazy about B and written:
S_wider <= (A(31)& A) + not B + not C_in ;
BTW, testing for both '0' and '1' does not help the hardware in any way. My recommendation is to either be lazy (and safe) and write:
if Binv = '0' then
S_wider <= ( A(31) & A) + ( B(31) & B) + C_in;
else
S_wider <= (A(31)& A) + (not B(31) & not B) + not C_in;
end if;
Alternately be paranoid and vigilant and make the output is 'X' when the control input is an 'X'. However be sure to double check your "elsif" expression - get this wrong when it is more complex and it may be challenging to find the bug (meaning you better have test cases that cover all possible input values of the controls):
if Binv = '0' then
S_wider <= ( A(31) & A) + ( B(31) & B) + C_in;
elsif Binv = '1' then
S_wider <= (A(31)& A) + (not B(31) & not B) + not C_in;
else
S_wider <= (others => 'X') ; -- X in propagates as X out can help debug
end if;
An AddSub module has only one control input lets call it \bar{add}/sub. This means, if add_sub is zero perform an add operation, if its one perform a subtraction.
There is a solid relation between C_in and Binv. If you want to add Binv and C_in are zero, if you want to subtract both are one.
The equation for an adder is simply S := A + B + 0 for a subtracter it can be retrieved by some transformations:
S := A - B -- transform into an add operation
S := A + (- B) -- transform negative number using 2's complement
S := A + ( 2's complement of B) -- transform 2's complement into 1's complement
S := A + ((1's complement of B) + 1) -- transform 1's complement into bit wise not operation
S := A + ((bit wise not of B) + 1)
If you combine both equations you will get:
S := A + (B xor vector(add_sub)) + add_sub
So in VHDL this would be:
S_wider <= unsigned('0' & A) + unsigned('0' & (B xor (B'range => add_sub))) + unsigned((B'range => '0') & add_sub);
S <= S_wider(S'range);
C_out <= S_wider(S_width'high);
Synthesis is smart enough to find a 3:1 adder with a switchable constant input 3 to be an addsub-macro block. If you want to perform signed add/sub then exchange the conversion functions and sign-extension accordingly.
Related
So I've been working on some homework for my VHDL course and I can't seem to understand this problem.
The point here is to create the adder/subtractor of an ALU that works both on 2's complement and unsigned 32-bit buses, which is why I have a condition called sub_mode ( A - B = A + !B + 1 ) which will also be the carry-in when activated.
The rest of the different inputs and outputs are pretty self-explanatory.
My problem is with the testbenching of such component where, even though carry_temp and r_temp have been initialized in declaration section of the architecture, end up showing up undefined. I have guessed that it is due to the for loop within the process screwing everything up. Would that be an accurate guess? And if yes, is it possible to proceed to add two bit buses together without having to fully create an n-bit adder made from n 1-bit adder components?
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity add_sub is
port(
a : in std_logic_vector(31 downto 0);
b : in std_logic_vector(31 downto 0);
sub_mode : in std_logic;
carry : out std_logic;
zero : out std_logic;
r : out std_logic_vector(31 downto 0)
);
end add_sub;
architecture synth of add_sub is
signal cond_inv : std_logic_vector(31 downto 0);
signal carry_temp : std_logic_vector(32 downto 0) := (others => '0');
signal r_temp : std_logic_vector(31 downto 0) := (others => '0');
begin
behave : process(a,b,sub_mode)
begin
if sub_mode = '1' then
cond_inv <= b xor x"ffffffff";
else
cond_inv <= b;
end if;
carry_temp(0) <= sub_mode;
for i in 0 to 31 loop
r_temp(i) <= a(i) xor cond_inv(i) xor carry_temp(i);
carry_temp(i+1) <=
(a(i) and cond_inv(i)) or
(a(i) and carry_temp(i)) or
(cond_inv(i)and carry_temp(i));
end loop;
if r_temp = x"00000000" then
zero <= '1';
else
zero <= '0';
end if;
r <= r_temp;
carry <= carry_temp(32);
end process behave;
end synth;
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.
Good day,
I have implemented a 8 bit CLA add/subtract module and it works great. The code is below: I have strung 2 of these modules below to create a 16 bit adder/subtractor. This 16 bit version works great for addition, the carry is generated by 1 8 bit adder for the lower bits, which is then passed onto the next adder to be handled for the upper bits.
The problem is with subtraction. It doesn't work, even on paper. Let me give you an example. Lets say I want to do 350 - 50
300: 00000001 00101100
50: 00000000 00110010
Hence, if i let one adder handle the lower bits, and another handle the upper bits, it simply would not work. Here is why:
300: 00000001 00101100
50 in 2's compliment: 11111111 11001110
250 is supposed to be 00000000 11111010
1st adder: Generates correct value after addition 11111010. That's cool. Now the second adder, is a problem. It will do (1's compliment + 1) which will give 00000000 (with carry). It was supposed to be (11111111), but because of the + 1 in the algo which is a general implementation, it screws up the final answer.
By right, since Adder 0 has no carry, Adder 1 should not do the + 1. How might I be able to implement this in the logic for the general purpose 8 bit sub/adder? Is this the correct thinking and have i covered all possible fallouts/edge cases?
entity CLA_ADD_SUB is
generic (N : integer := 8);
Port ( A : in STD_LOGIC_VECTOR (N-1 downto 0);
B : in STD_LOGIC_VECTOR (N-1 downto 0);
Binv : in STD_LOGIC;
C_in: in STD_LOGIC;
S : out STD_LOGIC_VECTOR (N-1 downto 0);
TEST : out STD_LOGIC_VECTOR (N-1 downto 0);
C_out : out STD_LOGIC
);
end CLA_ADD_SUB;
architecture CLA_ADD_SUB_ARCH of CLA_ADD_SUB is
SIGNAL h_sum : STD_LOGIC_VECTOR(N-1 DOWNTO 0);
SIGNAL carry_generate : STD_LOGIC_VECTOR(N-1 DOWNTO 0);
SIGNAL carry_propagate : STD_LOGIC_VECTOR(N-1 DOWNTO 0);
SIGNAL carry_in_internal : STD_LOGIC_VECTOR(N-1 DOWNTO 1);
SIGNAL B_mod : STD_LOGIC_VECTOR(N-1 DOWNTO 0) := B;
SIGNAL C_in_mod: STD_LOGIC := C_in;
signal S_wider : std_logic_vector(N downto 0);
begin
WITH Binv SELECT
B_mod <= B WHEN '0',
not B WHEN '1',
B WHEN OTHERS;
WITH Binv SELECT
C_in_mod <= C_in WHEN '0',
not C_in WHEN '1',
C_in WHEN OTHERS;
-- Sum, P and G
h_sum <= A XOR B_mod;
carry_generate <= A AND B_mod;
carry_propagate <= A OR B_mod;
PROCESS (carry_generate,carry_propagate,carry_in_internal,C_in_mod)
BEGIN
carry_in_internal(1) <= carry_generate(0) OR (carry_propagate(0) AND C_in_mod);
inst: FOR i IN 1 TO (N-2) LOOP
carry_in_internal(i+1) <= carry_generate(i) OR (carry_propagate(i) AND carry_in_internal(i));
END LOOP;
C_out <= carry_generate(N-1) OR (carry_propagate(N-1) AND carry_in_internal(N-1));
END PROCESS;
S(0) <= h_sum(0) XOR C_in_mod;
S(N-1 DOWNTO 1) <= h_sum(N-1 DOWNTO 1) XOR carry_in_internal(N-1 DOWNTO 1);
end CLA_ADD_SUB_ARCH;
The problem is, that you did an error calculating the 2's complement of 50:
In your equation you use:
50 in 2's compliment: 11111111 11001101 <--- WRONG.
which is just 50 with all bits inverted. two's complement however is build by first inverting the bits, then add one to it.
The correct representation of -50 in 16 bit integers is:
50 in 2's compliment: 11111111 11001110
If we now do the math of 300 - 50 we'll get:
00000001 00101100 | 300
+ 11111111 11001110 | -50 in 2's complement form
-------------------
00000000 11111010 | 250 (expected result)
For your VHDL implementation that means that you can implement subtraction by re-using the addition part. To do so build the two's complement in two steps:
If subtraction-mode:
negate all bits of B prior to addition
force the carry-in of the low 8 bit adder to high.
The second step will add the one to the negated B which then is a correct two's complement number. Now you add your numbers as usual and get a functional subtracter.
u_ADDER_0: entity work.CLA_ADD_SUB(CLA_ADD_SUB_ARCH)
port map(
A => ADDER_0_A, -- Bits 0-7
B => ADDER_0_B,
Binv => TOADD_BINV,
C_in => ADDER_0_CARRY_IN,
S => ADDER_0_SUM,
TEST => ADDER_0_TEST,
C_out => ADDER_0_CARRY_OUT
);
u_ADDER_1: entity work.CLA_ADD_SUB(CLA_ADD_SUB_ARCH)
port map(
A => ADDER_1_A, --Bits 7 to 15
B => ADDER_1_B,
Binv => TOADD_BINV,
C_in => TOADD_BINV xor ADDER_0_CARRY_OUT,
S => ADDER_1_SUM,
TEST => ADDER_1_TEST,
C_out => ADDER_1_CARRY_OUT
);
Ah I get it, actually what I did was for all subsequent adders (for bits 7-15 etc.) I set the Carry for those to (Binv xor Adder_0_Carry). Hence, if the 1st adder has a carry due to the + 1 for the 2's compliment, it will propogate out of the carry, and since I xor it with Binv, I tell the second adder to not add a carry.
the idea is that if we are subtracting (doing 2's compliment), we should just do a (1's compliment) if the first adder had no carry
I cannot confirm this for all test cases. This is just a theory and so far it seems to work
This is supplemental to your own answer.
Hmm..if I set B_inv to 0, meaning I am doing addition, and I pass in two signed bits. say 50 and -250, it won't work, because the second adder's C_in is determined by Binv xor Adder_0_carry
I think your manual arithmetic is faulty:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_add_sub_gang is
constant n: natural := 8;
end entity;
architecture foo of tb_add_sub_gang is
signal a: std_logic_vector (2*n-1 downto 0);
signal b: std_logic_vector (2*n-1 downto 0);
signal s: std_logic_vector (2*n-1 downto 0);
signal test: std_logic_vector (2*n-1 downto 0);
signal binv: std_logic;
signal cout0: std_logic;
signal cin1: std_logic;
signal cout1: std_logic;
begin
cin1 <= cout0 xor binv;
uadder0:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a((2*n-1)/2 downto 0), -- bits 0-7
b => b((2*n-1)/2 downto 0),
binv => binv,
c_in => '0',
s => s((2*n-1)/2 downto 0),
test => s((2*n-1)/2 downto 0),
c_out => cout0
);
uadder1:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a(2*n-1 downto n), --bits 8 to 15
b => b(2*n-1 downto n),
binv => binv,
c_in => cin1,
s => s(2*n-1 downto n),
test => test(2*n-1 downto n),
c_out => cout1
);
STIMULUS:
process
begin
wait for 100 ns;
a <= std_logic_vector(to_unsigned(350,a'length));
b <= std_logic_vector(to_unsigned(50,b'length));
binv <= '1';
wait for 100 ns;
binv <= '0';
wait for 100 ns;
a <= std_logic_vector(to_unsigned(50,a'length));
b <= std_logic_vector(to_unsigned(250,b'length));
binv <= '1';
wait for 100 ns;
binv <= '0';
wait for 600 ns;
wait;
end process;
end architecture;
Gives:
(I update the waveform image for your signed subtraction/addition).
The binv selector in cla_add_sub is the equivalent of XOR between Binv and C_in. XORing Binv in again externally for the Most Significant n bit adder is gives you an even number number of XORs removing their effect, carrying in the carry out of the Least Significant adder.
The proper thing to do is actually to only invert B with Binv and use Binv to also invert the carry in of the LS adder. Because you never carry in to it other than for subtraction, hook it directly to Binv. This will fix everything.
in cla_add_sub comment out:
-- WITH Binv SELECT
-- C_in_mod <= C_in WHEN '0',
-- not C_in WHEN '1',
-- C_in WHEN OTHERS;
The declaration for C_in_mod:
-- SIGNAL C_in_mod: STD_LOGIC := C_in;
And use C_in directly:
PROCESS (carry_generate,carry_propagate,carry_in_internal,C_in)
BEGIN
carry_in_internal(1) <= carry_generate(0) OR (carry_propagate(0) AND C_in);
inst: FOR i IN 1 TO (N-2) LOOP
carry_in_internal(i+1) <= carry_generate(i) OR (carry_propagate(i) AND carry_in_internal(i));
END LOOP;
C_out <= carry_generate(N-1) OR (carry_propagate(N-1) AND carry_in_internal(N-1));
END PROCESS;
And for S(0):
S(0) <= h_sum(0) XOR C_in;
In the top level:
-- signal cin1: std_logic;
-- cin1 <= cout0 xor binv;
uadder0:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a((2*n-1)/2 downto 0), -- bits 0-7
b => b((2*n-1)/2 downto 0),
binv => binv,
c_in => binv,
s => s((2*n-1)/2 downto 0),
test => s((2*n-1)/2 downto 0),
c_out => cout0
);
uadder1:
entity work.cla_add_sub(cla_add_sub_arch)
port map(
a => a(2*n-1 downto n), --bits 8 to 15
b => b(2*n-1 downto n),
binv => binv,
c_in => cout,
s => s(2*n-1 downto n),
test => test(2*n-1 downto n),
c_out => cout1
);
And that gives the same results as shown above.
And notice this is in keeping with Nils answer.
If you only had an n bit adder/subtractor you'd use the method in your answer where carry out (LS) to carry in (MS) would be inverted again to chain two 8 bit operations together.
This instantiates two adders that happen to invert B, the 1's complement part of 2's Complement to subtract 'B'. You could add an input to cla_add_sub signify when it's the LS adder and only XOR Binv then. That way it could serve as either a stand alone n bit adder or one that can be daisy chained.
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.
I'm trying to combine several 1 bit ALUs into a 4 bit ALU. I am confused about how to actually do this in VHDL. Here is the code for the 1bit ALU that I am using:
component alu1 -- define the 1 bit alu component
port(a, b: std_logic_vector(1 downto 0);
m: in std_logic_vector(1 downto 0);
result: out std_logic_vector(1 downto 0));
end alu1;
architecture behv1 of alu1 is
begin
process(a, b, m)
begin
case m is
when "00" =>
result <= a + b;
when "01" =>
result <= a + (not b) + 1;
when "10" =>
result <= a and b;
when "11" =>
result <= a or b;
end case
end process
end behv1
I am assuming I define alu1 as a component of the larger entity alu4, but how can I tie them together?
Interesting you would even ask that question. VHDL synthesizers are quite capable of inferring any adder you like. You can just type what you need:
use ieee.numeric_std.all;
...
signal r : unsigned(3 downto 0);
signal a : unsigned(2 downto 0);
signal b : unsigned(2 downto 0);
signal c : unsigned(2 downto 0);
...
r <= a + b + c;
Then you can slice r to fit your needs:
result <= std_logic_vector(r(2 downto 0));
You can't (easily) string together these 1-bit ALUs into a functional multiple bit version. There is no way to handle the carry in/out needed for your add and subtract modes to work properly (the bitwise and & or should work OK, however).
Ignoring the carry issue for the moment, you would typically just setup a for generate loop and instantiate multiple copies of your bitwise logic, possibly special casing the first and/or last elements, ie:
MyLabel : for bitindex in 0 to 3 generate
begin
alu_x4 : entity work.alu1
port map (
a => input_a(bitindex),
b => input_b(bitindex),
m => mode,
result => result_x4(bitindex) );
end generate;