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:
Colin Riley 2018-11-21 23:45:51 +00:00
parent a9c5413cd9
commit bb6683092f
7 changed files with 338 additions and 46 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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
View 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;

View file

@ -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

View file

@ -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;

View file

@ -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;