VHDL coding tips and tricks: Synthesizable Matrix Multiplier in VHDL

Saturday, November 28, 2020

Synthesizable Matrix Multiplier in VHDL

    Long back I had posted a simple matrix multiplier which works well in simulation but couldn't be synthesized. But many people had requested for synthesizable version of this code. So here we go.

    The design takes two matrices of 3 by 3 and outputs a matrix of 3 by 3. Each element is stored as unsigned 8 bits. This is not a generic multiplier, but if you watch the video explaining the code, you might be able to extend it to a different sized multiplier. 



    Each matrix has 9 elements, each of which is 8 bits in size. So I am passing the matrix as a 72 bit 1-Dimensional array in the design. The following table shows how the 2-D elements are mapped into the 1-D array.

Row

Column

Bit’s Position in 1-D array

0

0

7:0

0

1

15:8

0

2

23:16

1

0

31:24

1

1

39:32

1

2

47:40

2

0

55:48

2

1

63:56

2

2

71:64


Let me share the codes now...

matrix_mult.vhd:


--3 by 3 matrix multiplier. Each element of the matrix is 8 bit wide. 
--Inputs are called A and B and output is called C. 
--Each matrix has 9 elements each of which is 8 bit wide. So the inputs is 9*8=72 bit long.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all; 

entity matrix_mult is
    port (  Clock: in std_logic; 
            reset : in std_logic;   --active high reset
            start : in std_logic;   --A '1' starts the matrix multiplication process.
            A,B : in unsigned(71 downto 0);
            C : out unsigned(71 downto 0);
            done : out std_logic    --a '1' indicates that multiplication is done and result is availble at C.
            );
end entity;

architecture Behav of matrix_mult is

type matType is array(0 to 2,0 to 2) of unsigned(7 downto 0);
signal matA, matB, matC : matType := (others => (others => X"00"));
type state_type is (init,do_mult,apply_outputs);
signal state : state_type := init;
signal i,j,k : integer := 0;

begin 

sm : process (Clock,reset)    --process implementing the state machine for multiplying the matrices.
variable temp : unsigned(15 downto 0) := (others => '0');
begin
    if(reset = '1') then
        state <= init;
        i <= 0;
        j <= 0;
        k <= 0;
        done <= '0';
        matA <= (others => (others => X"00"));
        matB <= (others => (others => X"00"));
        matC <= (others => (others => X"00"));
    elsif rising_edge(Clock) then
        case state is
            when init =>    --the matrices which are in a 1-D array are converted to 2-D matrices first.
                if(start = '1') then
                    for i in 0 to 2 loop    --run through the rows
                        for j in 0 to 2 loop    --run through the columns
                            matA(i,j) <= A((i*3+j+1)*8-1 downto (i*3+j)*8);
                            matB(i,j) <= B((i*3+j+1)*8-1 downto (i*3+j)*8);
                        end loop;
                    end loop;
                    state <= do_mult;
                end if;
            when do_mult =>
                temp := matA(i,k)*matB(k,j);
                matC(i,j) <= matC(i,j) + temp(7 downto 0);
                if(k = 2) then
                    k <= 0;
                    if(j = 2) then
                        j <= 0;
                        if (i= 2) then
                            i <= 0;
                            state <= apply_outputs;
                        else
                            i <= i + 1;
                        end if;
                    else
                        j <= j+1;
                    end if;        
                else
                    k <= k+1;
                end if;     
            when apply_outputs =>   --convert 3 by 3 matrix into a 1-D matrix.
                for i in 0 to 2 loop    --run through the rows
                    for j in 0 to 2 loop    --run through the columnss
                        C((i*3+j+1)*8-1 downto (i*3+j)*8) <= matC(i,j);
                    end loop;
                end loop;   
                done <= '1';
                state <= init;  
        end case;
    end if;
end process;
 
end architecture;


tb_matrix_mult.vhd:


--Testbench for testing the 3 by 3 matrix multiplier.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all; 

entity tb_matrix_mult is  --testbench entity is always empty. No input or output ports.
end entity;

architecture behav of tb_matrix_mult is

component matrix_mult is
    port (  Clock: in std_logic; 
            reset : in std_logic;   --active high reset
            start : in std_logic;   --A '1' starts the matrix multiplication process.
            A,B : in unsigned(71 downto 0);
            C : out unsigned(71 downto 0);
            done : out std_logic    --a '1' indicates that multiplication is done and result is availble at C.
            );
end component;

signal A,B,C : unsigned(71 downto 0);
signal Clock,reset, start, done : std_logic := '0';
type matType is array(0 to 2,0 to 2) of unsigned(7 downto 0);
signal matC : matType := (others => (others => X"00")); 

begin

matrix_multiplier : matrix_mult port map (Clock, reset, start, A,B, C,done);

--generate a 50Mhz clock for testing the design.
Clk_generator : process
begin
    wait for 10 ns;
    Clock <= not Clock;
end process;

apply_inputs : process
begin
    reset <= '1';
    wait for 100 ns;
    reset <= '0';
    wait for 20 ns;
    A <= X"09" & X"08" & X"07" & X"06" & X"05" & X"04" & X"03" & X"02" & X"01";
    B <= X"01" & X"09" & X"08" & X"07" & X"06" & X"05" & X"04" & X"03" & X"02";
    start <= '1';
    wait for 20 ns;
    start <= '0';
    wait until done = '1';
    --The result C should be (93,150,126,57,96,81,21,42,36)
    wait for 5 ns;
    for i in 0 to 2 loop --run through the rows
        for j in 0 to 2 loop --run through the columnss
            matC(i, j) <= C((i * 3 + j + 1) * 8 - 1 downto (i * 3 + j) * 8);
        end loop;
    end loop;
    wait;
end process;

end behav;


Simulation Results:

    The design was simulated successfully using Modelsim SE 10.4a version. Screenshots of the simulation waveform is shown below:




    Please let me know if you are unable to get the code to work or if its not synthesisable. Good luck with your projects. 

 

1 comment:

  1. How to change this code for the multiplication of 3×3 and 3×1 matrices..Please help

    ReplyDelete