Skip to content
Snippets Groups Projects
matrix_mul.vhd 6.97 KiB
Newer Older
BRONES Romain's avatar
BRONES Romain committed
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library desy;
use desy.ram_tdp;
use desy.math_signed.all;
BRONES Romain's avatar
BRONES Romain committed

library desyrdl;
use desyrdl.pkg_corr_matrixpi.t_mem_MATRIXCOEF_2d_out;
use desyrdl.pkg_corr_matrixpi.t_mem_MATRIXCOEF_2d_in;
BRONES Romain's avatar
BRONES Romain committed

use work.pkg_corr_matrixpi.all;

entity matrix_mul is
    port(
        clk                    : in std_logic;
        rst_n                  : in std_logic;

        -- Coef table, desyrdl
        mm_coef_i              : in t_mem_MATRIXCOEF_2d_out;
        mm_coef_o              : out t_mem_MATRIXCOEF_2d_in;
BRONES Romain's avatar
BRONES Romain committed
        id_cnt_load            : in std_logic_vector(C_W_MM_IDCNT-1 downto 0);

        -- Position data in
        pos_x                  : in signed(C_W_OE-1 downto 0);
        pos_y                  : in signed(C_W_OE-1 downto 0);
BRONES Romain's avatar
BRONES Romain committed
        pos_id                 : in std_logic_vector(C_W_BPMID-1 downto 0);
        pos_seq                : in std_logic_vector(C_W_BPMSEQ-1 downto 0);
        pos_tvalid             : in std_logic;

        -- Data out
        matmult                : out signed_array(0 to C_N_MM_PSC-1)(C_W_MM-1 downto 0);
BRONES Romain's avatar
BRONES Romain committed
        matmult_tvalid         : out std_logic;
        matmult_seq            : out std_logic_vector(C_W_BPMSEQ-1 downto 0)

        );
end entity;

