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.
How to change this code for the multiplication of 3×3 and 3×1 matrices..Please help
ReplyDelete