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

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [rtl/] [core/] [neorv32_cpu_alu.vhd] - Diff between revs 34 and 36

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 34 Rev 36
Line 1... Line 1...
-- #################################################################################################
-- #################################################################################################
-- # << NEORV32 - Arithmetical/Logical Unit >>                                                     #
-- # << NEORV32 - Arithmetical/Logical Unit >>                                                     #
-- # ********************************************************************************************* #
-- # ********************************************************************************************* #
-- # Main data and address ALU. Includes comparator unit and co-processor interface/arbiter.       #
-- # Main data and address ALU. Includes comparator unit and co-processor interface/arbiter.       #
-- # The shifter sub-unit uses an iterative approach.                                              #
 
-- # ********************************************************************************************* #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License                                                                          #
-- # BSD 3-Clause License                                                                          #
-- #                                                                                               #
-- #                                                                                               #
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved.                                     #
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved.                                     #
-- #                                                                                               #
-- #                                                                                               #
Line 58... Line 57...
    pc2_i       : in  std_ulogic_vector(data_width_c-1 downto 0); -- delayed PC
    pc2_i       : in  std_ulogic_vector(data_width_c-1 downto 0); -- delayed PC
    imm_i       : in  std_ulogic_vector(data_width_c-1 downto 0); -- immediate
    imm_i       : in  std_ulogic_vector(data_width_c-1 downto 0); -- immediate
    -- data output --
    -- data output --
    cmp_o       : out std_ulogic_vector(1 downto 0); -- comparator status
    cmp_o       : out std_ulogic_vector(1 downto 0); -- comparator status
    res_o       : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
    res_o       : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
 
    add_o       : out std_ulogic_vector(data_width_c-1 downto 0); -- address computation result
 
    opb_o       : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU operand B
    -- co-processor interface --
    -- co-processor interface --
    cp0_start_o : out std_ulogic; -- trigger co-processor 0
    cp0_start_o : out std_ulogic; -- trigger co-processor 0
    cp0_data_i  : in  std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 0 result
    cp0_data_i  : in  std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 0 result
    cp0_valid_i : in  std_ulogic; -- co-processor 0 result valid
    cp0_valid_i : in  std_ulogic; -- co-processor 0 result valid
    cp1_start_o : out std_ulogic; -- trigger co-processor 1
    cp1_start_o : out std_ulogic; -- trigger co-processor 1
    cp1_data_i  : in  std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 1 result
    cp1_data_i  : in  std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 1 result
    cp1_valid_i : in  std_ulogic; -- co-processor 1 result valid
    cp1_valid_i : in  std_ulogic; -- co-processor 1 result valid
 
    cp2_start_o : out std_ulogic; -- trigger co-processor 2
 
    cp2_data_i  : in  std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 2 result
 
    cp2_valid_i : in  std_ulogic; -- co-processor 2 result valid
 
    cp3_start_o : out std_ulogic; -- trigger co-processor 3
 
    cp3_data_i  : in  std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 3 result
 
    cp3_valid_i : in  std_ulogic; -- co-processor 3 result valid
    -- status --
    -- status --
    wait_o      : out std_ulogic -- busy due to iterative processing units
    wait_o      : out std_ulogic -- busy due to iterative processing units
  );
  );
end neorv32_cpu_alu;
end neorv32_cpu_alu;
 
 
Line 76... Line 83...
 
 
  -- operands --
  -- operands --
  signal opa, opb : std_ulogic_vector(data_width_c-1 downto 0);
  signal opa, opb : std_ulogic_vector(data_width_c-1 downto 0);
 
 
  -- results --
  -- results --
  signal addsub_res : std_ulogic_vector(data_width_c-1 downto 0);
  signal addsub_res : std_ulogic_vector(data_width_c downto 0);
  signal cp_res     : std_ulogic_vector(data_width_c-1 downto 0);
  signal cp_res     : std_ulogic_vector(data_width_c-1 downto 0);
 
 
  -- comparator --
  -- comparator --
  signal cmp_opx   : std_ulogic_vector(data_width_c downto 0);
  signal cmp_opx   : std_ulogic_vector(data_width_c downto 0);
  signal cmp_opy   : std_ulogic_vector(data_width_c downto 0);
  signal cmp_opy   : std_ulogic_vector(data_width_c downto 0);
  signal cmp_sub   : std_ulogic_vector(data_width_c downto 0);
  signal cmp_sub   : std_ulogic_vector(data_width_c downto 0);
  signal cmp_less  : std_ulogic;
 
 
 
  -- shifter --
  -- shifter --
  type shifter_t is record
  type shifter_t is record
    cmd     : std_ulogic;
    cmd     : std_ulogic;
    cmd_ff  : std_ulogic;
    cmd_ff  : std_ulogic;
