OpenCores
URL https://opencores.org/ocsvn/plasma_fpu/plasma_fpu/trunk

Subversion Repositories plasma_fpu

[/] [plasma_fpu/] [trunk/] [src/] [subunits/] [plasma_mult.vhd] - Rev 2

Compare with Previous | Blame | View Log

-- --------------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<<<<
-- --------------------------------------------------------------------------
-- TITLE:       Plasma MULTIPLICATOR
-- AUTHOR:      Alex Schoenberger (Alex.Schoenberger@ies.tu-darmstadt.de)
-- COMMENT:     This project is based on Plasma CPU core by Steve Rhoads
--
-- www.ies.tu-darmstadt.de
-- TU Darmstadt
-- Institute for Integrated Systems
-- Merckstr. 25
-- 
-- 64283 Darmstadt - GERMANY
-- --------------------------------------------------------------------------
-- PROJECT:       Plasma CPU core with FPU
-- FILENAME:      plasma_mult.vhd
-- --------------------------------------------------------------------------
-- COPYRIGHT: 
--  This project is distributed by GPLv2.0
--  Software placed into the public domain by the author.
--  Software 'as is' without warranty.  Author liable for nothing.
-- --------------------------------------------------------------------------
-- DESCRIPTION:
--    implements multiplication operations depending on instruction code:
--    MULT, DIV, MULTU, DIVU, MTLO, MFLO, MTHI, MFHI
--
--    SYNTHESIZABLE
--
----------------------------------------------------------------------------
-- Revision History
-- --------------------------------------------------------------------------
-- Revision   Date    Author     CHANGES
-- 1.0      4/2014    AS         initial
-- --------------------------------------------------------------------------
library IEEE;
   use IEEE.std_logic_1164.ALL;
   use IEEE.numeric_std.ALL;
 
library PLASMA;
  use PLASMA.mips_instruction_set.ALL;
  use PLASMA.plasma_pack.ALL;
 
entity plasma_mult is
    port(
      control                 : in  t_main_control;
      mult_a_in               : in  t_plasma_word;
      mult_b_in               : in  t_plasma_word;
      mult_func               : in  t_mips_function;
      mult_busy               : out std_logic;
      mult_out                : out t_plasma_word
    );
end entity plasma_mult;
 
-- synthesis translate_off
-- ____ _ _  _ _  _ _    ____ ___ _ ____ _  _ 
-- [__  | |\/| |  | |    |__|  |  | |  | |\ | 
-- ___] | |  | |__| |___ |  |  |  | |__| | \| 
architecture sim_mult of plasma_mult is
 
   signal reg_mult      : t_plasma_dword;
   signal i_reg_mult    : t_plasma_dword;
 
