It's been quite some time since I last posted. Amidst this crazy pandemic, I found some time to blog.

This post is about simple VHDL code to model a 4-Bit Binary multiplier.

There are two ways to write a code for this-

- Structural modeling (using Dataflow modeling)
- Behavioral modeling

The first approach requires you to understand the logic diagram of a 4-bit binary multiplier and requires gate-to-gate mapping which is a tedious task. The latter is a rather smart way to code wherein you let the software choose the right gates and components, while you write a general code.

This is the diagram I'm talking about. Needless to say, it makes sense to write a code that doesn't use this diagram i.e behavioral modeling.

To start with here's a basic code that does exactly what we want.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity multiplier_4bit is
port
(
num1, num2: in std_logic_vector(3 downto 0);
ans: out std_logic_vector(7 downto 0)
);
end entity multiplier_4bit;
architecture Behavioral of multiplier_4bit is
begin
ans <= std_logic_vector(unsigned(num1) * unsigned(num2));
end architecture Behavioral;

It doesn't get easier than this. The code is pretty compact and simple, all thanks to one library we've imported- IEEE.NUMERIC_STDThis library provides one powerful datatype called 'unsigned', which is similar to std_logic_vector and contains several overloaded definitions for addition, subtraction, multiplication etc between two unsigned numbers.

ans <= std_logic_vector(unsigned(num1) * unsigned(num2));

This is the line where we unleash(!) the power of the unsigned datatype by typecasting the two std_logic_vector inputs to unsigned. We multiply the two unsigned numbers and then again convert the result to std_logic_vector datatype.

But for such a task importing an entire library may be an overkill, so can we get rid of 'unsigned' and the library itself and write our own functions instead?Yep, we can, and it's easier done than said. Here's the code to achieve the same functionality without using a library-
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity multiplier_4bit is
port
(
num1, num2: in std_logic_vector(3 downto 0);
ans: out std_logic_vector(7 downto 0)
);
end entity multiplier_4bit;
architecture Behavioral of multiplier_4bit is
----------------------------------------------------------------------------------

-----------------------------------Functions------------------------------------------------
-- The function that converts vector to int
function vector_to_int (A : std_logic_vector) return integer is variable answer : integer;
begin
answer := 0;
for I in 0 to A'length-1 loop
if (A(I) = '1') then
answer:= answer + (2 ** I);
else
next;
end if;
end loop;
return answer;
end vector_to_int;
--function to convert to int to vector
function int_to_vector (A : integer) return std_logic_vector is variable answer : std_logic_vector(7 downto 0);
variable dividend : integer :=A;
variable remainder : integer :=0;
begin
answer:= "00000000";
for index in 0 to 7 loop
remainder := dividend mod 2;
if (remainder = 1) then
answer(index) := '1';
else
answer(index) := '0';
end if;
dividend:= dividend - remainder;
dividend := dividend/2;
end loop;
return answer;
end int_to_vector;

`---------------------------------------------------------------------------------`

----------------------------end of function declarations-------------------------
begin
ans <= std_logic_vector(int_to_vector(vector_to_int(num1) * vector_to_int(num2)));
end architecture Behavioral;

Notice that, we're no longer using the NUMERIC_STD library and if you remove the code between the dashes(------), it's almost the same as the previous code, just that we've created two new functions-

- vector_to_int (std_logic_vector) --> Converts a std_logic_vector to integer.
- int_to_vector (integer) --> Converts an integer to an 8-bit std_logic_vector.

In VHDL functions are written in the declarative part of the architecture (which is the part of the code enclosed between lots of dashes ---------).Lets quickly look at how the functions work.

The first one that converts a std_logic_vector to an integer, follows the basic method in which you convert a binary number to decimal.

The function to do this is pretty straightforward and follows the explanation above. Convince yourself that the function below is doing exactly what the image above explains.

function vector_to_int (A : std_logic_vector) return integer is variable answer : integer;
begin
answer := 0;
for I in 0 to A'length-1 loop
if (A(I) = '1') then
answer:= answer + (2 ** I);
else
next;
end if;
end loop;
return answer;
end vector_to_int;

Now, the second function that converts an integer to std_logic_vector follows the repeated- remainder method to convert decimal to binary.

This is the exact concept that is implemented into the code-

function int_to_vector (A : integer) return std_logic_vector is variable answer : std_logic_vector(7 downto 0);
variable dividend : integer :=A;
variable remainder : integer :=0;
begin
answer:= "00000000";
for index in 0 to 7 loop
remainder := dividend mod 2;
if (remainder = 1) then
answer(index) := '1';
else
answer(index) := '0';
end if;
dividend:= dividend - remainder;
dividend := dividend/2;
end loop;
return answer;
end int_to_vector;

That's all for the functions!

ans <= std_logic_vector(int_to_vector(vector_to_int(num1) * vector_to_int(num2)));

