RPU/vhdl/alu_int32_div.vhd
Colin Riley 4b16f9bf6f RPU 1.0
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.
2020-09-11 00:06:01 +01:00

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;