FPGA

Verilog Floating Point Multiplier

By CourseTron Team ·  4 min read ·  Updated Oct 2026 💬 𝕏 in f
Table of Contents
    ? Print / Save as PDF

    In short: An IEEE 754 multiplier XORs the signs, adds the biased exponents and subtracts the bias once, multiplies the 24-bit significands (hidden bit included), then normalizes the 48-bit product by at most one position, rounds to nearest-even and repacks the fields.

    Why floating-point multiplication is easier than addition

    Ask a hardware interviewer which is cheaper on silicon, a floating-point adder or a multiplier, and the honest answer is "the adder is harder". Addition needs exponent comparison, a barrel shifter to align operands, a leading-zero counter after cancellation and a second rounding pass. Multiplication has no alignment step: the three fields are processed independently and only meet at the end. That is why an FPGA engineer can sketch a working single-precision multiplier on a whiteboard in ten minutes, and why the multiplier is the classic first floating-point exercise after you have finished your integer FPGA basics.

    The format you must know cold

    An IEEE 754 number is stored as sign, biased exponent and fraction. The value of a normal number is (−1)s × 1.fraction × 2(e − bias). The leading 1 is implicit, so a 23-bit fraction really carries 24 bits of precision.

    FormatSignExponentFractionBias
    Half (binary16)151015
    Single (binary32)1823127
    Double (binary64)111521023

    Key fact: exponent 0 means zero or subnormal, exponent 255 (all ones) means infinity or NaN. Only exponents 1 to 254 carry the hidden leading 1.

    The four steps, with a worked example

    Single-precision multiplier datapath Unpack A, B s | e | f Sign sa XOR sb Exponent ea + eb − 127 Significand 24 × 24 → 48 bits Normalize + round shift ≤ 1 bit Pack s | e | f CourseTron · coursetron.com
    The three lanes are independent until normalization, which is why multiplication pipelines so cleanly.

    Take 3.5 × (−2.25). In binary, 3.5 = 1.11 × 21 and 2.25 = 1.001 × 21.

    • Sign: 0 XOR 1 = 1, so the result is negative.
    • Exponent: the stored values are 128 and 128. Adding gives 256, which double-counts the bias, so subtract 127 once: 129. That is a true exponent of 2.
    • Significand: 1.75 × 1.125 = 1.96875, which is 1.11111 in binary.
    • Normalize: already in the form 1.x, so no shift. The result is −1.96875 × 22 = −7.875, stored as 0xC0FC0000.

    Key fact: always subtract the bias exactly once after adding the stored exponents. Forgetting this gives results that are off by a factor of 2127, a classic first-simulation bug.

    Why normalization is at most one bit

    Both significands lie in [1, 2). Their product therefore lies in [1, 4), so the 48-bit product has the form 01.xxx or 1x.xxx. Test product bit 47. If it is 0, the fraction is bits [45:23] and the exponent stays. If it is 1, the fraction is bits [46:24] and the exponent increases by one. Compare 1.5 × 1.5: 1.1 × 1.1 = 10.01 in binary, bit 47 is set, the exponent goes from 127 to 128 and the stored result is 1.001 × 21 = 2.25. Unlike subtraction, there is no leading-zero counter anywhere.

    Picking the fraction from the 48-bit product Case 1: P[47] = 0, product is 01.xxx, exponent unchanged 0 1 fraction = P[45:23] guard = P[22], sticky = |P[21:0] Case 2: P[47] = 1, product is 1x.xxx, exponent + 1 1 x fraction = P[46:24] guard = P[23], sticky = |P[22:0] Round up when guard = 1 and (sticky = 1 or fraction LSB = 1): round-to-nearest-even. CourseTron · coursetron.com
    Bit 47 of the product selects the case; the discarded low bits supply guard and sticky for rounding.

    Rounding, the part people skip

    Dropping the low bits is truncation, not IEEE rounding. The default mode is round-to-nearest, ties-to-even: look at the guard bit (the first discarded bit) and the sticky bit (the OR of everything below it). Round up if guard is 1 and either sticky or the fraction LSB is 1. A tie, where guard is 1 and everything below is 0, rounds to whichever neighbour has an even LSB, so errors do not drift in one direction over millions of accumulations. If rounding carries all the way out of the fraction (1.111…1 + 1 ulp), the fraction becomes zero and the exponent increments again.

    Key fact: the 24 × 24 multiply produces 48 exact bits, so guard and sticky are free. You only need an extra rounding adder, not a wider datapath.

    A Verilog implementation outline

    The sketch below is combinational and handles normal numbers; wrap the stages in registers for timing. Use continuous assigns for the wiring (see reg vs wire in Verilog) and non-blocking assignments for any pipeline registers (see blocking vs non-blocking). Note the widened exponent: if you keep it at 8 bits, overflow and underflow become undetectable. For a refresher on why width matters, read about sign extension in Verilog.

    module fp_mul (input [31:0] a, b, output [31:0] y);
      wire        sy  = a[31] ^ b[31];
      wire [7:0]  ea  = a[30:23], eb = b[30:23];
      wire [23:0] ma  = {1'b1, a[22:0]};   // hidden bit (normal only)
      wire [23:0] mb  = {1'b1, b[22:0]};
      wire [9:0]  es  = {2'b0,ea} + {2'b0,eb} - 10'd127;
      wire [47:0] p   = ma * mb;
      wire        nrm = p[47];
      wire [22:0] fr  = nrm ? p[46:24] : p[45:23];
      wire        g   = nrm ? p[23]    : p[22];
      wire        st  = nrm ? |p[22:0] : |p[21:0];
      wire        up  = g & (st | fr[0]);
      wire [23:0] rf  = {1'b0, fr} + up;
      wire [9:0]  er  = es + nrm + rf[23];
      wire        ovf = ($signed(er) >= 255);
      wire        unf = ($signed(er) <= 0);
      assign y = (unf) ? {sy, 31'b0} :
                 (ovf) ? {sy, 8'hFF, 23'b0} :
                         {sy, er[7:0], rf[22:0]};
    endmodule

    A production block adds the special cases in front: if either input exponent is 0 the result is zero (or a subnormal), if either is 255 the output is infinity or NaN, and 0 × infinity must return NaN. Subnormals are the expensive part, which is why many FPGA designs flush them to zero and document it.

    Mapping to FPGA hardware

    The 24 × 24 multiplier is the only costly block. A Xilinx (AMD) DSP48E2 offers a 27 × 18 multiplier and an Intel variable-precision DSP block handles 27 × 27, so a 24-bit operand pair typically consumes two to four DSP slices depending on the family; the trade-offs are covered in our Xilinx vs Intel comparison. Vendors also ship floating-point IP (AMD Floating-Point Operator, Intel FP functions) that is fully pipelined at 300 to 500 MHz, so hand-rolled RTL is mainly an interview and learning exercise, or a way to build custom formats such as bfloat16. In ASIC flows, Synopsys DesignWare and Cadence Genus both infer the multiplier from the * operator, and Siemens Questa is commonly used to run the corner-case regression against a C reference model. Our Booth-encoded multiplier article (verilog-4-bit-booth-multiplier) shows how the integer core can be made smaller.

    3.5 × (−2.25) moving through the pipeline 1. Sign 0 XOR 1 = 1 2. Exponent 128+128−127=129 3. Multiply 1.75×1.125=1.96875 4. Normalize 1.x, no shift Result: −1.96875 × 2² = −7.875, stored as 0xC0FC0000 CourseTron · coursetron.com
    Animated: the packet visits each stage in turn and the active stage lights up.

    Verification checklist interviewers like

    • Directed tests: 1.0 × 1.0, 1.5 × 1.5 (normalize shift), largest finite × 2 (overflow), smallest normal × 0.5 (underflow), and a rounding tie.
    • Random tests compared bit-for-bit against a C float multiply, which is IEEE-compliant on every mainstream CPU.
    • Set the simulation time unit deliberately; the timescale directive catches many testbench timing surprises.

    If you want a structured path from RTL fundamentals to DSP datapaths, explore our CourseTron courses, and for instructor-led placement-focused VLSI training see ChipXpert.

    Ready to build real datapaths, not just read about them? Join the CourseTron FPGA and Verilog course and implement, simulate and synthesize your own floating-point unit.

    Frequently asked questions

    Why subtract 127 after adding exponents?

    Each stored exponent already includes the bias of 127. Adding two of them includes the bias twice, so one copy is removed to leave a single biased result.

    Can the product need more than one normalization shift?

    No, not for normal inputs. Both significands are in [1, 2), so the product is in [1, 4) and needs at most a one-bit right shift. Subnormal inputs are the exception because they lack the hidden 1.

    Is truncating the low bits acceptable?

    It is cheaper but not IEEE compliant; it biases results downward and can produce errors up to one full ulp. Use round-to-nearest-even with guard and sticky bits for compliance.

    How many DSP slices does a single-precision multiplier use?

    Typically two to four, depending on the FPGA family, since the 24 × 24 significand multiply is wider than one native DSP multiplier.

    Advertisement