Finally, it boils down to calling the two functions correctly to multiply two numbers.

By replacing the '*' operator to '+', '-' or a series of operations in the line above, we can easily modify the code to perform addition, subtraction, etc.

Here's the code for a simple testbench that prints the multiplication table of 5.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity multiplier_4bit_tb is
-- Port ( );
end multiplier_4bit_tb;
architecture Behavioral of multiplier_4bit_tb is
component multiplier_4bit
port(
num1, num2: in std_logic_vector(3 downto 0);
ans: out std_logic_vector(7 downto 0)
);
end component;
signal num1 : std_logic_vector(3 downto 0);
signal num2 : std_logic_vector(3 downto 0);
signal ans : std_logic_vector(7 downto 0);
begin
utt: multiplier_4bit port map(
num1=>num1,
num2=>num2,
ans=>ans
);
stimulus: process
begin
for v in 1 to 10 loop
num1<= std_logic_vector(to_unsigned(5,4));
num2<= std_logic_vector(to_unsigned(v,4));
wait for 10 ns;
end loop;
wait;
end process;
end Behavioral;

I hope I've done justice in explaining my approach to code a 4-bit multiplier!

Cheers,Siddharth

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity multiplier_4bit is port ( num1, num2: in std_logic_vector(3 downto 0); ans: out std_logic_vector(7 downto 0) ); end entity multiplier_4bit; architecture Behavioral of multiplier_4bit is begin ans <= std_logic_vector(unsigned(num1) * unsigned(num2)); end architecture Behavioral;

ans <= std_logic_vector(unsigned(num1) * unsigned(num2));

This is the line where we unleash(!) the power of the unsigned datatype by typecasting the two std_logic_vector inputs to unsigned. We multiply the two unsigned numbers and then again convert the result to std_logic_vector datatype.

library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity multiplier_4bit is port ( num1, num2: in std_logic_vector(3 downto 0); ans: out std_logic_vector(7 downto 0) ); end entity multiplier_4bit; architecture Behavioral of multiplier_4bit is ----------------------------------------------------------------------------------

-----------------------------------Functions------------------------------------------------ -- The function that converts vector to int function vector_to_int (A : std_logic_vector) return integer is variable answer : integer; begin answer := 0; for I in 0 to A'length-1 loop if (A(I) = '1') then answer:= answer + (2 ** I); else next; end if; end loop; return answer; end vector_to_int; --function to convert to int to vector function int_to_vector (A : integer) return std_logic_vector is variable answer : std_logic_vector(7 downto 0); variable dividend : integer :=A; variable remainder : integer :=0; begin answer:= "00000000"; for index in 0 to 7 loop remainder := dividend mod 2; if (remainder = 1) then answer(index) := '1'; else answer(index) := '0'; end if; dividend:= dividend - remainder; dividend := dividend/2; end loop; return answer; end int_to_vector;

`---------------------------------------------------------------------------------`

----------------------------end of function declarations------------------------- begin ans <= std_logic_vector(int_to_vector(vector_to_int(num1) * vector_to_int(num2))); end architecture Behavioral;

- vector_to_int (std_logic_vector) --> Converts a std_logic_vector to integer.
- int_to_vector (integer) --> Converts an integer to an 8-bit std_logic_vector.

function vector_to_int (A : std_logic_vector) return integer is variable answer : integer; begin answer := 0; for I in 0 to A'length-1 loop if (A(I) = '1') then answer:= answer + (2 ** I); else next; end if; end loop; return answer; end vector_to_int;

function int_to_vector (A : integer) return std_logic_vector is variable answer : std_logic_vector(7 downto 0); variable dividend : integer :=A; variable remainder : integer :=0; begin answer:= "00000000"; for index in 0 to 7 loop remainder := dividend mod 2; if (remainder = 1) then answer(index) := '1'; else answer(index) := '0'; end if; dividend:= dividend - remainder; dividend := dividend/2; end loop; return answer; end int_to_vector;

ans <= std_logic_vector(int_to_vector(vector_to_int(num1) * vector_to_int(num2)));

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use ieee.numeric_std.all; entity multiplier_4bit_tb is -- Port ( ); end multiplier_4bit_tb; architecture Behavioral of multiplier_4bit_tb is component multiplier_4bit port( num1, num2: in std_logic_vector(3 downto 0); ans: out std_logic_vector(7 downto 0) ); end component; signal num1 : std_logic_vector(3 downto 0); signal num2 : std_logic_vector(3 downto 0); signal ans : std_logic_vector(7 downto 0); begin utt: multiplier_4bit port map( num1=>num1, num2=>num2, ans=>ans ); stimulus: process begin for v in 1 to 10 loop num1<= std_logic_vector(to_unsigned(5,4)); num2<= std_logic_vector(to_unsigned(v,4)); wait for 10 ns; end loop; wait; end process; end Behavioral;

## Comments

## Post a Comment