VHDL code for Matrix multiplication is presented. This VHDL project is aimed to develop and implement a synthesizable matrix multiplier core, which is able to perform matrix calculation for matrices with the size of 32x32.

Each component of the matrices is 16-bit unsigned integer. The core is implemented on Xilinx FPGA Spartan-6 XC6SLX45-CSG324-3. Both behavior and post-route verification are completed. The simulated result is accurately compared to Matlab implementation result.

Block diagram of the design core

The design core is based on the reference design of matrix addition, which input and output buffers are generated by Xilinx Core Generator to save input and output data. The main work is the block to calculate matrix multiplication . Based on the theory of matrix multiplication, the matrix multiplication is done by the following equation:





To calculate cij , during the state of “stReadBufferAB”, we have to read out all 32 columns of row i and 32 the rows of column j, and do multiplication and accumulation like the equation. Furthermore, we add one more state “stSaveData” to the FSM of the reference core which is aimed to save the accumulated data before going to the next state of “stWriteBufferC”.

Block interface of the design core

V HDL top level code for the matrix multiplier:

Verilog projects, VHDL projects -- fpga4student.com FPGA projects -- VHDL project: VHDL code for matrix multiplcation library ieee ; use ieee.std_logic_1164.all ; use ieee.numeric_std.all ; use IEEE.STD_LOGIC_UNSIGNED.ALL ; -- Required entity declaration entity IntMatMulCore is port ( Reset, Clock, WriteEnable, BufferSel : in std_logic ; WriteAddress : in std_logic_vector ( 9 downto 0 ); WriteData : in std_logic_vector ( 15 downto 0 ); ReadAddress : in std_logic_vector ( 9 downto 0 ); ReadEnable : in std_logic ; ReadData : out std_logic_vector ( 63 downto 0 ); DataReady : out std_logic ); end IntMatMulCore ; architecture IntMatMulCore_arch of IntMatMulCore is -- fpga4student.com FPGA projects, Verilog projects, VHDL projects COMPONENT dpram1024x16 PORT ( clka : IN STD_LOGIC ; wea : IN STD_LOGIC_VECTOR ( 0 DOWNTO 0 ); addra : IN STD_LOGIC_VECTOR ( 9 DOWNTO 0 ); dina : IN STD_LOGIC_VECTOR ( 15 DOWNTO 0 ); clkb : IN STD_LOGIC ; enb : IN STD_LOGIC ; addrb : IN STD_LOGIC_VECTOR ( 9 DOWNTO 0 ); doutb : OUT STD_LOGIC_VECTOR ( 15 DOWNTO 0 ) ); END COMPONENT ; -- fpga4student.com FPGA projects, Verilog projects, VHDL projects COMPONENT dpram1024x64 PORT ( clka : IN STD_LOGIC ; wea : IN STD_LOGIC_VECTOR ( 0 DOWNTO 0 ); addra : IN STD_LOGIC_VECTOR ( 9 DOWNTO 0 ); dina : IN STD_LOGIC_VECTOR ( 63 DOWNTO 0 ); clkb : IN STD_LOGIC ; enb : IN STD_LOGIC ; addrb : IN STD_LOGIC_VECTOR ( 9 DOWNTO 0 ); doutb : OUT STD_LOGIC_VECTOR ( 63 DOWNTO 0 ) ); END COMPONENT ; -- fpga4student.com FPGA projects, Verilog projects, VHDL projects type stateType is (stIdle, stWriteBufferA, stWriteBufferB, stReadBufferAB, stSaveData, stWriteBufferC, stComplete); signal presState : stateType; signal nextState : stateType; signal iReadEnableAB, iCountReset,iCountEnable, iCountEnableAB,iCountResetAB : std_logic ; signal iWriteEnableA, iWriteEnableB, iWriteEnableC : std_logic_vector ( 0 downto 0 ); signal iReadDataA, iReadDataB : std_logic_vector ( 15 downto 0 ); signal iWriteDataC : std_logic_vector ( 63 downto 0 ); signal iCount, iReadAddrA, iReadAddrB,iRowA : unsigned( 9 downto 0 ); signal CountAT,CountBT : unsigned( 9 downto 0 ); signal iColB : unsigned( 19 downto 0 ); signal irow,icol,iCountA,iCountB : unsigned( 4 downto 0 ); signal iCountEnableAB_d1,iCountEnableAB_d2,iCountEnableAB_d3 : std_logic ; begin --Write Enable for RAM A iWriteEnableA( 0 ) <= WriteEnable and BufferSel; --Write Enable for RAM B iWriteEnableB( 0 ) <= WriteEnable and ( not BufferSel); -- fpga4student.com FPGA projects, Verilog projects, VHDL projects --Input Buffer A Instance InputBufferA : dpram1024x16 PORT MAP ( clka => Clock, wea => iWriteEnableA, addra => WriteAddress, dina => WriteData, clkb => Clock, enb => iReadEnableAB, addrb => std_logic_vector (iReadAddrA), doutb => iReadDataA ); -- fpga4student.com FPGA projects, Verilog projects, VHDL projects InputBufferB : dpram1024x16 PORT MAP ( clka => Clock, wea => iWriteEnableB, addra => WriteAddress, dina => WriteData, clkb => Clock, enb => iReadEnableAB, addrb => std_logic_vector (iReadAddrB), doutb => iReadDataB ); -- fpga4student.com FPGA projects, Verilog projects, VHDL projects OutputBufferC : dpram1024x64 PORT MAP ( clka => Clock, wea => iWriteEnableC, addra => std_logic_vector (iCount), dina => iWriteDataC, clkb => Clock, enb => ReadEnable, addrb => ReadAddress, doutb => ReadData ); process (Clock,Reset) begin if (rising_edge(Clock)) then if (Reset = '1' ) then iCountEnableAB_d1 <= '0' ; iCountEnableAB_d2 <= '0' ; else iCountEnableAB_d1 <= iCountEnable; iCountEnableAB_d2 <= iCountEnableAB_d1; end if ; end if ; end process ; iCountEnableAB_d3 <= ( not iCountEnableAB_d2) AND iCountEnableAB_d1 ; -- fpga4student.com FPGA projects, Verilog projects, VHDL projects process (Clock) begin if rising_edge (Clock) then if (Reset = '1' ) then iWriteDataC <= ( others => '0' ); elsif (iWriteEnableC( 0 ) = '1' ) then iWriteDataC <= ( others => '0' ); elsif (iCountEnableAB_d3 = '1' ) then iWriteDataC <= ( others => '0' ); elsif (iReadEnableAB = '1' ) then iWriteDataC <= iWriteDataC + std_logic_vector (signed(iReadDataA( 15 ) & iReadDataA) * signed(iReadDataB( 15 ) & iReadDataB)); end if ; end if ; end process ; -- fpga4student.com FPGA projects, Verilog projects, VHDL projects process (Clock) begin if rising_edge (Clock) then if Reset = '1' then presState <= stIdle; iCountA <= ( others => '0' ); iCountB <= ( others => '0' ); else presState <= nextState; if iCountResetAB = '1' then iCountA <= ( others => '0' ); iCountB <= ( others => '0' ); elsif iCountEnableAB = '1' then iCountA <= iCountA + 1 ; iCountB <= iCountB + 1 ; end if ; end if ; if iCountReset = '1' then iCount <= ( others => '0' ); elsif iCountEnable = '1' then iCount <= iCount + 1 ; end if ; end if ; end process ; iRowA <= iCount srl 5 ; iColB <= ( "0000000000" & iCount) - iRowA * 32 ; irow <= iRowA( 4 downto 0 ); icol <= iColB( 4 downto 0 ); CountAT <= "00000" & iCountA; CountBT <= "00000" & iCountB; iReadAddrA <= (iRowA sll 5 ) + CountAT; iReadAddrB <= (CountBT sll 5 ) + iColB( 9 downto 0 ); -- fpga4student.com FPGA projects, Verilog projects, VHDL projects process (presState, WriteEnable, BufferSel, iCount, iCountA, iCountB) begin -- signal defaults iCountResetAB <= '0' ; iCountReset <= '0' ; iCountEnable <= '1' ; iReadEnableAB <= '0' ; iWriteEnableC( 0 ) <= '0' ; Dataready <= '0' ; iCountEnableAB <= '0' ; case presState is when stIdle => if (WriteEnable = '1' and BufferSel = '1' ) then nextState <= stWriteBufferA; else iCountReset <= '1' ; nextState <= stIdle; end if ; when stWriteBufferA => if iCount = x "3FF" then report "Writing A" ; iCountReset <= '1' ; nextState <= stWriteBufferB; else nextState <= stWriteBufferA; end if ; when stWriteBufferB => report "Writing B" ; if iCount = x "3FF" then iCountReset <= '1' ; nextState <= stReadBufferAB; else nextState <= stWriteBufferB; end if ; when stReadBufferAB => iReadEnableAB <= '1' ; iCountEnable <= '0' ; report "CalculatingAB" ; if iCountA = x "1F" and iCountB = x"1F" then nextState <= stSaveData; report "Calculating" ; iCountEnableAB <= '0' ; iCountResetAB <= '1' ; else nextState <= stReadBufferAB; iCountEnableAB <= '1' ; iCountResetAB <= '0' ; end if ; when stSaveData => iReadEnableAB <= '1' ; iCountEnable <= '0' ; nextState <= stWriteBufferC; when stWriteBufferC => iWriteEnableC( 0 ) <= '1' ; report "finish 1 component" ; if iCount = x "3FF" then iCountReset <= '1' ; nextState <= stComplete; else nextState <= stReadBufferAB; end if ; when stComplete => DataReady <= '1' ; nextState <= stIdle; end case ; end process ; end IntMatMulCore_arch ;

