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.
301 lines
No EOL
13 KiB
VHDL
301 lines
No EOL
13 KiB
VHDL
----------------------------------------------------------------------------------
|
|
-- Project Name: RISC-V CPU
|
|
-- Description: CSR unit RV32I
|
|
--
|
|
----------------------------------------------------------------------------------
|
|
-- Copyright 2018,2019,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;
|
|
use IEEE.NUMERIC_STD.all;
|
|
|
|
library work;
|
|
use work.constants.all;
|
|
|
|
entity csr_unit is
|
|
port (
|
|
I_clk : in STD_LOGIC;
|
|
I_en : in STD_LOGIC;
|
|
I_dataIn : in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
O_dataOut : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
I_csrOp : in STD_LOGIC_VECTOR (4 downto 0);
|
|
I_csrAddr : in STD_LOGIC_VECTOR (11 downto 0);
|
|
O_int : out STD_LOGIC;
|
|
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
|
I_instRetTick : in STD_LOGIC;
|
|
|
|
-- interrupt handling causes many data dependencies
|
|
-- mcause has a fast path in from other units
|
|
I_int_cause : in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
I_int_pc : in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
I_int_mtval : in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
-- We need to know when an interrupt occurs as to perform the
|
|
-- relevant csr modifications. Same with exit.
|
|
I_int_entry : in STD_LOGIC;
|
|
I_int_exit : in STD_LOGIC;
|
|
|
|
-- Currently just feeds machine level CSR values
|
|
O_csr_status : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
O_csr_cause : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
O_csr_ie : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
O_csr_tvec : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
|
O_csr_epc : out STD_LOGIC_VECTOR (XLENM1 downto 0)
|
|
);
|
|
end csr_unit;
|
|
|
|
architecture Behavioral of csr_unit is
|
|
|
|
constant CSR_ADDR_USTATUS : STD_LOGIC_VECTOR (11 downto 0) := X"000";
|
|
constant CSR_ADDR_UIE : STD_LOGIC_VECTOR (11 downto 0) := X"004";
|
|
constant CSR_ADDR_UTVEC : STD_LOGIC_VECTOR (11 downto 0) := X"005";
|
|
|
|
constant CSR_ADDR_USCRATCH : STD_LOGIC_VECTOR (11 downto 0) := X"040";
|
|
constant CSR_ADDR_UEPC : STD_LOGIC_VECTOR (11 downto 0) := X"041";
|
|
constant CSR_ADDR_UCAUSE : STD_LOGIC_VECTOR (11 downto 0) := X"042";
|
|
constant CSR_ADDR_UTVAL : STD_LOGIC_VECTOR (11 downto 0) := X"043";
|
|
constant CSR_ADDR_UIP : STD_LOGIC_VECTOR (11 downto 0) := X"044";
|
|
|
|
constant CSR_ADDR_CYCLE : STD_LOGIC_VECTOR (11 downto 0) := X"C00";
|
|
constant CSR_ADDR_TIME : STD_LOGIC_VECTOR (11 downto 0) := X"C01";
|
|
constant CSR_ADDR_INSTRET : STD_LOGIC_VECTOR (11 downto 0) := X"C02";
|
|
|
|
constant CSR_ADDR_CYCLEH : STD_LOGIC_VECTOR (11 downto 0) := X"C80";
|
|
constant CSR_ADDR_TIMEH : STD_LOGIC_VECTOR (11 downto 0) := X"C81";
|
|
constant CSR_ADDR_INSTRETH : STD_LOGIC_VECTOR (11 downto 0) := X"C82";
|
|
constant CSR_ADDR_TEST_400 : STD_LOGIC_VECTOR (11 downto 0) := X"400";
|
|
constant CSR_ADDR_TEST_401 : STD_LOGIC_VECTOR (11 downto 0) := X"401";
|
|
|
|
constant CSR_ADDR_MSTATUS : STD_LOGIC_VECTOR (11 downto 0) := X"300";
|
|
constant CSR_ADDR_MISA : STD_LOGIC_VECTOR (11 downto 0) := X"301";
|
|
constant CSR_ADDR_MEDELEG : STD_LOGIC_VECTOR (11 downto 0) := X"302";
|
|
constant CSR_ADDR_MIDELEG : STD_LOGIC_VECTOR (11 downto 0) := X"303";
|
|
constant CSR_ADDR_MIE : STD_LOGIC_VECTOR (11 downto 0) := X"304";
|
|
constant CSR_ADDR_MTVEC : STD_LOGIC_VECTOR (11 downto 0) := X"305";
|
|
constant CSR_ADDR_MCOUNTEREN : STD_LOGIC_VECTOR (11 downto 0) := X"306";
|
|
|
|
constant CSR_ADDR_MSCRATCH : STD_LOGIC_VECTOR (11 downto 0) := X"340";
|
|
constant CSR_ADDR_MEPC : STD_LOGIC_VECTOR (11 downto 0) := X"341";
|
|
constant CSR_ADDR_MCAUSE : STD_LOGIC_VECTOR (11 downto 0) := X"342";
|
|
constant CSR_ADDR_MTVAL : STD_LOGIC_VECTOR (11 downto 0) := X"343";
|
|
constant CSR_ADDR_MIP : STD_LOGIC_VECTOR (11 downto 0) := X"344";
|
|
|
|
constant CSR_ADDR_MCYCLE : STD_LOGIC_VECTOR (11 downto 0) := X"B00";
|
|
constant CSR_ADDR_MINSTRET : STD_LOGIC_VECTOR (11 downto 0) := X"B02";
|
|
|
|
constant CSR_ADDR_MCYCLEH : STD_LOGIC_VECTOR (11 downto 0) := X"B80";
|
|
constant CSR_ADDR_MINSTRETH : STD_LOGIC_VECTOR (11 downto 0) := X"B82";
|
|
|
|
constant CSR_ADDR_MVENDORID : STD_LOGIC_VECTOR (11 downto 0) := X"F11";
|
|
constant CSR_ADDR_MARCHID : STD_LOGIC_VECTOR (11 downto 0) := X"F12";
|
|
constant CSR_ADDR_MIMPID : STD_LOGIC_VECTOR (11 downto 0) := X"F13";
|
|
constant CSR_ADDR_MHARDID : STD_LOGIC_VECTOR (11 downto 0) := X"F14";
|
|
signal csr_cycles : STD_LOGIC_VECTOR(63 downto 0) := (others => '0');
|
|
signal csr_instret : STD_LOGIC_VECTOR(63 downto 0) := (others => '0');
|
|
|
|
signal csr_mstatus : STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000000";
|
|
signal csr_mie : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
|
signal csr_mtvec : STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000004";
|
|
signal csr_mscratch : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
|
signal csr_mepc : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
|
signal csr_mcause : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
|
signal csr_mtval : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
|
signal csr_mip : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
|
|
|
signal csr_vexrisc_irq_mask : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
|
signal csr_vexrisc_irq_pending : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
|
|
|
signal curr_csr_value : STD_LOGIC_VECTOR(XLENM1 downto 0) := (others => '0');
|
|
signal next_csr_value : STD_LOGIC_VECTOR(XLENM1 downto 0) := (others => '0');
|
|
|
|
signal test0_CSR : STD_LOGIC_VECTOR(XLENM1 downto 0) := X"FEFbbEF0";
|
|
signal test1_CSR : STD_LOGIC_VECTOR(XLENM1 downto 0) := X"FEFbbEF1";
|
|
|
|
signal csr_op : STD_LOGIC_VECTOR(4 downto 0) := (others => '0');
|
|
signal opState : integer := 0;
|
|
|
|
signal raise_int : std_logic := '0';
|
|
|
|
constant STEP_READ_OR_IDLE : integer := 0;
|
|
constant STEP_MODIFY : integer := 1;
|
|
constant STEP_WRITE : integer := 2;
|
|
begin
|
|
|
|
O_int <= raise_int;
|
|
O_int_data <= X"00000000";
|
|
O_csr_status <= csr_mstatus;
|
|
O_csr_tvec <= csr_mtvec;
|
|
O_csr_cause <= csr_mcause;
|
|
O_csr_ie <= csr_mie;
|
|
O_csr_epc <= csr_mepc;
|
|
|
|
O_dataOut <= curr_csr_value;
|
|
|
|
cycles : process (I_clk)
|
|
begin
|
|
if rising_edge(I_clk) then
|
|
csr_cycles <= std_logic_vector(unsigned(csr_cycles) + 1);
|
|
end if;
|
|
end process;
|
|
|
|
instret : process (I_clk)
|
|
begin
|
|
if rising_edge(I_clk) and I_instRetTick = '1' then
|
|
csr_instret <= std_logic_vector(unsigned(csr_instret) + 1);
|
|
end if;
|
|
end process;
|
|
|
|
protection : process (I_clk, I_en)
|
|
begin
|
|
if rising_edge(I_clk) then
|
|
if (I_csrAddr(CSR_ADDR_ACCESS_BIT_START downto CSR_ADDR_ACCESS_BIT_END) = CSR_ADDR_ACCESS_READONLY) and
|
|
(I_csrOp(CSR_OP_BITS_WRITTEN) = '1') then
|
|
--todo: raise exception
|
|
raise_int <= '1';
|
|
else
|
|
raise_int <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Read data is available next cycle, with an additional cycle before another op can be processed
|
|
-- Write to CSR occurs 3 cycles later.
|
|
-- cycle 1: read of existing csr available
|
|
-- cycle 2: update value calculates (whole write, set/clear bit read-modify-write)
|
|
-- cycle 3: actual write to csr occurs.
|
|
datamain : process (I_clk, I_en)
|
|
begin
|
|
if rising_edge(I_clk) then
|
|
|
|
if I_int_entry = '1' then
|
|
-- on entry:
|
|
-- mstatus.mpie = mstatus.mie
|
|
csr_mstatus(7) <= csr_mstatus(3);
|
|
-- mstatus.mie = 0
|
|
csr_mstatus(3) <= '0';
|
|
-- mstatus.mpp = current privilege mode
|
|
csr_mstatus(12 downto 11) <= "11";
|
|
|
|
csr_mcause <= I_int_cause;
|
|
csr_mepc <= I_int_pc;
|
|
csr_mtval <= I_int_mtval;
|
|
|
|
elsif I_int_exit = '1' then
|
|
-- privilege set to mstatus.mpp
|
|
-- mstatus.mie = mstatus.mpie
|
|
csr_mstatus(3) <= csr_mstatus(7);
|
|
csr_mstatus(7) <= '1';
|
|
csr_mstatus(12 downto 11) <= "00";
|
|
|
|
-- interrupt data changes take all priority
|
|
|
|
elsif I_en = '1' and opState = STEP_READ_OR_IDLE then
|
|
csr_op <= I_csrOp;
|
|
case I_csrAddr is
|
|
when CSR_ADDR_MVENDORID =>
|
|
curr_csr_value <= X"00000000"; -- JEDEC non-commercial
|
|
when CSR_ADDR_MARCHID =>
|
|
curr_csr_value <= X"00000000";
|
|
when CSR_ADDR_MIMPID =>
|
|
curr_csr_value <= X"52505531"; -- "RPU1"
|
|
when CSR_ADDR_MHARDID =>
|
|
curr_csr_value <= X"00000000";
|
|
when CSR_ADDR_MISA =>
|
|
curr_csr_value <= X"40001100"; -- XLEN 32, RV32IM
|
|
|
|
when CSR_ADDR_MSTATUS =>
|
|
curr_csr_value <= csr_mstatus;
|
|
when CSR_ADDR_MTVEC =>
|
|
curr_csr_value <= csr_mtvec;
|
|
when CSR_ADDR_MIE =>
|
|
curr_csr_value <= csr_mie;
|
|
when CSR_ADDR_MIP =>
|
|
curr_csr_value <= csr_mip;
|
|
when CSR_ADDR_MCAUSE =>
|
|
curr_csr_value <= csr_mcause;
|
|
when CSR_ADDR_MEPC =>
|
|
curr_csr_value <= csr_mepc;
|
|
when CSR_ADDR_MTVAL =>
|
|
curr_csr_value <= csr_mtval;
|
|
when CSR_ADDR_MSCRATCH =>
|
|
curr_csr_value <= csr_mscratch;
|
|
|
|
when CSR_ADDR_CYCLE =>
|
|
curr_csr_value <= csr_cycles(31 downto 0);
|
|
when CSR_ADDR_CYCLEH =>
|
|
curr_csr_value <= csr_cycles(63 downto 32);
|
|
|
|
when CSR_ADDR_INSTRET =>
|
|
curr_csr_value <= csr_instret(31 downto 0);
|
|
when CSR_ADDR_INSTRETH =>
|
|
curr_csr_value <= csr_instret(63 downto 32);
|
|
|
|
when CSR_ADDR_MCYCLE =>
|
|
curr_csr_value <= csr_cycles(31 downto 0);
|
|
when CSR_ADDR_MCYCLEH =>
|
|
curr_csr_value <= csr_cycles(63 downto 32);
|
|
|
|
when CSR_ADDR_MINSTRET =>
|
|
curr_csr_value <= csr_instret(31 downto 0);
|
|
when CSR_ADDR_MINSTRETH =>
|
|
curr_csr_value <= csr_instret(63 downto 32);
|
|
|
|
when others =>
|
|
-- raise exception for unsupported CSR
|
|
end case;
|
|
opState <= STEP_MODIFY;
|
|
|
|
elsif opState = STEP_MODIFY then
|
|
-- update stage for sets, clears and writes
|
|
case csr_op(3 downto 2) is
|
|
when CSR_MAINOP_WR =>
|
|
next_csr_value <= I_dataIn;
|
|
when CSR_MAINOP_SET =>
|
|
next_csr_value <= curr_csr_value or I_dataIn;
|
|
when CSR_MAINOP_CLEAR =>
|
|
next_csr_value <= curr_csr_value and (not I_dataIn);
|
|
when others =>
|
|
end case;
|
|
|
|
if I_csrOp(CSR_OP_BITS_WRITTEN) = '1' then
|
|
opState <= STEP_WRITE;
|
|
else
|
|
opState <= STEP_READ_OR_IDLE;
|
|
end if;
|
|
|
|
elsif opState = STEP_WRITE then
|
|
-- write stage
|
|
opState <= STEP_READ_OR_IDLE;
|
|
case I_csrAddr is
|
|
|
|
when CSR_ADDR_MSTATUS =>
|
|
csr_mstatus <= next_csr_value;
|
|
when CSR_ADDR_MTVEC =>
|
|
csr_mtvec <= next_csr_value;
|
|
when CSR_ADDR_MIE =>
|
|
csr_mie <= next_csr_value;
|
|
when CSR_ADDR_MIP =>
|
|
csr_mip <= next_csr_value;
|
|
when CSR_ADDR_MEPC =>
|
|
csr_mepc <= next_csr_value;
|
|
when CSR_ADDR_MSCRATCH =>
|
|
csr_mscratch <= next_csr_value;
|
|
when others =>
|
|
end case;
|
|
end if;
|
|
end if;
|
|
|
|
end process;
|
|
|
|
end Behavioral; |