2
\$\begingroup\$

if i include the library numeric_std.vhd (the implementation is here https://standards.ieee.org/downloads/1076/1076.2-1996/numeric_std-body.vhdl) you can see that the operator *,+ (as instance are implemented in the following way)

  1. Unsigned sum

    function ADD_UNSIGNED (L, R: UNSIGNED; C: STD_LOGIC) return UNSIGNED is
        constant L_LEFT: INTEGER := L'LENGTH-1;
        alias XL: UNSIGNED(L_LEFT downto 0) is L;
        alias XR: UNSIGNED(L_LEFT downto 0) is R;
        variable RESULT: UNSIGNED(L_LEFT downto 0);
        variable CBIT: STD_LOGIC := C;
      begin
        for I in 0 to L_LEFT loop
          RESULT(I) := CBIT xor XL(I) xor XR(I);
          CBIT := (CBIT and XL(I)) or (CBIT and XR(I)) or (XL(I) and XR(I));
        end loop;
        return RESULT;
    end ADD_UNSIGNED;
    
  2. Multiplication

    function "*" (L, R: UNSIGNED) return UNSIGNED is
        constant L_LEFT: INTEGER := L'LENGTH-1;
        constant R_LEFT: INTEGER := R'LENGTH-1;
        alias XXL: UNSIGNED(L_LEFT downto 0) is L;
        alias XXR: UNSIGNED(R_LEFT downto 0) is R;
        variable XL: UNSIGNED(L_LEFT downto 0);
        variable XR: UNSIGNED(R_LEFT downto 0);
        variable RESULT: UNSIGNED((L'LENGTH+R'LENGTH-1) downto 0) := (others => '0');
        variable ADVAL: UNSIGNED((L'LENGTH+R'LENGTH-1) downto 0);
      begin
        if ((L'LENGTH < 1) or (R'LENGTH < 1)) then return NAU;
        end if;
        XL := TO_01(XXL, 'X');
        XR := TO_01(XXR, 'X');
        if ((XL(XL'LEFT)='X') or (XR(XR'LEFT)='X')) then
          RESULT := (others => 'X');
          return RESULT;
        end if;
        ADVAL := RESIZE(XR, RESULT'LENGTH);
        for I in 0 to L_LEFT loop
          if XL(I)='1' then RESULT := RESULT + ADVAL;
          end if;
          ADVAL := SHIFT_LEFT(ADVAL, 1);
        end loop;
        return RESULT;
    end "*";
    

Now i'm not sure of how it would work a VHDL compiler, but my question is... Since basically the algorithms i shown are "ripple carry adder" and "sum and shift" respectively apart logic optimization that the compiler usually could do wherever you use the operator "*,+" the compiler will always synthesizes a "ripple carry adder" and a "sum and shift" isn't? i mean usually the compiler don't try to draw a carry look ahead adder or a better multiplier by their own, so apart from options related to optimized delay or optimized area (which are performed at logic level not at architectural level) the programmer has to perform architectural optimization by his own isn't?

I'm asking this because i don't know if specific toolchain (except external package or library, which are used by the programmer anyway) could perform such kind of optimization by itself.

\$\endgroup\$
  • 3
    \$\begingroup\$ I think that it's safe to assume that the synthesis tools do not use the IEEE's reference implementations of the standard libraries, but their own implementations that are functionally equivalent, but optimized to allow their tools to achieve the greatest possible performance on the target technology. \$\endgroup\$ – Dave Tweed Sep 17 '15 at 16:02
  • \$\begingroup\$ Synthesizers exchange the libraries and primitive instantiations. For example the normal RTL view in Xilinx ISE shows adder blocks and synthesis reports inferred adders of n bits. In the technology RTL view the adder is replaced by LUTs, MUXCY and XORCY primitives (these two form the carry chain). The final XST report lists only mapable bells. Btw. Xilinx's and Altera's fast adder implementations are RCAs. The dedicated carrychain is the reason for the speedup. \$\endgroup\$ – Paebbels Sep 17 '15 at 21:03
  • \$\begingroup\$ Is there a way to be sure that a synthesizer use specific primitive for the operators? documentation etc? Like Xilinx, DC etc? \$\endgroup\$ – user8469759 Sep 18 '15 at 15:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.