begin
 
  process( control.clk )
 
    variable a_in_sig     :   signed(PLASMA_DATA_WIDTH - 1 downto 0);
    variable b_in_sig     :   signed(PLASMA_DATA_WIDTH - 1 downto 0);   
 
    variable a_in_uns     : unsigned(PLASMA_DATA_WIDTH - 1 downto 0);
    variable b_in_uns     : unsigned(PLASMA_DATA_WIDTH - 1 downto 0);
 
  begin
 
    if falling_edge( control.clk ) then                         -- avoid spurious division by zero
 
    -- default values
    i_reg_mult <= reg_mult;
    mult_out      <= PLASMA_ZERO_WORD;
 
    -- operation mux
    case mult_func is
        when MIPS_FUNC_MFLO       => 
              mult_out      <= reg_mult(  PLASMA_DATA_WIDTH  - 1 downto                 0);
        when MIPS_FUNC_MFHI       => 
              mult_out      <= reg_mult(2*PLASMA_DATA_WIDTH  - 1 downto PLASMA_DATA_WIDTH);
        when MIPS_FUNC_MTLO      => 
              i_reg_mult <= reg_mult(2*PLASMA_DATA_WIDTH  - 1 downto PLASMA_DATA_WIDTH) & mult_a_in;
        when MIPS_FUNC_MTHI      => 
              i_reg_mult <= mult_a_in & reg_mult(PLASMA_DATA_WIDTH - 1 downto 0);
 
        when MIPS_FUNC_MULTU => 
 
              a_in_uns := unsigned(mult_a_in);
              b_in_uns := unsigned(mult_b_in);
 
              i_reg_mult <= std_logic_vector(a_in_uns * b_in_uns);
 
        when MIPS_FUNC_MULT   => 
              a_in_sig :=   signed(mult_a_in);
              b_in_sig :=   signed(mult_b_in);
 
              i_reg_mult <= std_logic_vector(a_in_sig * b_in_sig);
 
        when MIPS_FUNC_DIVU  => 
 
              a_in_uns := unsigned(mult_a_in);
              b_in_uns := unsigned(mult_b_in);
 
              assert ( b_in_uns /= 0) report "ERROR:Division by zero!" severity failure;
 
              i_reg_mult(  PLASMA_DATA_WIDTH - 1 downto                 0) <= std_logic_vector(a_in_uns  /  b_in_uns);
              i_reg_mult(2*PLASMA_DATA_WIDTH - 1 downto PLASMA_DATA_WIDTH) <= std_logic_vector(a_in_uns mod b_in_uns);
 
        when MIPS_FUNC_DIV    => 
 
              a_in_sig :=   signed(mult_a_in);
              b_in_sig :=   signed(mult_b_in);
 
              assert ( b_in_sig /= 0) report "ERROR:Division by zero!" severity failure;
 
              i_reg_mult(  PLASMA_DATA_WIDTH - 1 downto                 0) <= std_logic_vector(a_in_sig  /  b_in_sig);
              i_reg_mult(2*PLASMA_DATA_WIDTH - 1 downto PLASMA_DATA_WIDTH) <= std_logic_vector(a_in_sig mod b_in_sig);
 
        when others                    =>
      end case;
      end if;
   end process;
 
 
   process( control.clk )
   begin
      if rising_edge( control.clk ) then
         if control.rst = '1' then
            reg_mult <= (others => '0');
         else
            reg_mult <= i_reg_mult;
         end if;
      end if;
   end process;
 
   mult_busy <= '0';
 
end architecture sim_mult;
-- synthesis translate_on
 
 
library MUL;
 
-- ____ ___  ____ ____ 
-- |___ |__] | __ |__| 
-- |    |    |__] |  | 
architecture FPGA_mult of plasma_mult is
 
  -- ____ ___  ____ ____ ____ ___ _ ____ _  _    ____ ____ ____ ____ ____ 
  -- |  | |__] |___ |__/ |__|  |  | |  | |\ |    |    |  | |__/ |___ [__  
  -- |__| |    |___ |  \ |  |  |  | |__| | \|    |___ |__| |  \ |___ ___] 
  --
  -- multiplication
  --
  component mul_core is
  port(
    clk               : in  std_logic;
    rst               : in  std_logic;
 
    start             : in  std_logic;
    busy              : out std_logic;
    rdy               : out std_logic;
 
    sign_flag         : in  std_logic;
 
    a                 : in  std_logic_vector(31 downto 0);
    b                 : in  std_logic_vector(31 downto 0);
 
    c                 : out std_logic_vector(63 downto 0)
  );
  end component mul_core;
 
  --
  -- division
  --
  component div_core is
  port(
    clk               : in  std_logic;
    rst               : in  std_logic;
 
    start             : in  std_logic;
    busy              : out std_logic;
    rdy               : out std_logic;
 
    sign_flag         : in  std_logic;
 
    a                 : in  std_logic_vector(31 downto 0);
    b                 : in  std_logic_vector(31 downto 0);
 
    c                 : out std_logic_vector(31 downto 0);
    r                 : out std_logic_vector(31 downto 0)
  );
  end component div_core;
 
  --
  -- control
  --
  type t_core_ctrl is
    record
      -- start             : std_logic;       -- ModelSIM cannot handle different directions in a record
      busy              : std_logic;
      rdy               : std_logic;
    end record;
 
  signal c_mul          : t_core_ctrl;
  signal c_div          : t_core_ctrl;
 
  signal mul_start      : std_logic;
  signal div_start      : std_logic;
 
  signal sign_flag      : std_logic;
 
  --
  -- calculated data
  --
  signal mul_data       : t_plasma_dword;
  signal div_data       : t_plasma_dword;
 
  -- ____ ___ ____ ___ ____    _  _ ____ ____ _  _ _ _  _ ____ 
  -- [__   |  |__|  |  |___    |\/| |__| |    |__| | |\ | |___ 
  -- ___]  |  |  |  |  |___    |  | |  | |___ |  | | | \| |___ 
  type t_mult_state is ( s_IDLE, s_BUSY );
 
  signal i_state, state : t_mult_state;
 
  signal i_start        : std_logic;
  signal flag_div       : std_logic;
 
 
  -- _  _ ____ _ _  _    ____ ____ ____ _ ____ ___ ____ ____ 
  -- |\/| |__| | |\ |    |__/ |___ | __ | [__   |  |___ |__/ 
  -- |  | |  | | | \|    |  \ |___ |__] | ___]  |  |___ |  \ 
  type t_mul_reg_sel is (
      MUL_REG_STORE,                            -- stored value
      MUL_REG_LO,                               -- LO data from PLASMA
      MUL_REG_HI,                               -- HI data from PLASMA
      MUL_REG_MUL,                              -- data from multiplier core
      MUL_REG_DIV                               -- data from divisor core
    );
 
  signal mul_reg_sel    : t_mul_reg_sel;
 
  --
  -- main register
  --
  signal reg_en         : std_logic;
  signal reg_mult       : t_plasma_dword;
  signal i_reg_mult     : t_plasma_dword;
 
  --
  -- function
  --
  signal i_busy         : std_logic;
  signal func_en        : std_logic;
  signal i_mult_func    : t_mips_function;
  signal reg_mult_func  : t_mips_function;
 
  -- ____ _  _ ___ ___  _  _ ___ 
  -- |  | |  |  |  |__] |  |  |  
  -- |__| |__|  |  |    |__|  |  
  --
  -- output mux
  --
  type t_mul_out_sel is (
      MUL_OUT_HI,                               -- HI word
      MUL_OUT_LO,                               -- LO word
      MUL_OUT_MUL,                              -- from MUL core
      MUL_OUT_DIV                               -- from DIV core
    );
 
  signal mul_out_sel    : t_mul_out_sel;
 
