mirror of
https://github.com/Domipheus/RPU.git
synced 2025-04-18 19:15:13 -04:00
Updated ISA support to RV32IMZcsr - Passes riscv-compliance. Integer divide/rem in 34 cycles. Integer multiply in 2 cycles (when using xilinx dsp blocks!) Saved multiple cycles from fetch/memory load stages by short-cutting the start of memory requests. Compliant misaligned exceptions for jumps,loads and stores. Addrs starting 0xFxxxxxxx ignore alignment requests (assumes mmio space). Added CSRs for riscv-compliance requirements. Source ran through a formatter for ease of use.
183 lines
No EOL
6.8 KiB
VHDL
183 lines
No EOL
6.8 KiB
VHDL
----------------------------------------------------------------------------------
|
|
-- Project Name: RISC-V CPU
|
|
-- Description: ALU unit for 32-bit integer division ops
|
|
--
|
|
----------------------------------------------------------------------------------
|
|
-- Copyright 2020 Colin Riley
|
|
--
|
|
-- Licensed under the Apache License, Version 2.0 (the "License");
|
|
-- you may not use this file except in compliance with the License.
|
|
-- You may obtain a copy of the License at
|
|
--
|
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
--
|
|
-- Unless required by applicable law or agreed to in writing, software
|
|
-- distributed under the License is distributed on an "AS IS" BASIS,
|
|
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
-- See the License for the specific language governing permissions and
|
|
-- limitations under the License.
|
|
----------------------------------------------------------------------------------
|
|
|
|
library IEEE;
|
|
use IEEE.STD_LOGIC_1164.all;
|
|
|
|
-- Uncomment the following library declaration if using
|
|
-- arithmetic functions with Signed or Unsigned values
|
|
use IEEE.NUMERIC_STD.all;
|
|
library work;
|
|
use work.constants.all;
|
|
|
|
entity alu_int32_div is
|
|
port (
|
|
I_clk : in STD_LOGIC;
|
|
I_exec : in STD_LOGIC;
|
|
I_dividend : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
|
I_divisor : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
|
I_op : in STD_LOGIC_VECTOR (1 downto 0);
|
|
O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
|
O_done : out STD_LOGIC;
|
|
O_int : out std_logic
|
|
);
|
|
end alu_int32_div;
|
|
|
|
architecture Behavioral of alu_int32_div is
|
|
signal s_done : std_logic := '0';
|
|
signal s_int : std_logic := '0';
|
|
signal s_op : std_logic_vector(1 downto 0) := (others => '0');
|
|
signal s_result : std_logic_vector(XLEN32M1 downto 0) := (others => '0');
|
|
signal s_outsign : std_logic := '0';
|
|
signal s_ur : unsigned(XLEN32M1 downto 0) := (others => '0');
|
|
|
|
signal s_i : integer := 0;
|
|
signal s_N : unsigned(XLEN32M1 downto 0) := (others => '0');
|
|
signal s_D : unsigned(XLEN32M1 downto 0) := (others => '0');
|
|
signal s_R : unsigned(XLEN32M1 downto 0) := (others => '0');
|
|
signal s_Q : unsigned(XLEN32M1 downto 0) := (others => '0');
|
|
constant STATE_IDLE : integer := 0;
|
|
constant STATE_INFLIGHTU : integer := 1;
|
|
constant STATE_COMPLETE : integer := 2;
|
|
|
|
signal s_state : integer := 0;
|
|
begin
|
|
|
|
process (I_clk)
|
|
begin
|
|
if rising_edge(I_clk) then
|
|
if s_state = STATE_IDLE then
|
|
s_done <= '0';
|
|
if I_exec = '1' then
|
|
s_op <= I_op;
|
|
s_done <= '0';
|
|
|
|
if (I_divisor = X"00000000") then
|
|
s_state <= STATE_COMPLETE;
|
|
s_Q <= X"ffffffff";
|
|
|
|
if I_dividend(31) = '1' then
|
|
s_R <= unsigned(-signed(I_dividend));
|
|
else
|
|
s_R <= unsigned(I_dividend);
|
|
end if;
|
|
|
|
if (I_op = ALU_INT32_DIV_OP_DIV) or (I_op = ALU_INT32_DIV_OP_DIVU) then
|
|
s_outsign <= '0';
|
|
else
|
|
s_outsign <= I_dividend(31);
|
|
end if;
|
|
|
|
elsif (I_divisor = X"00000001") and (I_op = ALU_INT32_DIV_OP_DIV) then
|
|
s_state <= STATE_COMPLETE;
|
|
s_R <= X"00000000";
|
|
if I_dividend(31) = '1' then
|
|
s_Q <= unsigned(-signed(I_dividend));
|
|
else
|
|
s_Q <= unsigned(I_dividend);
|
|
end if;
|
|
s_outsign <= I_dividend(31);
|
|
|
|
else
|
|
if I_op(ALU_INT32_DIV_OP_UNSIGNED_BIT) = '1' then
|
|
s_state <= STATE_INFLIGHTU;
|
|
s_N <= unsigned(I_dividend);
|
|
s_D <= unsigned(I_divisor);
|
|
s_ur <= X"00000000";
|
|
s_Q <= X"00000000";
|
|
s_R <= X"00000000";
|
|
|
|
s_i <= 31;
|
|
s_outsign <= '0';
|
|
else
|
|
s_state <= STATE_INFLIGHTU;
|
|
|
|
if (I_op = ALU_INT32_DIV_OP_DIV) then
|
|
s_outsign <= I_dividend(31) xor I_divisor(31);
|
|
else
|
|
s_outsign <= I_dividend(31);
|
|
end if;
|
|
|
|
if I_dividend(31) = '1' then
|
|
s_N <= unsigned(-signed(I_dividend));
|
|
else
|
|
s_N <= unsigned(I_dividend);
|
|
end if;
|
|
|
|
if I_divisor(31) = '1' then
|
|
s_D <= unsigned(-signed(I_divisor));
|
|
else
|
|
s_D <= unsigned(I_divisor);
|
|
end if;
|
|
|
|
s_ur <= X"00000000";
|
|
|
|
s_Q <= X"00000000";
|
|
s_R <= X"00000000";
|
|
|
|
s_i <= 31;
|
|
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
|
|
elsif s_state = STATE_INFLIGHTU then
|
|
-- binary integer long division loop
|
|
if (s_R(30 downto 0) & s_N(s_i)) >= s_D then
|
|
s_R <= (s_R(30 downto 0) & s_N(s_i)) - s_D;
|
|
s_Q(s_i) <= '1';
|
|
else
|
|
s_R <= s_R(30 downto 0) & s_N(s_i);
|
|
end if;
|
|
|
|
if s_i = 0 then
|
|
s_state <= STATE_COMPLETE;
|
|
else
|
|
s_i <= s_i - 1;
|
|
end if;
|
|
|
|
|
|
elsif s_state = STATE_COMPLETE then
|
|
|
|
if (s_op = ALU_INT32_DIV_OP_DIV) or (s_op = ALU_INT32_DIV_OP_DIVU) then
|
|
if (s_outsign = '1') then
|
|
s_result <= std_logic_vector(-signed(std_logic_vector(s_Q)));
|
|
else
|
|
s_result <= std_logic_vector(s_Q);
|
|
end if;
|
|
else
|
|
if (s_outsign = '1') then
|
|
s_result <= std_logic_vector(-signed(std_logic_vector(s_R)));
|
|
else
|
|
s_result <= std_logic_vector(s_R);
|
|
end if;
|
|
end if;
|
|
|
|
s_done <= '1';
|
|
s_state <= STATE_IDLE;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
O_dataResult <= s_result;
|
|
O_done <= s_done;
|
|
O_int <= s_int;
|
|
end Behavioral; |