This repository contains a synthesizable SystemVerilog implementation of a signed 2's complement hardware multiplier, along with its testbench and schematic to better understand its architecture. The two main components are the Control Unit (CU) and the Datapath.
The testbench for the multiplier is located at tb/tb_signed_mul.sv
. You can adjust the test size (i.e., the number of input stimuli) by modifying the test_size
variable within the testbench.
Note: If you change the test_size
variable, ensure you also update the runtime in scripts/simulate.tcl
. Set the runtime to 0.7 * test_size
to ensure proper simulation execution.
Execute the following instructions to simulate the design:
- Open the ModelSim terminal.
- Navigate to the
signed_mul/
directory:cd signed_mul/
- Run the testbench script using the following command:
do ./scripts/simulate.tcl
The architecture of the multiplier is seen in the following figure:
The multiplier is composed of the following components:
- multiplier_reg, pp_upper_reg, pp_lower_reg: 32-bit shift registers
- multiplicand_reg: standard 32-bit register
- mux
- adder/subtractor unit
- CU
We can also see the FSM graph of the control unit here:
The role of each state is explained in the following:
- wait_state: None of the registers are loaded in this state, which reduces switching activity. It waits for the
start
to be asserted. - load: When
start
is asserted, the multiplier and multiplicand registers are loaded with the two operands of the multiplication operation. The two partial product registers are set to 0, and the next state isshift
. - shift: In this state the addition (or subtraction in the last cycle) operation takes place, we either add the multiplicand or 0 to the partial product, depending on the LSB of the multiplier. During the multiplication the state alternates between shift and load_pp after one clock cycle.
- load_pp: After adding the partial product with the multiplicand or 0, it needs to be shifted by one bit to the right, which is why we need this state. After the shift we go back to shift. Since the operands are 32-bit, the multiplier requires 32 shifts. Each shift is followed by an addition, which takes an additional clock cycle. Therefore, the total number of clock cycles is 64.