mirror of
https://github.com/Domipheus/RPU.git
synced 2025-04-18 19:15:13 -04:00
RISC-V Machine level Interrupt support first pass.
- Added Local interrupt unit which just collates all int sources. - Added relevant core glue logic. - Added M-level CSRs for trap handling. - Disabled legacy interrupt handling from pc unit as interrupt vector is no longer fixed. - ALU handles mret as a basic branch to epc. - ECALL/EBREAK/MRET support added to decoder. True RISC-V interrupt support still needs interrupt enables via CSR, and proper state flipping (IE/PIE etc)
This commit is contained in:
parent
a9c5413cd9
commit
bb6683092f
7 changed files with 338 additions and 46 deletions
|
@ -123,6 +123,8 @@ begin
|
|||
if (I_aluop(6 downto 2) = OPCODE_LOAD or
|
||||
I_aluop(6 downto 2) = OPCODE_STORE) then
|
||||
s_state <= "0010000"; -- MEM
|
||||
-- elsif (I_aluop(6 downto 2) = OPCODE_SYSTEM) then
|
||||
-- s_state <= "1001000"; -- alu stall
|
||||
else
|
||||
s_state <= "0100000"; -- WB
|
||||
end if;
|
||||
|
@ -161,14 +163,14 @@ begin
|
|||
-- interrupt stall
|
||||
if interrupt_state = "001" then
|
||||
-- give a cycle of latency
|
||||
interrupt_state <= "010";
|
||||
elsif interrupt_state = "010" then
|
||||
-- sample input data for state?
|
||||
O_idata <= I_int_mem_data;
|
||||
set_idata <= '1';
|
||||
interrupt_state <= "100";
|
||||
elsif interrupt_state = "100" then
|
||||
set_idata <= '0';
|
||||
-- interrupt_state <= "010";
|
||||
-- elsif interrupt_state = "010" then
|
||||
-- -- sample input data for state?
|
||||
-- O_idata <= I_int_mem_data;
|
||||
-- set_idata <= '1';
|
||||
-- interrupt_state <= "100";
|
||||
-- elsif interrupt_state = "100" then
|
||||
-- set_idata <= '0';
|
||||
-- set PC to interrupt vector.
|
||||
set_ipc <= '1';
|
||||
interrupt_state <= "101";
|
||||
|
@ -178,7 +180,9 @@ begin
|
|||
interrupt_state <= "000";
|
||||
s_state <= "0000001"; --F
|
||||
end if;
|
||||
|
||||
when "1001000" =>
|
||||
-- alu 1 cycle stall
|
||||
s_state <= "0100000"; -- WB
|
||||
when others =>
|
||||
s_state <= "0000001";
|
||||
end case;
|
||||
|
|
112
vhdl/core.vhd
112
vhdl/core.vhd
|
@ -103,9 +103,11 @@ architecture Behavioral of core is
|
|||
O_aluOp : OUT std_logic_vector(6 downto 0);
|
||||
O_aluFunc : OUT std_logic_vector(15 downto 0);
|
||||
O_memOp : out STD_LOGIC_VECTOR(4 downto 0);
|
||||
|
||||
O_csrOP : out STD_LOGIC_VECTOR(4 downto 0);
|
||||
O_csrAddr : out STD_LOGIC_VECTOR(11 downto 0)
|
||||
O_csrAddr : out STD_LOGIC_VECTOR(11 downto 0);
|
||||
O_int : out STD_LOGIC;
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_int_ack: in STD_LOGIC
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
|
@ -117,8 +119,9 @@ architecture Behavioral of core is
|
|||
I_dataB : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
I_dataDwe : in STD_LOGIC;
|
||||
I_aluop : in STD_LOGIC_VECTOR (4 downto 0);
|
||||
I_aluFunc : in STD_LOGIC_VECTOR (15 downto 0);
|
||||
I_aluFunc : in STD_LOGIC_VECTOR (15 downto 0);
|
||||
I_PC : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
I_epc : in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
I_dataIMM : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
O_branchTarget : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
|
@ -158,10 +161,39 @@ architecture Behavioral of core is
|
|||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
|
||||
I_instRetTick : in STD_LOGIC;
|
||||
O_csr_status : out STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
O_csr_tvec : out STD_LOGIC_VECTOR(XLENM1 downto 0)
|
||||
|
||||
-- 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);
|
||||
-- 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 COMPONENT;
|
||||
|
||||
COMPONENT lint_unit
|
||||
PORT (
|
||||
I_clk : in STD_LOGIC;
|
||||
I_reset : in STD_LOGIC;
|
||||
I_pc : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_int0 : in STD_LOGIC;
|
||||
I_int_data0 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int0_ack: out STD_LOGIC;
|
||||
I_int1 : in STD_LOGIC;
|
||||
I_int_data1 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int1_ack: out STD_LOGIC;
|
||||
I_int2 : in STD_LOGIC;
|
||||
I_int_data2 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_int3 : in STD_LOGIC;
|
||||
I_int_data3 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int : out STD_LOGIC;
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int_epc : out STD_LOGIC_VECTOR (31 downto 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
COMPONENT mem_controller
|
||||
PORT(
|
||||
|
@ -214,6 +246,12 @@ architecture Behavioral of core is
|
|||
signal memMode : std_logic := '0';
|
||||
signal ram_req_size : std_logic := '0';
|
||||
|
||||
|
||||
signal decoder_int: STD_LOGIC;
|
||||
signal decoder_int_data: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal decoder_int_ack: STD_LOGIC := '0';
|
||||
|
||||
|
||||
signal reg_en: std_logic := '0';
|
||||
signal reg_we: std_logic := '0';
|
||||
|
||||
|
@ -229,6 +267,7 @@ architecture Behavioral of core is
|
|||
signal en_stall : std_logic := '0';
|
||||
|
||||
signal PC : std_logic_vector(XLENM1 downto 0) := (others => '0');
|
||||
signal PC_at_int : std_logic_vector(XLENM1 downto 0) := (others => '0');
|
||||
|
||||
signal memctl_ready : std_logic;
|
||||
signal memctl_execute : std_logic := '0';
|
||||
|
@ -245,11 +284,12 @@ architecture Behavioral of core is
|
|||
|
||||
signal int_idata: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal int_set_idata: STD_LOGIC;
|
||||
signal int_enabled: std_logic;
|
||||
signal int_enabled: std_logic := '1';
|
||||
signal int_set_irpc: STD_LOGIC;
|
||||
|
||||
signal csru_int: STD_LOGIC;
|
||||
signal csru_int_data: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal csru_int_ack: STD_LOGIC := '0';
|
||||
|
||||
signal csru_dataIn : STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal csru_dataOut : STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
|
@ -262,9 +302,19 @@ architecture Behavioral of core is
|
|||
-- Some CSRs are needed in various places easily, so they are distributed
|
||||
signal csr_status : STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal csr_tvec : STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal csr_cause : STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
signal csr_ie : STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
signal csr_epc : STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
|
||||
|
||||
signal core_clock:STD_LOGIC := '0';
|
||||
|
||||
signal lint_reset: STD_LOGIC := '0';
|
||||
signal lint_nothing: STD_LOGIC := '0';
|
||||
signal lint_nothing_data: STD_LOGIC_VECTOR(XLENM1 downto 0):= (others => '0');
|
||||
signal lint_int: STD_LOGIC;
|
||||
signal lint_int_data: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
|
||||
begin
|
||||
core_clock <= I_clk;
|
||||
|
||||
|
@ -304,10 +354,10 @@ begin
|
|||
I_reset => I_reset,
|
||||
I_aluop => aluop,
|
||||
|
||||
I_int => I_int,
|
||||
O_int_ack => O_int_ack,
|
||||
I_int => lint_int,
|
||||
O_int_ack => lint_reset,
|
||||
I_int_enabled => int_enabled,
|
||||
I_int_mem_data=>MEM_I_data,
|
||||
I_int_mem_data=> lint_int_data,
|
||||
O_idata=> int_idata,
|
||||
O_set_idata=> int_set_idata,
|
||||
O_set_ipc=> PCintVec,
|
||||
|
@ -332,7 +382,11 @@ begin
|
|||
O_aluFunc => aluFunc,
|
||||
O_memOp => memOp,
|
||||
O_csrOp => csru_csrOp,
|
||||
O_csrAddr => csru_csrAddr
|
||||
O_csrAddr => csru_csrAddr,
|
||||
-- This unit can raise exceptions
|
||||
O_int => decoder_int,
|
||||
O_int_data => decoder_int_data,
|
||||
I_int_ack => decoder_int_ack
|
||||
);
|
||||
|
||||
alu: alu_RV32I PORT MAP (
|
||||
|
@ -344,6 +398,7 @@ begin
|
|||
I_aluop => aluop(6 downto 2),
|
||||
I_aluFunc => aluFunc,
|
||||
I_PC => PC,
|
||||
I_epc => csr_epc,
|
||||
I_dataIMM => dataIMM,
|
||||
O_dataResult => dataResult,
|
||||
O_branchTarget => branchTarget,
|
||||
|
@ -377,10 +432,37 @@ begin
|
|||
-- This unit can raise exceptions
|
||||
O_int => csru_int,
|
||||
O_int_data => csru_int_data,
|
||||
--I_int_ack => csru_int_ack,
|
||||
|
||||
I_instRetTick => csru_instRetTick,
|
||||
|
||||
I_int_cause => lint_int_data,
|
||||
I_int_pc => PC_at_int,
|
||||
|
||||
O_csr_status => csr_status,
|
||||
O_csr_tvec => csr_tvec
|
||||
O_csr_tvec => csr_tvec,
|
||||
O_csr_cause => csr_cause,
|
||||
O_csr_ie => csr_ie,
|
||||
O_csr_epc => csr_epc
|
||||
);
|
||||
|
||||
lint: lint_unit PORT MAP (
|
||||
I_clk => core_clock,
|
||||
I_reset => lint_reset,
|
||||
I_pc => PC,
|
||||
I_int0 => decoder_int,
|
||||
I_int_data0 => decoder_int_data,
|
||||
O_int0_ack => decoder_int_ack,
|
||||
I_int1 => csru_int,
|
||||
I_int_data1 => csru_int_data,
|
||||
O_int1_ack => csru_int_ack,
|
||||
I_int2 => lint_nothing,
|
||||
I_int_data2 => lint_nothing_data,
|
||||
I_int3 => lint_nothing,
|
||||
I_int_data3 => lint_nothing_data,
|
||||
O_int => lint_int,
|
||||
O_int_data => lint_int_data,
|
||||
O_int_epc => PC_at_int
|
||||
);
|
||||
|
||||
|
||||
|
@ -391,8 +473,8 @@ begin
|
|||
-- These are the pipeline stage enable bits
|
||||
en_fetch <= state(0);
|
||||
en_decode <= state(1);
|
||||
en_alu <= '0' when aluop(6 downto 2) = OPCODE_SYSTEM else state(3);
|
||||
en_csru <= state(3) when aluop(6 downto 2) = OPCODE_SYSTEM else '0';
|
||||
en_alu <= '0' when (aluop(6 downto 2) = OPCODE_SYSTEM and aluFunc(2 downto 0) /= "000") else state(3);
|
||||
en_csru <= state(3) when (aluop(6 downto 2) = OPCODE_SYSTEM and aluFunc(2 downto 0) /= "000") else '0';
|
||||
en_memory <= state(4);
|
||||
en_regwrite <= state(5);
|
||||
en_stall <= state(6);
|
||||
|
@ -401,10 +483,12 @@ begin
|
|||
pcop <= PCU_OP_RESET when I_reset = '1' else
|
||||
PCU_OP_ASSIGN when shouldBranch = '1' and state(5) = '1' else
|
||||
PCU_OP_INC when shouldBranch = '0' and state(5) = '1' else
|
||||
PCU_OP_ASSIGN when PCintvec = '1' else
|
||||
PCU_OP_NOP;
|
||||
|
||||
-- The input PC is just always the branch target output from ALU
|
||||
in_pc <= branchTarget;
|
||||
-- todo: tvec needs modifiec for vectored exceptions
|
||||
in_pc <= csr_tvec when PCintvec = '1' else branchTarget;
|
||||
|
||||
-- input data from the register file, or use immediate if the OP specifies it
|
||||
csru_dataIn <= dataIMM when csru_csrOp(CSR_OP_BITS_IMM) = '1' else dataA;
|
||||
|
|
|
@ -34,8 +34,15 @@ entity csr_unit is
|
|||
O_int : out STD_LOGIC;
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_instRetTick : in STD_LOGIC;
|
||||
-- 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);
|
||||
-- Currently just feeds machine level CSR values
|
||||
O_csr_status : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
O_csr_tvec : 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;
|
||||
|
||||
|
@ -91,9 +98,14 @@ 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_status : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_tvec : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mstatus : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mie : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mtvec : STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000010";
|
||||
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 curr_csr_value: STD_LOGIC_VECTOR(XLENM1 downto 0) := (others=> '0');
|
||||
signal next_csr_value: STD_LOGIC_VECTOR(XLENM1 downto 0) := (others=> '0');
|
||||
|
@ -103,10 +115,18 @@ 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';
|
||||
|
||||
begin
|
||||
|
||||
O_csr_status <= csr_status;
|
||||
O_csr_tvec <= csr_tvec;
|
||||
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;
|
||||
|
||||
|
@ -126,10 +146,13 @@ begin
|
|||
|
||||
protection: process (I_clk, I_en)
|
||||
begin
|
||||
if rising_edge(I_clk) and I_en = '1' then
|
||||
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;
|
||||
|
@ -142,6 +165,14 @@ begin
|
|||
datamain: process (I_clk, I_en)
|
||||
begin
|
||||
if rising_edge(I_clk) then
|
||||
-- fastpath mcause write
|
||||
if (I_int_cause /= csr_mcause) then
|
||||
csr_mcause <= I_int_cause;
|
||||
end if;
|
||||
if (I_int_pc /= csr_mepc) then
|
||||
csr_mepc <= I_int_pc;
|
||||
end if;
|
||||
|
||||
if I_en = '1' and opState = 0 then
|
||||
csr_op <= I_csrOp;
|
||||
case I_csrAddr is
|
||||
|
@ -156,6 +187,15 @@ begin
|
|||
when CSR_ADDR_MISA =>
|
||||
curr_csr_value <= X"40000080"; -- XLEN 32, RV32I
|
||||
|
||||
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_MCAUSE =>
|
||||
curr_csr_value <= csr_mcause;
|
||||
|
||||
when CSR_ADDR_CYCLE =>
|
||||
curr_csr_value <= csr_cycles(31 downto 0);
|
||||
when CSR_ADDR_CYCLEH =>
|
||||
|
@ -212,6 +252,13 @@ begin
|
|||
test0_CSR <= next_csr_value;
|
||||
when CSR_ADDR_TEST_401 =>
|
||||
test1_CSR <= next_csr_value;
|
||||
|
||||
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 others =>
|
||||
end case;
|
||||
end if;
|
||||
|
|
117
vhdl/lint_unit.vhd
Normal file
117
vhdl/lint_unit.vhd
Normal file
|
@ -0,0 +1,117 @@
|
|||
----------------------------------------------------------------------------------
|
||||
-- Project Name: RISC-V CPU
|
||||
-- Description: Local Interrupt unit
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2018 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 lint_unit is
|
||||
Port ( I_clk : in STD_LOGIC;
|
||||
I_reset : in STD_LOGIC;
|
||||
I_pc : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_int0 : in STD_LOGIC;
|
||||
I_int_data0 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int0_ack: out STD_LOGIC;
|
||||
I_int1 : in STD_LOGIC;
|
||||
I_int_data1 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int1_ack: out STD_LOGIC;
|
||||
I_int2 : in STD_LOGIC;
|
||||
I_int_data2 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_int3 : in STD_LOGIC;
|
||||
I_int_data3 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int : out STD_LOGIC;
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int_epc : out STD_LOGIC_VECTOR (31 downto 0)
|
||||
);
|
||||
end lint_unit;
|
||||
|
||||
architecture Behavioral of lint_unit is
|
||||
|
||||
signal actual_int: std_logic := '0';
|
||||
signal actual_int_data: std_logic_vector (31 downto 0) := X"00000000";
|
||||
signal actual_int_epc: std_logic_vector (31 downto 0) := X"00000000";
|
||||
|
||||
signal int0_ack: std_logic := '0';
|
||||
signal int1_ack: std_logic := '0';
|
||||
signal int2_ack: std_logic := '0';
|
||||
signal int3_ack: std_logic := '0';
|
||||
begin
|
||||
|
||||
O_int <= actual_int;
|
||||
O_int_data <= actual_int_data;
|
||||
O_int_epc <= actual_int_epc;
|
||||
|
||||
O_int0_ack <= int0_ack;
|
||||
O_int1_ack <= int1_ack;
|
||||
|
||||
-- This simply filters one of the 4 int sources to a single one in
|
||||
-- decreasing priority, latching the data until a reset.
|
||||
arb: process (I_clk)
|
||||
begin
|
||||
if rising_edge(I_clk) then
|
||||
if I_reset = '1' then
|
||||
actual_int <= '0';
|
||||
int0_ack <= '0';
|
||||
int1_ack <= '0';
|
||||
int2_ack <= '0';
|
||||
int3_ack <= '0';
|
||||
elsif I_int0 = '1' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data0;
|
||||
int0_ack <= '1';
|
||||
if (I_int_data0(31) = '1') then
|
||||
actual_int_epc <= std_logic_vector(signed( I_PC) + 4);
|
||||
else
|
||||
actual_int_epc <= I_PC;
|
||||
end if;
|
||||
elsif I_int1 = '1' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data1;
|
||||
int1_ack <= '1';
|
||||
if (I_int_data1(31) = '1') then
|
||||
actual_int_epc <= std_logic_vector(signed( I_PC) + 4);
|
||||
else
|
||||
actual_int_epc <= I_PC;
|
||||
end if;
|
||||
elsif I_int2 = '1' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data2;
|
||||
int2_ack <= '1';
|
||||
if (I_int_data2(31) = '1') then
|
||||
actual_int_epc <= std_logic_vector(signed( I_PC) + 4);
|
||||
else
|
||||
actual_int_epc <= I_PC;
|
||||
end if;
|
||||
elsif I_int3 = '1' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data3;
|
||||
int3_ack <= '1';
|
||||
if (I_int_data3(31) = '1') then
|
||||
actual_int_epc <= std_logic_vector(signed( I_PC) + 4);
|
||||
else
|
||||
actual_int_epc <= I_PC;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end Behavioral;
|
|
@ -46,9 +46,9 @@ begin
|
|||
if rising_edge(I_clk) then
|
||||
case I_nPCop is
|
||||
when PCU_OP_NOP => -- NOP, keep PC the same/halt
|
||||
if I_intVec = '1' then -- in a NOP, you can get intterupts. check.
|
||||
current_pc <= ADDR_INTVEC;-- set PC to interrupt vector;
|
||||
end if;
|
||||
-- if I_intVec = '1' then -- in a NOP, you can get intterupts. check.
|
||||
-- current_pc <= ADDR_INTVEC;-- set PC to interrupt vector;
|
||||
-- end if;
|
||||
when PCU_OP_INC => -- increment
|
||||
current_pc <= std_logic_vector(unsigned(current_pc) + 4); -- 32bit byte addressing
|
||||
when PCU_OP_ASSIGN => -- set from external input
|
||||
|
|
|
@ -35,6 +35,7 @@ entity alu_RV32I is
|
|||
I_aluop : in STD_LOGIC_VECTOR (4 downto 0);
|
||||
I_aluFunc : in STD_LOGIC_VECTOR (15 downto 0);
|
||||
I_PC : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
I_epc : in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
I_dataIMM : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
O_branchTarget : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
|
@ -159,7 +160,13 @@ begin
|
|||
s_branchTarget <= std_logic_vector(signed( I_PC) + signed( I_dataIMM));
|
||||
s_shouldBranch <= '1';
|
||||
s_result(31 downto 0) <= std_logic_vector(signed( I_PC) + 4);
|
||||
|
||||
|
||||
when OPCODE_SYSTEM =>
|
||||
if I_aluFunc(9 downto 0) = F7_PRIVOP_MRET&F3_PRIVOP then
|
||||
s_branchTarget <= I_epc;
|
||||
s_shouldBranch <= '1';
|
||||
s_result(31 downto 0) <= std_logic_vector(signed( I_PC) + 4);
|
||||
end if;
|
||||
when OPCODE_LUI =>
|
||||
s_shouldBranch <= '0';
|
||||
s_result(31 downto 0) <= I_dataIMM;
|
||||
|
|
|
@ -38,7 +38,10 @@ entity decoder_RV32 is
|
|||
O_aluFunc : out STD_LOGIC_VECTOR (15 downto 0); -- ALU function
|
||||
O_memOp : out STD_LOGIC_VECTOR(4 downto 0); -- Memory operation
|
||||
O_csrOP : out STD_LOGIC_VECTOR(4 downto 0); -- CSR operations
|
||||
O_csrAddr : out STD_LOGIC_VECTOR(11 downto 0) -- CSR address
|
||||
O_csrAddr : out STD_LOGIC_VECTOR(11 downto 0); -- CSR address
|
||||
O_int : out STD_LOGIC; -- is there a trap?
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0); -- trap descriptor
|
||||
I_int_ack: in STD_LOGIC -- our int is now being serviced
|
||||
);
|
||||
end decoder_RV32;
|
||||
|
||||
|
@ -50,6 +53,9 @@ begin
|
|||
|
||||
process (I_clk, I_en)
|
||||
begin
|
||||
if rising_edge(I_clk) and I_int_ack = '1' then
|
||||
O_int <= '0';
|
||||
end if;
|
||||
if rising_edge(I_clk) and I_en = '1' then
|
||||
|
||||
O_selD <= I_dataInst(RD_START downto RD_END);
|
||||
|
@ -61,17 +67,20 @@ begin
|
|||
|
||||
case I_dataInst(OPCODE_START downto OPCODE_END_2) is
|
||||
when OPCODE_LUI =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "00000";
|
||||
O_dataIMM <= I_dataInst(IMM_U_START downto IMM_U_END)
|
||||
& "000000000000";
|
||||
when OPCODE_AUIPC =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "00000";
|
||||
O_dataIMM <= I_dataInst(IMM_U_START downto IMM_U_END)
|
||||
& "000000000000";
|
||||
when OPCODE_JAL =>
|
||||
if I_dataInst(RD_START downto RD_END) = "00000" then
|
||||
O_int <= '0';
|
||||
if I_dataInst(RD_START downto RD_END) = "00000" then
|
||||
O_regDwe <= '0';
|
||||
else
|
||||
O_regDwe <= '1';
|
||||
|
@ -83,7 +92,8 @@ begin
|
|||
O_dataIMM <= "000000000000" & I_dataInst(19 downto 12) & I_dataInst(20) & I_dataInst(30 downto 21) & '0';
|
||||
end if;
|
||||
when OPCODE_JALR =>
|
||||
if I_dataInst(RD_START downto RD_END) = "00000" then
|
||||
O_int <= '0';
|
||||
if I_dataInst(RD_START downto RD_END) = "00000" then
|
||||
O_regDwe <= '0';
|
||||
else
|
||||
O_regDwe <= '1';
|
||||
|
@ -94,7 +104,8 @@ begin
|
|||
else
|
||||
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
end if;
|
||||
when OPCODE_OPIMM =>
|
||||
when OPCODE_OPIMM =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "00000";
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
|
@ -102,23 +113,26 @@ begin
|
|||
else
|
||||
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
end if;
|
||||
when OPCODE_LOAD =>
|
||||
when OPCODE_LOAD =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "10" & I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
O_memOp <= "10" & I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
else
|
||||
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
end if;
|
||||
when OPCODE_STORE =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
O_memOp <= "11" & I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
O_memOp <= "11" & I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(IMM_S_A_START downto IMM_S_A_END) & I_dataInst(IMM_S_B_START downto IMM_S_B_END);
|
||||
else
|
||||
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_S_A_START downto IMM_S_A_END) & I_dataInst(IMM_S_B_START downto IMM_S_B_END);
|
||||
end if;
|
||||
when OPCODE_BRANCH =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
O_memOp <= "00000";
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
|
@ -127,15 +141,32 @@ begin
|
|||
O_dataIMM <= X"0000" & "0000" & I_dataInst(7) & I_dataInst(30 downto 25) & I_dataInst(11 downto 8) & '0';
|
||||
end if;
|
||||
when OPCODE_MISCMEM =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
O_memOp <= "01000";
|
||||
O_dataIMM <= I_dataInst;
|
||||
when OPCODE_SYSTEM =>
|
||||
O_memOp <= "00000";
|
||||
if I_dataInst(FUNCT3_START downto FUNCT3_END) = "000" then
|
||||
if I_dataInst(FUNCT3_START downto FUNCT3_END) = F3_PRIVOP then
|
||||
-- ECALL or EBREAK
|
||||
|
||||
case I_dataInst(IMM_I_START downto IMM_I_END) is
|
||||
when IMM_I_SYSTEM_ECALL =>
|
||||
-- raise trap, save pc, perform requiredCSR operations
|
||||
O_int <= '1';
|
||||
O_int_data <= EXCEPTION_INT_MACHINE_SOFTWARE;
|
||||
--todo: Priv level needs checked as to mask this to user/supervisor/machine level
|
||||
when IMM_I_SYSTEM_EBREAK =>
|
||||
O_int <= '1';
|
||||
O_int_data <= EXCEPTION_BREAKPOINT;
|
||||
|
||||
when F7_PRIVOP_MRET & R2_PRIV_RET =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
-- return from interrupt. implement as a branch - alu will branch to epc.
|
||||
when others =>
|
||||
end case;
|
||||
else
|
||||
O_int <= '0';
|
||||
-- CSR
|
||||
-- The immediate output is the zero-extended R1 value for Imm-form CSR ops
|
||||
O_dataIMM <= X"000000" & "000" & I_dataInst(R1_START downto R1_END);
|
||||
|
@ -163,9 +194,11 @@ begin
|
|||
|
||||
end if;
|
||||
when others =>
|
||||
O_memOp <= "00000";
|
||||
O_regDwe <= '1';
|
||||
O_dataIMM <= I_dataInst(IMM_I_START downto IMM_S_B_END)
|
||||
O_int <= '1';
|
||||
O_int_data <= EXCEPTION_INSTRUCTION_ILLEGAL;
|
||||
O_memOp <= "00000";
|
||||
O_regDwe <= '0';
|
||||
O_dataIMM <= I_dataInst(IMM_I_START downto IMM_S_B_END)
|
||||
& "0000000";
|
||||
end case;
|
||||
end if;
|
||||
|
|
Loading…
Add table
Reference in a new issue