0
votes

I have a question on synthesis in VHDL that I'm hoping some of you can help me with. I have the following model for a adder :

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;

ENTITY Q3a IS
PORT    (A_MSB,B_MSB,A_LSB,B_LSB : IN   std_logic_vector(3 DOWNTO 0):="0000";
         SEL                     :  IN      std_logic:='0';
         CARRY                   :  OUT     std_logic:='0';
         OUTPUT                  :  OUT std_logic_vector(7 DOWNTO 0):="00000000");
END ENTITY Q3a;

ARCHITECTURE behavioral OF Q3a IS
SIGNAL A,B,SUM,B_NEG        :   std_logic_vector(8 DOWNTO 0);

BEGIN

A <= (A_MSB(3) & '0' & A_MSB(2 DOWNTO 0) & A_LSB) WHEN A_MSB(3) = '0' ELSE
      (A_MSB(3) & '1' & A_MSB(2 DOWNTO 0) & A_LSB);
B <= (B_MSB(3) & '0' & B_MSB(2 DOWNTO 0) & B_LSB) WHEN B_MSB(3) = '0' ELSE
      (B_MSB(3) & '1' & B_MSB(2 DOWNTO 0) & B_LSB);
B_NEG <= std_logic_vector(signed(not(B_MSB(3) & '0' & B_MSB(2 DOWNTO 0) & B_LSB))+1);


SUM <= std_logic_vector(signed(A)+ signed(B)) WHEN SEL = '0' ELSE
         std_logic_vector(signed(A)+ signed(B_NEG));

CARRY <= SUM(7);
OUTPUT <= SUM(8) & SUM(6 DOWNTO 0);

END ARCHITECTURE behavioral;

The model works OK'ish a few glitches. When I look at it though I see 3 multiplexers, one for A, one for B, and one for input selection to the adder. When I open the model with RTL viewer on Quartus II. I get this:

enter image description here

Which to me looks like 4 adders and a multiplexer. Can anyone share some light with me on this? Cheers D

3
How does your huge expression for A differ from A <= A_MSB(3) & A_MSB & A_LSB; ?user_1818839
Well it adds a bit in between A_MSB(3) and A_MSB (2 D---. It also uses a mux to check if A_MSB (3) is '1' or '0' to identify if the input is neg or pos. Then changes the additional bit for overflow/carry accordingly.hoboBob
Yes but unless I missed something, the added bit is identical to A_MSB(3) ... exactly as in mine. So, what did I miss? (Metavalues excepted).user_1818839
lol :) indeed it is.... thank you. Can you add any comments about the synthesis too?hoboBob
None except that an over-complicated expression can confuse the optimiser, which may be happening here. Compare resource use before/after simplification. (And I would double-check in simulation that your subtraction works correctly in all cases. I have a feeling that B and B_Neg should be more symmetrical.)user_1818839

3 Answers

3
votes

If I understand you correctly, you want one adder for a+b and a+b_neg, and a mux that selects between b or b_neg. You didn't write it explicitly, you need to write it like so

architecture behavioral of Q3a is
   signal a,b,sum,b_neg  :   std_logic_vector(8 downto 0);
   signal b_addr         :   std_logic_vector(8 downto 0);
begin
    a <= (a_msb(3) & a_msb & a_lsb);
    b <= (b_msb(3) & b_msb & b_lsb);
    b_neg <= std_logic_vector(-signed(b));

    b_addr <= b when sel = '0' else b_neg;

    sum <= std_logic_vector(signed(a)+ signed(b_addr));

    carry <= sum(7);
    output <= sum(8) & sum(6 downto 0);
end architecture behavioral;

Hopes that help you.

1
votes

There is a single mux in your design, as Brian noted the logic for A is simplified to A <= A_MSB(3) & A_MSG & A_LSB , which doesn't have a mux.

Your logic for B_neg is wrong, as it will only give you -B when B is positive. If you use B_neg <= std_logic_vector(signed(not(B))+1); you will have different synthesis results.

There should be 3 adders, one for B_neg, one for A+B and one for A+B_neg. However, I suspect because of the way you define B_neg with a constant '0', the synthesizer outsmart you and divide the B_neg adder into 2 smaller adder.

You don't have to define B_neg as "not B + 1", i.e. two's complement unary minus definition. It is better, for readability to use B_neg <= std_logic_vector(-signed(B)); or SUM <= std_logic_vector(signed(A)+signed(B)) when SEL = '0' else std_logic_vector(signed(A)-signed(B));

0
votes

After making the changes I have the following Architecture:

ARCHITECTURE behavioral OF Q3a IS
SIGNAL A,B,SUM,B_NEG        :   std_logic_vector(8 DOWNTO 0);

BEGIN

A <= (A_MSB(3) & A_MSB & A_LSB);
B <= (B_MSB(3) & B_MSB & B_LSB);
B_NEG <= std_logic_vector(-signed(B));


SUM <= std_logic_vector(signed(A)+ signed(B)) WHEN SEL = '0' ELSE
         std_logic_vector(signed(A)+ signed(B_NEG));

CARRY <= SUM(7);
OUTPUT <= SUM(8) & SUM(6 DOWNTO 0);
END ARCHITECTURE behavioral;

The RTL synthesis diagram has changed to:

enter image description here

Just like Jonathan suggested it would. I understand it needs 1 adder for B_NEG, but, but is their a reason for it having separate adders for A+B and A+B_NEG followed by a Mux, instead of having a Mux and two adders? Something more like this:

enter image description here

Is this just synthesis choice?