architecture rtl of matrix_mul is

    type arr_slv is array (natural range <>) of std_logic_vector;
    ------------------------
    -- SIGNAL DECLARATION --
    ------------------------
    -- delay registers
    signal r_pos_x    : signed(pos_x'left downto 0);
    signal r_pos_y    : signed(pos_y'left downto 0);
    signal r_seq      : arr_slv(0 to 3)(C_W_BPMSEQ-1 downto 0);
    signal r_tvalid   : std_logic_vector(3 downto 0);
BRONES Romain's avatar
BRONES Romain committed


    -- Accumulators general control
    signal rst_accu     : std_logic;
    signal ena_accu     : std_logic;

    signal id_cnt       : unsigned(C_W_MM_IDCNT-1 downto 0);

    signal new_seq : std_logic;

begin



    ---------------------
    -- DELAY REGISTERS --
    ---------------------
    p_reg:process(clk, rst_n)
    begin
        if rst_n = '0' then
            r_pos_x       <= (others => '0');
            r_pos_y       <= (others => '0');
            r_seq         <= (others => (others => '0'));
            r_tvalid      <= (others => '0');
        elsif rising_edge(clk) then
            r_pos_x         <= pos_x;
            r_pos_y         <= pos_y;

            r_seq(0)        <= pos_seq;
            for I in 1 to r_seq'right loop
                r_seq(I) <= r_seq(I-1);
            end loop;

            r_tvalid        <= r_tvalid(r_tvalid'left-1 downto 0) & pos_tvalid;
        end if;
    end process;

    ena_accu <= r_tvalid(1);

    ----------------
    -- SEQ DETECT --
    ----------------
    new_seq <= '1' when pos_seq /= r_seq(0) else '0';

    ----------------
    -- ID COUNTER --
    ----------------
    p_idcnt:process(clk, rst_n)
    begin
        if rst_n = '0' then
            id_cnt <= (others => '1');
        elsif rising_edge(clk) then
            if id_cnt = 0 then
                id_cnt <= unsigned(id_cnt_load);
            else
                if new_seq= '1' then
                    id_cnt <= unsigned(id_cnt_load);
                else
                    if r_tvalid(0) = '1' then
                        id_cnt <= id_cnt - 1;
                    end if;
                end if;
            end if;
        end if;
    end process;

    ---------------------------
    -- MATRIX MULTIPLICATION --
    ---------------------------
    -- Generate matrix line multiplication, two planes by loop iteration
    G_MATRIX:for I in 0 to C_N_MM_PSC/2 generate
        signal mult_x   : signed(C_W_MM_MULT-1 downto 0);
        signal mult_y   : signed(C_W_MM_MULT-1 downto 0);
        signal accu_x   : signed(C_W_MM_ACCU-1 downto 0);
        signal accu_y   : signed(C_W_MM_ACCU-1 downto 0);
        signal table_coefx  : std_logic_vector(C_W_MM_COEF-1 downto 0);
        signal table_coefy  : std_logic_vector(C_W_MM_COEF-1 downto 0);


    begin

        ------------------------------------------------------------------
        -- COEF TABLES
        inst_coefx_table: entity desy.ram_tdp
        generic map(
            G_ADDR  => C_W_MM_IDCNT,
            G_DATA  => C_W_MM_COEF
        )
        port map(
            pi_clk_a    => clk,
            pi_en_a     => mm_coef_i(2*I).en,
            pi_we_a     => mm_coef_i(2*I).we,
            pi_addr_a   => mm_coef_i(2*I).addr,
            pi_data_a   => mm_coef_i(2*I).data,
            po_data_a   => mm_coef_o(2*I).data,
            pi_clk_b    => clk,
            pi_en_b     => '1',
            pi_we_b     => '0',
            pi_addr_b   => pos_id(C_W_MM_IDCNT-1 downto 0),
            pi_data_b   => (others => '0'),
            po_data_b   => table_coefx
        );

        inst_coefy_table: entity desy.ram_tdp
BRONES Romain's avatar
BRONES Romain committed
        generic map(
            G_ADDR  => C_W_MM_IDCNT,
            G_DATA  => C_W_MM_COEF
        )
        port map(
            pi_clk_a    => clk,
            pi_en_a     => mm_coef_i(2*I+1).en,
            pi_we_a     => mm_coef_i(2*I+1).we,
            pi_addr_a   => mm_coef_i(2*I+1).addr,
            pi_data_a   => mm_coef_i(2*I+1).data,
            po_data_a   => mm_coef_o(2*I+1).data,
            pi_clk_b    => clk,
            pi_en_b     => '1',
            pi_we_b     => '0',
            pi_addr_b   => pos_id(C_W_MM_IDCNT-1 downto 0),
            pi_data_b   => (others => '0'),
            po_data_b   => table_coefy
        );

        ------------------------------------------------------------------
        -- MULT ACCU
        p_multaccu:process(clk, rst_n)
        begin
            if rst_n = '0' then
                mult_x    <= (others => '0');
                accu_x    <= (others => '0');
                mult_y    <= (others => '0');
                accu_y    <= (others => '0');
            elsif rising_edge(clk) then

                mult_x <= r_pos_x * signed(table_coefx);
                mult_y <= r_pos_y * signed(table_coefy);

                if rst_accu = '1' then
                    accu_x    <= (others => '0');
                    accu_y    <= (others => '0');
                elsif ena_accu = '1' then
                    accu_x  <= f_sum_sat(accu_x, mult_x);
                    accu_y  <= f_sum_sat(accu_y, mult_y);
                end if;
            end if;
        end process;

        ------------------------------------------------------------------
        -- ROUND, SATURATE AND MAP RESULT
        p_rndsat:process(clk, rst_n)
        begin
            if rst_n = '0' then
                matmult(2*I)    <= (others => '0');
                matmult(2*I+1)  <= (others => '0');
            elsif rising_edge(clk) then
                matmult(2*I)    <= f_resize_sat(f_resize_lsb(accu_x, C_W_MM_ACCU-C_N_MM_RND), C_W_MM);
                matmult(2*I+1)  <= f_resize_sat(f_resize_lsb(accu_y, C_W_MM_ACCU-C_N_MM_RND), C_W_MM);
            end if;
        end process;
BRONES Romain's avatar
BRONES Romain committed

    end generate;

    --------------------
    -- OUTPUT CONNECT --
    --------------------
    matmult_tvalid   <= r_tvalid(3);
    matmult_seq     <= r_seq(3);
BRONES Romain's avatar
BRONES Romain committed

end architecture;