The module "multiply_sd"
a VHDL implementation of a multiplication algorithm using signed digit adders

The VHDL module "multiply_sd" (see symbol) calculates the signed product of a multiplicand and a multiplier.

It uses the "Ordinary Signed Digit" redundant number system as described in
IEEE TRANSACTIONS ON COMPUTERS, VOL. 39, NO. I, JANUARY 1990
Generalized Signed-Digit Number Systems:
A Unifying Framework for Redundant Number Representations
BEHROOZ PARHAMI, SENIOR MEMBER, IEEE

Using signed-digit adders has the advantage that an addition can be implemented with a carry propagation only
to the next sum digit but not to any other sum digit.

The internal operands are not numbers coded in bits, but numbers coded in digits.
As a radix 4 redundant number system is used, the digits can have a value
from -3 to +3 (in 2's complement coding): "101", "110", "111", "000", "001", "010" or "011".

Using the signed-digit adders causes a circuit structure where the timing does not depend on the width of the
operands, but only depends on the number of consecutive additions which are executed in one clock period.
The module "multiply_sd" has a better timing than the modules "multiply" and "multiply_bsc" also available from this web site.
The module "multiply_sd" has a worse timing than the modules "multiply_cs" and "multiply_wt" also available from this web site.

Note that if you are using an advanced synthesis tool such as Synopsys Design Compiler Ultra,
the module "multiply_sd" design may not give a better timing than the "multiply" design.
Design Compiler Ultra already uses advanced arithmetic optimisations that implement fast addition structures.

The number of bits of multiplicand and multiplier are configured by generics.
Product, multiplicand and multiplier are numbers in 2's complement format.
The module uses flipflops only for storing the product (and for controlling).
For quick access to the multiplier bits, the multiplier is first stored in the product flipflops and
then replaced by the upcoming product bits through shift operations.
The latency of the module can be configured by a generic independently from the width of the operands.

This means, the module is configurable by generics in order

But of course there is no guarantee that timing closure can be reached with the selected values
for the generics, as the timing depends on the technology which is used at synthesis.

The module "multiply_sd" was developed with HDL-SCHEM-Editor.

Ports:

Port name Direction Description
res_i input asynchronous reset input, 1-active
Can be clamped to 0 when g_latency=0.
clk_i input clock input
Can be clamped to 0 when g_latency=0.
start_i input This input expects an 1-active impulse of 1 clock cycle width in order to start the calculation.
When g_latency=0 then back to back pulses can be used.
multiplicand_i(g_multiplicand_width-1:0) input Signed multiplicand (g_multiplicand_width is a generic).
The input must be stable during the calculation.
multiplier_i(g_multiplier_width-1:0) input Signed multiplier (g_multiplier_width is a generic).
The input is latched at start=1 and can be changed afterwards.
ready_o output 1-active impulse of 1 clock cycle width, when the calculation is ready (at latency 0 it gets active in the same clock cycle in which start_i gets active).
product_o(g_multiplicand_width+g_multiplier_width-1:0) output Signed product. Valid at ready_o=1. Not stable during calculation.

Generics:

Generic name Minimum Value Maximum Value Description
g_multiplicand_width 2 none Number of bits of the multiplicand
The first bit represents the sign as the operands have to be coded in 2's complement.
g_multiplier_width 2 none Number of bits of the multiplier
The first bit represents the sign as the operands have to be coded in 2's complement.
g_latency_mul 0 none Latency of the multiplication algorithm in clock cycles
When g_latency_mul is 0, then the multiplication is a combinatorial design.
g_latency_convert 0 1 Latency of the submodule multiply_sd_convert in clock cycles
This module converts the product from a signed-digit number into a 2's complement number.
When g_latency_convert is 0, then multiply_sd_convert is a combinatorial design.

The module "multiply_sd" is a hierarchical module, which is built by 4 submodules.

Submodule name Functionality
multiply_sd_package

The package multiply_sd_package contains all needed type definitions and functions to handle "signed-digit" numbers.

multiply_sd_prepare

The "multiply_sd_prepare" submodule converts the multiplicand into a signed-digit number and calculates 2 times and 3 times the multiplicand.

The "multiply_sd_prepare" submodule is a combinatorial submodule.

multiply_sd_step

The "multiply_sd_step" submodule processes 1 digit (= 2 bits) of the multiplier.
The submodule is instantiated as many times as multiplier digits are processed during a clock
cycle (which depends on the generic g_latency_mul).

Depending on the multiplier digit processed, the multiplicand is added 3 times, 2 times, 1 times or 0 times to the partial product.

If the processed multiplier digit is the sign digit and has a value of 0, then 0 is added to the partial product.
If the processed multiplier digit is the sign digit and has a value of 1, then the multiplicand is subtracted from the partial product.
This subtraction compensates for the error of treating the digits of the negative multiplier as if the multiplier were positive.

multiply_sd_convert

The "multiply_sd_convert" submodule converts the product from a signed-digit number into a 2's complement number.

If g_latency_convert=0 then the "multiply_sd_convert" submodule is a combinatorial design.
Otherwise the "multiply_sd_convert" submodule will use a register to store the converted product,
in order to relax the timing at the product_o output.

multiply_sd_control

The multiply_sd_control submodule generates all the control signals which are needed.
It enables the internal registers for the intermediate or final results.
It identifies the clock period in which the sign digit of the multiplier is handled.
It activates the ready_o output at the end of the calculation.

There are no limitations for the generics g_multiplicand_width and g_multiplier_width (except that they must be bigger than 1).
These generics are most of the time determined by the environment, where the module multiply_sd is used.

There is also no limitation for the generic g_latency_mul. But this generic determines not only the latency but also
how difficult it will be to reach timing closure: The smaller the value is chosen, the harder it will be to reach timing closure.

The multiplier is converted into a signed digit number. The number of digits which are created can be calculated by
digits_to_process = g_multiplier_width/2+1 (integer division).

If g_latency_mul is equal to g_multiplier_width/2 (integer division), then one digit of the multiplier is processed in each clock cycle,
except for the first clock cycle, which always processes one digit more than each other.

If g_latency_mul is smaller than g_multiplier_width/2 (integer division), then more than 1 digit of the multiplier is processed in each clock cycle.
The number of digits processed in one cycle can be calculated by rounding up (digits_to_process-1)/g_latency_mul to the next integer.

If g_latency_mul is greater than g_multiplier_width/2 (integer division), then the number of digits of the multiplier is increased to g_latency_mul+1.
Again 1 digit of the (extended) multiplier is processed in each clock cycle.
This, of course, leads to an internal product register with the same additional number of digits as the multiplier.

symbol symbol symbol symbol symbol symbol symbol

Source code for HDL-SCHEM-Editor and HDL-FSM-Editor for module "multiply_sd" and its testbench (Number of downloads = 130 ).
With these files the schematics and the state-diagram of module multiply_sd can be loaded into HDL-SCHEM-Editor or HDL-FSM-Editor and can be easily read and modified:

All module VHDL-files of the module "multiply_sd" (Number of downloads = 117 ).
These files were generated by HDL-SCHEM-Editor and HDL-FSM-Editor:

All testbench VHDL-files of the module "multiply_sd" (Number of downloads = 114 ).
These files were generated by HDL-SCHEM-Editor and HDL-FSM-Editor:

Relocation hints:

You should extract all archives into a folder named "multiply_sd".

Then you should load the toplevel (probably the testbench) into HDL-SCHEM-Editor.
When you navigate through the design hierarchy by a double click at each symbol,
HDL-SCHEM-Editor will find the submodules on your disk and ask if it can replace
the original path to the submodule by the new one at your disk.
After storing the changed modules the relocation of the source files is ready
(instead you could replace "M:/gesicherte Daten/Programmieren/VHDL/multiply_sd" in all
"hdl_editor_designs/*.hse" source files by your path to this directory with your editor).

Now you can navigate through the design by HDL-SCHEM-Editor and generate HDL by HDL-SCHEM-Editor for
all modules except multiply_sd_control, for which the HDL must be generated by HDL-FSM-Editor.
Of course there is only need for generating HDL, if you change something at the modules,
because you can find the HDL in VHDL_designs.zip and VHDL_testbenches.zip.

If you want to simulate or modify the modules by HDL-SCHEM-Editor you also must adapt the information in the Control-tab of the toplevel you want to work on.
There you must define a "Compile through hierarchy command", an "Edit command", the path to your HDL-FSM-Editor and a "Working directory".

Change log:

Version 1.0 (16.05.2025):

If you detect any bugs or have any questions,
please send a mail to "matthias.schweikart@gmx.de".