Multiplier
Design
The multiplier is a 3-stage pipelined 32×32-bit signed/unsigned multiplier. Instead of implementing a custom shift-and-add state machine, the module relies on the synthesizer to infer DSP slices from the native multiplication expression.
sequenceDiagram
participant Stage1 as Stage 1<br/>(Sign-Extend)
participant Stage2 as Stage 2<br/>(Multiply)
participant Stage3 as Stage 3<br/>(Select Output)
Note over Stage1: rs1_in, rs2_in, multiplier_op_in
Stage1->>Stage1: ext_rs1 = {sign_rs1, rs1_in}<br/>ext_rs2 = {sign_rs2, rs2_in}
Stage1->>Stage2: reg1 values valid
Stage2->>Stage2: product = rs1_reg1 * rs2_reg1<br/>(DSP inference)
Stage2->>Stage3: reg2 values valid
Stage3->>Stage3: case(mul_op):<br/>MUL → product[31:0]<br/>default → product[63:32]
Note over Stage3: result + valid_out
Stage 1: Sign Extension
The 33-bit sign extension depends on the opcode:
| Op | rs1 | rs2 |
|---|---|---|
| MUL | Signed | Signed |
| MULH | Signed | Signed |
| MULHSU | Signed | Unsigned |
| MULHU | Unsigned | Unsigned |
For unsigned operands, the MSB is extended with 0 instead of the sign bit. The extended values are stored in pipeline registers rs1_reg1 and rs2_reg1.
Stage 2: Multiplication
The actual multiplication is expressed natively in HDL:
(* use_dsp = "yes" *) logic signed [65:0] product;
product <= rs1_reg1 * rs2_reg1;
The use_dsp attribute guides the synthesizer to map the multiplication onto DSP48E1 slices. On the XC7A100T, three DSP blocks are inferred for this operation. The multiplication is performed on 33-bit signed values (one bit wider than the inputs to accommodate the sign extension), producing a 66-bit result. The intermediate values are retained in flip-flops for the pipeline.
Stage 3: Output Selection
The final stage selects either the lower or upper 32 bits of the product:
- MUL: returns
product[31:0](the standard 32-bit multiplication result) - MULH / MULHSU / MULHU: returns
product[63:32](the high half, implementing multiply-high)
The 3-cycle latency means the result of a multiplication is available on the third clock cycle after issue. During these cycles, the pipeline is stalled to prevent dependent instructions from reading stale register values.
Verification
The multiplier testbench (rtl/tb_multiplier.sv) uses a dynamic scoreboard queue to handle the pipeline latency. Test vectors include:
- Basic signed and unsigned multiplications with known results
- Edge inputs (zero, one, maximum values, sign flips)
- Hazard chains where MUL results feed directly into subsequent operations
- Full coverage of all four MUL/MULH/MULHSU/MULHU variants