Below is the testbench code to read matrix inputs from text files and write the result to an output text file:

-- VHDL project: VHDL code for matrix multiplication -- fpga4student.com FPGA projects, Verilog projects, VHDL projects -- Testbench VHDL code for matrix multiplication library ieee ; use ieee.std_logic_1164.all ; use ieee.std_logic_textio.all ; use ieee.numeric_std.all ; use std.textio.all ; entity tb_IntMatMultCore is end tb_IntMatMultCore ; architecture behavior of tb_IntMatMultCore is component IntMatMulCore port ( Reset, Clock, WriteEnable, BufferSel : in std_logic ; WriteAddress : in std_logic_vector ( 9 downto 0 ); WriteData : in std_logic_vector ( 15 downto 0 ); ReadAddress : in std_logic_vector ( 9 downto 0 ); ReadEnable : in std_logic ; ReadData : out std_logic_vector ( 63 downto 0 ); DataReady : out std_logic ); end component ; signal tb_Reset : std_logic := '0' ; signal tb_Clock : std_logic := '0' ; signal tb_BufferSel : std_logic := '0' ; signal tb_WriteEnable : std_logic := '0' ; signal tb_WriteAddress : std_logic_vector ( 9 downto 0 ) := ( others => '0' ); signal tb_WriteData : std_logic_vector ( 15 downto 0 ) := ( others => '0' ); signal tb_ReadEnable : std_logic := '0' ; signal tb_ReadAddress : std_logic_vector ( 9 downto 0 ) := ( others => '0' ); signal tb_DataReady : std_logic ; signal tb_ReadData : std_logic_vector ( 63 downto 0 ); -- Clock period definitions constant period : time := 100 ns; begin -- fpga4student.com FPGA projects, Verilog projects, VHDL projects -- Instantiate the Unit Under Test (UUT) uut : IntMatMulCore PORT MAP ( Reset => tb_Reset, Clock => tb_Clock, WriteEnable => tb_WriteEnable, BufferSel => tb_BufferSel, WriteAddress => tb_WriteAddress, WriteData => tb_WriteData, ReadEnable => tb_ReadEnable, ReadAddress => tb_ReadAddress, ReadData => tb_ReadData, DataReady => tb_DataReady ); -- Test Bench Statements process is begin --while now <= 10000000000000 * period loop tb_Clock <= '0' ; wait for period / 2 ; tb_Clock <= '1' ; wait for period / 2 ; --end loop; --wait; end process ; process is begin tb_Reset <= '1' ; wait for 10 * period; tb_Reset <= '0' ; wait ; end process ; writingA : process is file FIA : TEXT open READ_MODE is "InputA.txt" ; -- the input file must have 17 rows file FIB : TEXT open READ_MODE is "InputB.txt" ; -- the input file must have 17 rows variable L : LINE; variable tb_MatrixData : std_logic_vector ( 15 downto 0 ); begin tb_WriteEnable <= '0' ; tb_BufferSel <= '1' ; tb_WriteAddress <= "11"&x"FF" ; wait for 20 * period; READLINE(FIA, L); while not ENDFILE(FIA) loop READLINE(FIA, L); HREAD(L, tb_MatrixData); wait until falling_edge(tb_Clock); tb_WriteAddress <= std_logic_vector (unsigned(tb_WriteAddress) + 1 ); tb_BufferSel <= '1' ; tb_WriteEnable <= '1' ; tb_WriteData <= tb_MatrixData; end loop ; READLINE(FIB, L); while not ENDFILE(FIB) loop READLINE(FIB, L); HREAD(L, tb_MatrixData); wait until falling_edge(tb_Clock); tb_WriteAddress <= std_logic_vector (unsigned(tb_WriteAddress) + 1 ); tb_BufferSel <= '0' ; tb_WriteEnable <= '1' ; tb_WriteData <= tb_MatrixData; end loop ; wait for period; tb_WriteEnable <= '0' ; wait ; end process ; -- fpga4student.com FPGA projects, Verilog projects, VHDL projects reading : process is file FO : TEXT open WRITE_MODE is "OutputMultC.txt" ; file FI : TEXT open READ_MODE is "OutputMultC_matlab.txt" ; variable L, Lm : LINE; variable v_ReadDatam : std_logic_vector ( 63 downto 0 ); variable v_OK : boolean ; begin tb_ReadEnable <= '0' ; tb_ReadAddress <= ( others => '0' ); ---wait for Mul done wait until rising_edge(tb_DataReady); wait until falling_edge(tb_DataReady); READLINE(FI, Lm); Write(L, STRING '( "OutputMultC" )); WRITELINE(FO, L); tb_ReadEnable <= '1' ; while not ENDFILE(FI) loop wait until rising_edge(tb_Clock); wait for 20 ns; READLINE(FI, Lm); HREAD(Lm, v_ReadDatam); if v_ReadDatam = tb_ReadData then v_OK := True; report "Matched" ; else v_OK := False; end if ; HWRITE(L, '0' & tb_ReadData, Left, 10 ); WRITE(L, v_OK, Right, 10 ); WRITELINE(FO, L); tb_ReadAddress <= std_logic_vector (unsigned(tb_ReadAddress) + 1 ); end loop ; tb_ReadEnable <= '0' ; assert false report "Simulation Finished" severity failure; -- to stop simulation wait ; end process ; end ;

Behavior Simulation for the matrix multiplication design

After finishing the design of the multiplier core, we carry out the behavior simulation for the core. The testbench is reading input A and B, then produce output C and then compare with Matlab result. If the result is 100% compared to Matlab, data in output file “OutputMultC.txt” will be “true”. Otherwise, it will be false.

Behavior simulation waveform

After 34816 clock cycles, the matrix multiplication for the matrix with size 32x32 is completed and the signal “dataready” is asserted high. It is reasonable because it would take 32 cycles to calculate each matrix component of the output matrix C. There are also 2 cycles which are saving data and writing data to buffer C for each matrix component. Thus, there are 34 clock cycles being used to calculate one component of matrix C. The size of matrix C is 32x32, then we have the matrix multiplication time is 32x32x34 = 34816 cycles. The behavior simulation result is correctly compared to Matlab. In fact, the output file “OutputMultC.txt” is all “true”. We also check the memory content of the buffer output and the results are of course similar to Matlab calculation.