Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
12 years ago

Addition problem in Quartus

So, after break the head for some minutes trying to find out why an simple addition didnt work, i went to see the RTL and found an weird thing:

https://dl.dropboxusercontent.com/u/38797606/Untitled.png

so, beyond putting an '0' on the last bit, it magically merges an vector of 32 bits into one of 31 bits (see big arrow on the image)?

the bigger vectors (of 46 bits) also have this issue.


library IEEE;use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity COUNTEUR_XYR_HIRES is Port ( 
    CODEUR1 : IN  STD_LOGIC_VECTOR (1  downto 0);
    CODEUR2 : IN  STD_LOGIC_VECTOR (1  downto 0);
    RELATION: IN  STD_LOGIC_VECTOR (23 downto 0);
    POSX    : OUT STD_LOGIC_VECTOR (31 downto 0);
    POSY    : OUT STD_LOGIC_VECTOR (31 downto 0);
    ROT     : OUT STD_LOGIC_VECTOR (15 downto 0);  --0-360 degrees+7 bits
    RESET   : IN  STD_LOGIC;
    H       : IN  STD_LOGIC
);
end COUNTEUR_XYR_HIRES;
architecture Behavioral of COUNTEUR_XYR_HIRES is
signal intPosX : Integer; --pas (32 bit) * 14 bits => 46 bits
signal intPosY : Integer; --pas (32 bit) * 14 bits => 46 bits
signal buffPosX : std_logic_vector(45 downto 0); 
signal buffPosY : std_logic_vector(45 downto 0); 
signal buffRot :  std_logic_vector(31 downto 0); 
signal subSubRot, subIncRot : std_logic_vector(31 downto 0);
signal nextSubRot, nextIncRot : std_logic_vector(31 downto 0);
--signal lastCod1, lastCod2: std_logic_vector(1 downto 0);
signal SINUS, COSINUS: STD_LOGIC_VECTOR(15 downto 0);
component TABLE_SINUS is Port (  
    H       : in  STD_LOGIC;
    ANGLE   : in  STD_LOGIC_VECTOR(15 downto 0);
    SINUS   : out STD_LOGIC_VECTOR(15 downto 0);
    COSINUS : out STD_LOGIC_VECTOR(15 downto 0)
);
end component;
begin
    POSX <= buffPosX(45 downto 14);
    POSY <= buffPosY(45 downto 14);
    ROT  <=  buffRot(31 downto 16);
    
    buffPosX <= std_logic_vector(to_unsigned(intPosX,46));
    buffPosY <= std_logic_vector(to_unsigned(intPosY,46));
    --buffRot  <= std_logic_vector(to_unsigned(intRot,32)) ;
    
    subSubRot <= STD_LOGIC_VECTOR(TO_UNSIGNED(TO_INTEGER(UNSIGNED(buffRot)) - TO_INTEGER(UNSIGNED(RELATION)),32));
    subIncRot <= STD_LOGIC_VECTOR(TO_UNSIGNED(TO_INTEGER(UNSIGNED(buffRot)) + TO_INTEGER(UNSIGNED(RELATION)),32));
    nextIncRot(23 downto 0) <= subIncRot(23 downto 0);
    nextSubRot(23 downto 0) <= subSubRot(23 downto 0);
    
    async : process(subIncRot, subSubRot)
    begin
        if(subIncRot(31 downto 24)=x"B4")then
            nextIncRot(31 downto 24) <= x"00";
        else
            nextIncRot(31 downto 24) <= subIncRot(31 downto 24);
        end if;
        if(subSubRot(31 downto 24)=x"FF")then
            nextSubRot(31 downto 24) <= x"B3";
        else
            nextSubRot(31 downto 24) <= subSubRot(31 downto 24);
        end if;
    end process;
    
    sin:TABLE_SINUS PORT MAP(
        H => H,
        ANGLE => buffRot(31 downto 16),
        SINUS => SINUS,
        COSINUS => COSINUS
    );
  
  onHorloge : process (H)
  begin
        if(H'event and H='1')then
            if(RESET='1')then
                intPosX<=0;
                intPosY<=0;
                buffRot <= x"00000000";
            else
                if(CODEUR1(0)='1')then
                    buffRot <= nextIncRot;
                    if(COSINUS(15)='0')then --cosinus>0
                        intPosX <= intPosX + TO_INTEGER(UNSIGNED(COSINUS(14 downto 0)));
                    else
                        intPosX <= intPosX - TO_INTEGER(UNSIGNED(COSINUS(14 downto 0)));
                    end if;
                    if(SINUS(15)='0')then
                        intPosY <= intPosY - TO_INTEGER(UNSIGNED(SINUS(14 downto 0)));
                    else
                        intPosY <= intPosY + TO_INTEGER(UNSIGNED(SINUS(14 downto 0)));
                    end if;
                elsif(CODEUR1(1)='1')then
                    buffRot <= nextSubRot;
                    if(COSINUS(15)='0')then --cosinus>0
                        intPosX <= intPosX - TO_INTEGER(UNSIGNED(COSINUS(14 downto 0)));
                    else
                        intPosX <= intPosX + TO_INTEGER(UNSIGNED(COSINUS(14 downto 0)));
                    end if;
                    if(SINUS(15)='0')then
                        intPosY <= intPosY + TO_INTEGER(UNSIGNED(SINUS(14 downto 0)));
                    else
                        intPosY <= intPosY - TO_INTEGER(UNSIGNED(SINUS(14 downto 0)));
                    end if;
                elsif(CODEUR2(0)='1')then
                    buffRot <= nextIncRot;
                    if(COSINUS(15)='0')then --cosinus>0, mais ici on subtraient
                        intPosX <= intPosX - TO_INTEGER(UNSIGNED(COSINUS(14 downto 0)));
                    else
                        intPosX <= intPosX + TO_INTEGER(UNSIGNED(COSINUS(14 downto 0)));
                    end if;
                    if(SINUS(15)='0')then
                        intPosY <= intPosY + TO_INTEGER(UNSIGNED(SINUS(14 downto 0)));
                    else
                        intPosY <= intPosY - TO_INTEGER(UNSIGNED(SINUS(14 downto 0)));
                    end if;
                elsif(CODEUR2(1)='1')then
                    buffRot <= nextSubRot;
                    if(COSINUS(15)='0')then --cosinus>0
                        intPosX <= intPosX + TO_INTEGER(UNSIGNED(COSINUS(14 downto 0)));
                    else
                        intPosX <= intPosX - TO_INTEGER(UNSIGNED(COSINUS(14 downto 0)));
                    end if;
                    if(SINUS(15)='0')then
                        intPosY <= intPosY - TO_INTEGER(UNSIGNED(SINUS(14 downto 0)));
                    else
                        intPosY <= intPosY + TO_INTEGER(UNSIGNED(SINUS(14 downto 0)));
                    end if;
                end if;
            end if;
        end if;
    end process;
end Behavioral;

I contourned the problem by shifting 1 bit all the vectors relative (thus, lost 1 bit reolution). but still, why cant i make a "simple" (32 bit) addition?

20 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The operator resize is new for me (thanks for the hint btw). I have not any more time to test until monday (maybe) but using them as SIGNED makes no sense for the projet (it represents one bit less available, except if you want it to spin a robot and it displays in the other sense). I just compiled the code using UNSIGNED and it seems exactly the same(loking at the RTL).

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    The operator resize is new for me (thanks for the hint btw).

    --- Quote End ---

    No problem :)

    Its a useful operator in that it will sign-extend for you.

    --- Quote Start ---

    I have not any more time to test until monday (maybe) but using them as SIGNED makes no sense for the projet (it represents one bit less available, except if you want it to spin a robot and it displays in the other sense). I just compiled the code using UNSIGNED and it seems exactly the same(loking at the RTL).

    --- Quote End ---

    If you draw yourself a "number circle" you'll find that an N-bit signed number or unsigned number has exactly the same binary patterns, so whether you use one format or the other really depends on what makes the most sense to you.

    For example, a 3-bit number can represent

    
    Bin   U    S
    --    -    -
    000   0    0
    001   1    1
    010   2    2
    011   3    3
    100   4   -4
    101   5   -3
    110   6   -2
    111   7   -1
    

    In either case;

    Unsigned: 101 + 100 = 5 + 4 -> 1 = 001

    Signed: 101 + 010 = -3 + 4 -> +1 = 001

    The point is that you can use the SIGNED data type without needing to use an extra bit relative to UNSIGNED. If you need a 31-bit representation for your modulo math, it can be signed or unsigned.

    Cheers,

    Dave
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Yes, but here it is filling with the resize, so (supposing an fill from 3 bits to 5):

    
    Bin(o)  Bin(f)   U  S
    000     00000    0  0
    001     00001    1  1
    010     00010    2  2
    011     00011    3  3
    100     11100    4  -4          
    101     11101    5  -3
    110     11110    6  -2
    111     11111    7  -1
      5 + 4
      00101 + 
      11100
    ---------
    1 00001 
    

    So, if I want to add values bigger than 3 (in this case) it will in fact subtract
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Yes, but here it is filling with the resize, so (supposing an fill from 3 bits to 5):

    
    Bin(o)  Bin(f)   U  S
    000     00000    0  0
    001     00001    1  1
    010     00010    2  2
    011     00011    3  3
    100     11100    4  -4          
    101     11101    5  -3
    110     11110    6  -2
    111     11111    7  -1
      5 + 4
      00101 + 
      11100
    ---------
    1 00001 
    

    So, if I want to add values bigger than 3 (in this case) it will in fact subtract

    --- Quote End ---

    to cast signed on an unsigned value you need to add a '0' sign bit to your unsigned values.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Yes, but here it is filling with the resize, so (supposing an fill from 3 bits to 5):

    --- Quote End ---

    If your number is unsigned to start with, resize should add zeros for the sign-extension bits.

    So your example for the unsigned values are no longer correct, i.e.,

    
    Bin(o)  resize(U,5) resize(S,5)
    100     00100 = 4  11100 = -4          
    101     00101 = 5  11101 = -3
    110     00110 = 6  11110 = -2
    111     00111 = 7  11111 = -1
    

    The resize() function should preserve the number in whatever format you pass it.

    Play with signed and/or signed numbers in Modelsim and I think you'll figure out what is the appropriate format for your application.

    Cheers,

    Dave
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    If your number is unsigned to start with, resize should add zeros for the sign-extension bits.

    The resize() function should preserve the number in whatever format you pass it.

    --- Quote End ---

    from http://standards.ieee.org/downloads/1076/1076.2-1996/numeric_std.vhdl

    function RESIZE (ARG: SIGNED; NEW_SIZE: NATURAL) return SIGNED;

    -- Result subtype: SIGNED(NEW_SIZE-1 downto 0)

    -- Result: Resizes the SIGNED vector ARG to the specified size.

    -- To create a larger vector, the new [leftmost] bit positions

    -- are filled with the sign bit (ARG'LEFT). When truncating,

    -- the sign bit is retained along with the rightmost part.

    By that, loks like: RESIZE(N(2 downto 0), 5) => N(2)&N(2)&N(2 downto 0)

    So, if I opt for UNSIGNED (again) I have all the bits, while if I opt for SIGNED, it will have 1 bit less with the possibility to change all the logic (witch in normal state isnt the case)

    also, i just compiled as said and it became weird in RTL:

    https://dl.dropboxusercontent.com/u/38797606/Untitled%20%282%29.png

    and then again, the RTL invents an circuit
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Look again at the link you posted, the function is over-loaded for both SIGNED and UNSIGNED.

    
    -- Id: R.1
      function RESIZE (ARG: SIGNED; NEW_SIZE: NATURAL) return SIGNED;
      -- Result subtype: SIGNED(NEW_SIZE-1 downto 0)
      -- Result: Resizes the SIGNED vector ARG to the specified size.
      --         To create a larger vector, the new  bit positions
      --         are filled with the sign bit (ARG'LEFT). When truncating,
      --         the sign bit is retained along with the rightmost part.
      -- Id: R.2
      function RESIZE (ARG: UNSIGNED; NEW_SIZE: NATURAL) return UNSIGNED;
      -- Result subtype: UNSIGNED(NEW_SIZE-1 downto 0)
      -- Result: Resizes the SIGNED vector ARG to the specified size.
      --         To create a larger vector, the new  bit positions
      --         are filled with '0'. When truncating, the leftmost bits
      --         are dropped.
    

    as I comment above, the MSBs of an unsigned number are '0' extended.

    --- Quote Start ---

    So, if I opt for UNSIGNED (again) I have all the bits, while if I opt for SIGNED, it will have 1 bit less

    --- Quote End ---

    I'm not sure what you mean by this. If you need 32-bits to represent a modulo-32 bit operation, then it does not matter if that 32-bit number uses signed or unsigned representation. In either case, you still need 32-bits. I'm not sure why you think signed would need 1-bit less.

    As for your RTL view ... personally I'd recommend starting with Modelsim and making sure your testbench produces the correct results, and then worry about synthesis.

    Cheers,

    Dave
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Look again at the link you posted, the function is over-loaded for both SIGNED and UNSIGNED.

    
    -- Id: R.1
      function RESIZE (ARG: SIGNED; NEW_SIZE: NATURAL) return SIGNED;
      -- Result subtype: SIGNED(NEW_SIZE-1 downto 0)
      -- Result: Resizes the SIGNED vector ARG to the specified size.
      --         To create a larger vector, the new  bit positions
      --         are filled with the sign bit (ARG'LEFT). When truncating,
      --         the sign bit is retained along with the rightmost part.
      -- Id: R.2
      function RESIZE (ARG: UNSIGNED; NEW_SIZE: NATURAL) return UNSIGNED;
      -- Result subtype: UNSIGNED(NEW_SIZE-1 downto 0)
      -- Result: Resizes the SIGNED vector ARG to the specified size.
      --         To create a larger vector, the new  bit positions
      --         are filled with '0'. When truncating, the leftmost bits
      --         are dropped.
    

    as I comment above, the MSBs of an unsigned number are '0' extended.

    I'm not sure what you mean by this. If you need 32-bits to represent a modulo-32 bit operation, then it does not matter if that 32-bit number uses signed or unsigned representation. In either case, you still need 32-bits. I'm not sure why you think signed would need 1-bit less.

    As for your RTL view ... personally I'd recommend starting with Modelsim and making sure your testbench produces the correct results, and then worry about synthesis.

    Cheers,

    Dave

    --- Quote End ---

    To avoid confusion I would declare the presumed unsigned value as signed "0"&value.

    Though we can use resize for either signed or unsigned but I am not sure what happens if we resize an unsigned value cast as signed inside this function. I would rather just avoid it.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I also just noticed that the signal is declares as std_logic_vector hence you cannot resize as signed when you mean unsigned unless you add 0 sign bit

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    To avoid confusion I would declare the presumed unsigned value as signed "0"&value.

    Though we can use resize for either signed or unsigned but I am not sure what happens if we resize an unsigned value cast as signed inside this function. I would rather just avoid it.

    --- Quote End ---

    I agree with Kaz. Since your operation involves both '+' and '-' operators, it makes more sense to use signed numbers for the representation.

    Assuming that 'relation' is an unsigned value, and given that it always has a lower bit-width than the 32-bit result, both of the following should yield identical results;

    
    subDecRot <= STD_LOGIC_VECTOR(SIGNED(buffRot)-resize(UNSIGNED(RELATION),32));
    subIncRot <= STD_LOGIC_VECTOR(SIGNED(buffRot)+resize(UNSIGNED(RELATION),32));
    

    although the subtraction may force the conversion to signed, in which case it might be preferred to simply convert relation to unsigned without resize, i.e., just unsigned(relation).

    The least ambiguous form is to use signed ...

    
    subDecRot <= STD_LOGIC_VECTOR(SIGNED(buffRot)-resize(SIGNED('0' & RELATION),32));
    subIncRot <= STD_LOGIC_VECTOR(SIGNED(buffRot)+resize(SIGNED('0' & RELATION),32));
    

    Ultimately your code would be less confusing if the entity ports used signed and unsigned types. Those ports can then be converted to std_logic_vector when used in the higher level design.

    Cheers,

    Dave