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

        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;
        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;
  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);
        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;
        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.

  • 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, 2015 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, 2015 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\$ Sep 18, 2015 at 15:12


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.