begin
  -- ____ ___  ____ ____ ____ ___ _ ____ _  _    ____ ____ ____ ____ ____ 
  -- |  | |__] |___ |__/ |__|  |  | |  | |\ |    |    |  | |__/ |___ [__  
  -- |__| |    |___ |  \ |  |  |  | |__| | \|    |___ |__| |  \ |___ ___] 
  mult_core_unit: entity MUL.mul_core
  PORT MAP( 
    clk       => control.clk,     rst => control.rst,
    start     => mul_start,
    busy      => c_mul.busy,      rdy => c_mul.rdy,
    sign_flag => sign_flag,
 
    a         => mult_a_in,       b   => mult_b_in,
    c         => mul_data
  );
 
  div_core_unit: entity MUL.div_core
  PORT MAP(
    clk       => control.clk,     rst => control.rst,
    start     => div_start,
    busy      => c_div.busy,      rdy => c_div.rdy,
    sign_flag => sign_flag,
 
    a         => mult_a_in,       b   => mult_b_in,
    c         => div_data(31 downto 0),
    r         => div_data(63 downto 32)
  );
 
  -- ___  ____ ____ ____ ___  ____ ____ 
  -- |  \ |___ |    |  | |  \ |___ |__/ 
  -- |__/ |___ |___ |__| |__/ |___ |  \ 
  --
  -- intern busy indicates calculation till ready is set
  --
  i_busy                <= (c_mul.busy or c_div.busy) and (not c_mul.rdy) and (not c_div.rdy);
 
  --
  -- store function till calculation is finished
  --
  i_mult_func           <= reg_mult_func when state = s_BUSY else mult_func;
 
  --
  -- signed calculation
  --
  sign_flag             <= '1' when (i_mult_func = MIPS_FUNC_MULT) or
                                    (i_mult_func = MIPS_FUNC_DIV)       
                                                                      else '0';
 
  --
  -- decode command
  --
  mult_decode:
  process( i_mult_func, c_mul.rdy, c_div.rdy )
  begin
    -- ############## DEFAULT VALUES
    reg_en              <= '0';             -- no register store
    mul_reg_sel         <= MUL_REG_STORE;   -- stored value remains
 
    mul_out_sel         <= MUL_OUT_LO;      -- LO word
 
    --
    -- state machine control
    --
    i_start             <= '0';             -- no calculation
    flag_div            <= '0';             -- multiplication is default
 
    -- operation mux
    case i_mult_func is
        when MIPS_FUNC_MFLO   => 
 
        when MIPS_FUNC_MFHI   =>               
              mul_out_sel       <= MUL_OUT_HI;
 
        when MIPS_FUNC_MTLO   => 
              mul_reg_sel       <= MUL_REG_LO;
              reg_en            <= '1';
 
        when MIPS_FUNC_MTHI   => 
              mul_reg_sel       <= MUL_REG_HI;
              reg_en            <= '1';
 
        when MIPS_FUNC_MULTU |
             MIPS_FUNC_MULT   => 
              i_start           <= '1';
 
              reg_en            <= c_mul.rdy;
              mul_reg_sel       <= MUL_REG_MUL;
 
        when MIPS_FUNC_DIVU  |
             MIPS_FUNC_DIV    => 
              i_start           <= '1';
              flag_div          <= '1';
 
              reg_en            <= c_div.rdy;
              mul_reg_sel       <= MUL_REG_DIV;
 
        when others            =>
      end case;
   end process;  
 
  -- ____ ___ ____ ___ ____    _  _ ____ ____ _  _ _ _  _ ____ 
  -- [__   |  |__|  |  |___    |\/| |__| |    |__| | |\ | |___ 
  -- ___]  |  |  |  |  |___    |  | |  | |___ |  | | | \| |___ 
  --
  -- start calculation units and store function
  --
  mult_state:
  process( state, i_start, flag_div, i_busy )
  begin
    -- ############ DEFAULT VALUES
    --
    -- calculations units control
    --
    mul_start           <= '0';             -- mul core inactive
    div_start           <= '0';             -- div core inactive
 
    --
    -- function store
    --
    func_en             <= '0';             -- no function store
 
    --
    -- next state
    --
    i_state             <= s_IDLE;          -- remain in IDLE
 
    -- ############ STATE LOGIC
    case state is
      when s_IDLE   => if i_start = '1' then
 
                        mul_start   <= not flag_div;
                        div_start   <= flag_div;
 
                        func_en     <= '1';   -- store function
 
                        i_state     <= s_BUSY;
                       end if;
 
      when s_BUSY   => if i_busy = '1' then
                        i_state     <= s_BUSY;
                       end if;
      when others   =>
    end case;
  end process;
 
  -- _  _ ____ _ _  _    ____ ____ ____ _ ____ ___ ____ ____ 
  -- |\/| |__| | |\ |    |__/ |___ | __ | [__   |  |___ |__/ 
  -- |  | |  | | | \|    |  \ |___ |__] | ___]  |  |___ |  \ 
  --
  -- select next input
  --
  with mul_reg_sel select
    i_reg_mult        <= reg_mult(2*PLASMA_DATA_WIDTH  - 1 downto PLASMA_DATA_WIDTH) & mult_a_in  when MUL_REG_LO,
                         mult_a_in & reg_mult(PLASMA_DATA_WIDTH - 1 downto 0)                     when MUL_REG_HI,
                         mul_data                                                                 when MUL_REG_MUL,
                         div_data                                                                 when MUL_REG_DIV,
                         reg_mult                                                                 when others;
 
  mult_register:
  process( control.clk )
  begin
    if rising_edge( control.clk ) then
      if control.rst = '1' then
        reg_mult          <= (others => '0');
 
        reg_mult_func     <= MIPS_FUNC_MFLO;
 
        state             <= s_IDLE;
      else
        if reg_en = '1' then
          reg_mult        <= i_reg_mult;
        end if;
 
        if func_en = '1' then
          reg_mult_func   <= mult_func;
        end if;
 
        state             <= i_state;           -- always active
      end if;
    end if;
  end process;
 
  -- ____ _  _ ___ ___  _  _ ___ 
  -- |  | |  |  |  |__] |  |  |  
  -- |__| |__|  |  |    |__|  | 
  --
  -- busy indication
  --
  -- mult_busy           <= c_mul.busy or c_div.busy;
  mult_busy           <= i_busy;      -- 1 clock cycle is necessary for change from ID to EX stage
 
  --
  -- data output
  --
  with mul_out_sel select
    mult_out          <= reg_mult(  PLASMA_DATA_WIDTH - 1 downto                 0) when MUL_OUT_LO,
                         reg_mult(2*PLASMA_DATA_WIDTH - 1 downto PLASMA_DATA_WIDTH) when others;
 
end architecture FPGA_mult;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.