Line 114... Line 120...
 
 
begin
begin
 
 
  -- Operand Mux ----------------------------------------------------------------------------
  -- Operand Mux ----------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  opa <= pc2_i when (ctrl_i(ctrl_alu_opa_mux_c) = '1') else rs1_i; -- operand a (first ALU input operand)
  opa <= pc2_i when (ctrl_i(ctrl_alu_opa_mux_c) = '1') else rs1_i; -- operand a (first ALU input operand), only required for arithmetic ops
  opb <= imm_i when (ctrl_i(ctrl_alu_opb_mux_c) = '1') else rs2_i; -- operand b (second ALU input operand)
  opb <= imm_i when (ctrl_i(ctrl_alu_opb_mux_c) = '1') else rs2_i; -- operand b (second ALU input operand)
 
  --
 
  opb_o <= opb;
 
 
 
 
  -- Comparator Unit ------------------------------------------------------------------------
  -- Comparator Unit ------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  cmp_opx  <= (rs1_i(rs1_i'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & rs1_i;
  cmp_opx  <= (rs1_i(rs1_i'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & rs1_i;
Line 150... Line 158...
    else-- addition
    else-- addition
      op_y_v   := op_b_v;
      op_y_v   := op_b_v;
      cin_v(0) := '0';
      cin_v(0) := '0';
    end if;
    end if;
 
 
    -- adder core --
    -- adder core (result + carry/borrow) --
    res_v := std_ulogic_vector(unsigned(op_a_v) + unsigned(op_y_v) + unsigned(cin_v(0 downto 0)));
    addsub_res <= std_ulogic_vector(unsigned(op_a_v) + unsigned(op_y_v) + unsigned(cin_v(0 downto 0)));
 
 
    -- output --
 
    cmp_less    <= res_v(32);
 
    addsub_res  <= res_v(31 downto 0);
 
    addsub_res  <= res_v(31 downto 0);
 
  end process binary_arithmetic_core;
  end process binary_arithmetic_core;
 
 
 
  -- direct output of address result --
 
  add_o <= addsub_res(data_width_c-1 downto 0);
 
 
 
 
  -- Shifter Unit ---------------------------------------------------------------------------
  -- Shifter Unit ---------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  shifter_unit: process(rstn_i, clk_i)
  shifter_unit: process(clk_i)
    variable bs_input_v   : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_input_v   : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_4_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_4_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_3_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_3_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_2_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_2_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_1_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_1_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_0_v : std_ulogic_vector(data_width_c-1 downto 0);
    variable bs_level_0_v : std_ulogic_vector(data_width_c-1 downto 0);
  begin
  begin
    if (rstn_i = '0') then
    if rising_edge(clk_i) then
      shifter.sreg   <= (others => '0');
 
      shifter.cnt    <= (others => '0');
 
      shifter.cmd_ff <= '0';
 
      if (FAST_SHIFT_EN = true) then
 
        shifter.bs_d_in <= (others => '0');
 
        shifter.bs_a_in <= (others => '0');
 
      end if;
 
    elsif rising_edge(clk_i) then
 
      shifter.cmd_ff <= shifter.cmd;
      shifter.cmd_ff <= shifter.cmd;
 
 
      -- --------------------------------------------------------------------------------
      -- --------------------------------------------------------------------------------
      -- Iterative shifter (small but slow) (default)
      -- Iterative shifter (small but slow) (default)
      -- --------------------------------------------------------------------------------
      -- --------------------------------------------------------------------------------
      if (FAST_SHIFT_EN = false) then
      if (FAST_SHIFT_EN = false) then
 
 
        if (shifter.start = '1') then -- trigger new shift
        if (shifter.start = '1') then -- trigger new shift
          shifter.sreg <= opa; -- shift operand
          shifter.sreg <= rs1_i; -- shift operand (can only be rs1; opa would also contain pc)
          shifter.cnt  <= opb(index_size_f(data_width_c)-1 downto 0); -- shift amount
          shifter.cnt  <= opb(index_size_f(data_width_c)-1 downto 0); -- shift amount
        elsif (shifter.run = '1') then -- running shift
        elsif (shifter.run = '1') then -- running shift
          -- coarse shift: multiples of 4 --
          -- coarse shift: multiples of 4 --
          if (or_all_f(shifter.cnt(shifter.cnt'left downto 2)) = '1') then -- shift amount >= 4
          if (or_all_f(shifter.cnt(shifter.cnt'left downto 2)) = '1') then -- shift amount >= 4
            shifter.cnt <= std_ulogic_vector(unsigned(shifter.cnt) - 4);
            shifter.cnt <= std_ulogic_vector(unsigned(shifter.cnt) - 4);
Line 219... Line 217...
      -- --------------------------------------------------------------------------------
      -- --------------------------------------------------------------------------------
      else
      else
 
 
        -- operands and cycle control --
        -- operands and cycle control --
        if (shifter.start = '1') then -- trigger new shift
        if (shifter.start = '1') then -- trigger new shift
          shifter.bs_d_in <= opa; -- shift data
          shifter.bs_d_in <= rs1_i; -- shift operand (can only be rs1; opa would also contain pc)
          shifter.bs_a_in <= opb(index_size_f(data_width_c)-1 downto 0); -- shift amount
          shifter.bs_a_in <= opb(index_size_f(data_width_c)-1 downto 0); -- shift amount
          shifter.cnt     <= (others => '0');
          shifter.cnt     <= (others => '0');
        end if;
        end if;
 
 
        -- convert left shifts to right shifts --
        -- convert left shifts to right shifts --
Line 296... Line 294...
    elsif rising_edge(clk_i) then
    elsif rising_edge(clk_i) then
      if (CPU_EXTENSION_RISCV_M = true) then
      if (CPU_EXTENSION_RISCV_M = true) then
        cp_ctrl.cmd_ff <= cp_ctrl.cmd;
        cp_ctrl.cmd_ff <= cp_ctrl.cmd;
        if (cp_ctrl.start = '1') then
        if (cp_ctrl.start = '1') then
          cp_ctrl.busy <= '1';
          cp_ctrl.busy <= '1';
        elsif ((cp0_valid_i or cp1_valid_i) = '1') then -- cp computation done?
        elsif ((cp0_valid_i or cp1_valid_i or cp2_valid_i or cp3_valid_i) = '1') then -- cp computation done?
          cp_ctrl.busy <= '0';
          cp_ctrl.busy <= '0';
        end if;
        end if;
      else -- no co-processor(s) implemented
      else -- no co-processor(s) implemented
        cp_ctrl.cmd_ff <= '0';
        cp_ctrl.cmd_ff <= '0';
        cp_ctrl.busy   <= '0';
        cp_ctrl.busy   <= '0';
Line 309... Line 307...
  end process cp_arbiter;
  end process cp_arbiter;
 
 
  -- is co-processor operation? --
  -- is co-processor operation? --
  cp_ctrl.cmd   <= '1' when (ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) = alu_cmd_cp_c) else '0';
  cp_ctrl.cmd   <= '1' when (ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) = alu_cmd_cp_c) else '0';
  cp_ctrl.start <= '1' when (cp_ctrl.cmd = '1') and (cp_ctrl.cmd_ff = '0') else '0';
  cp_ctrl.start <= '1' when (cp_ctrl.cmd = '1') and (cp_ctrl.cmd_ff = '0') else '0';
  cp0_start_o   <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = cp_sel_muldiv_c) else '0'; -- MULDIV CP
  cp0_start_o   <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "00") else '0'; -- CP0: MULDIV CP
  cp1_start_o   <= '0'; -- not yet implemented
  cp1_start_o   <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "01") else '0'; -- CP1: not implemented yet
 
  cp2_start_o   <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "10") else '0'; -- CP2: not implemented yet
 
  cp3_start_o   <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = "11") else '0'; -- CP3: not implemented yet
 
 
  -- co-processor operation running? --
  -- co-processor operation running? --
  cp_ctrl.halt <= cp_ctrl.busy or cp_ctrl.start;
  cp_ctrl.halt <= cp_ctrl.busy or cp_ctrl.start;
 
 
  -- co-processor result --
  -- co-processor result --
  cp_res <= cp0_data_i or cp1_data_i; -- only the **actaully selected** co-processor should output data != 0
  cp_res <= cp0_data_i or cp1_data_i or cp2_data_i or cp3_data_i; -- only the *actually selected* co-processor may output data != 0
 
 
 
 
  -- ALU Function Select --------------------------------------------------------------------
  -- ALU Function Select --------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  alu_function_mux: process(ctrl_i, opa, opb, addsub_res, cp_res, cmp_less, shifter.sreg)
  alu_function_mux: process(ctrl_i, rs1_i, opb, addsub_res, cp_res, shifter.sreg)
  begin
  begin
    case ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) is
    case ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) is
      when alu_cmd_xor_c    => res_o <= opa xor opb;
      when alu_cmd_xor_c    => res_o <= rs1_i xor opb; -- only rs1 required for logic ops (opa would also contain pc)
      when alu_cmd_or_c     => res_o <= opa or  opb;
      when alu_cmd_or_c     => res_o <= rs1_i or  opb;
      when alu_cmd_and_c    => res_o <= opa and opb;
      when alu_cmd_and_c    => res_o <= rs1_i and opb;
      when alu_cmd_movb_c   => res_o <= opb;
      when alu_cmd_movb_c   => res_o <= opb;
      when alu_cmd_addsub_c => res_o <= addsub_res;
      when alu_cmd_addsub_c => res_o <= addsub_res(data_width_c-1 downto 0);
      when alu_cmd_cp_c     => res_o <= cp_res;
      when alu_cmd_cp_c     => res_o <= cp_res;
      when alu_cmd_shift_c  => res_o <= shifter.sreg;
      when alu_cmd_shift_c  => res_o <= shifter.sreg;
      when alu_cmd_slt_c    => res_o <= (others => '0'); res_o(0) <= cmp_less;
      when alu_cmd_slt_c    => res_o <= (others => '0'); res_o(0) <= addsub_res(addsub_res'left); -- => carry/borrow
      when others           => res_o <= opb; -- undefined
      when others           => res_o <= opb; -- undefined
    end case;
    end case;
  end process alu_function_mux;
  end process alu_function_mux;
 
 
 
 

powered by: WebSVN 2.1.0

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