/////////////////////////////////////////// // trap.sv // // Written: David_Harris@hmc.edu 9 January 2021 // Modified: dottolia@hmc.edu 14 April 2021: Add support for vectored interrupts // // Purpose: Handle Traps: Exceptions and Interrupt // See RISC-V Privileged Mode Specification 20190608 3.1.10-11 // // A component of the Wally configurable RISC-V project. // // Copyright (C) 2021 Harvey Mudd College & Oklahoma State University // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////// `include "wally-config.vh" module trap ( input logic clk, reset, input logic InstrMisalignedFaultM, InstrAccessFaultM, IllegalInstrFaultM, input logic BreakpointFaultM, LoadMisalignedFaultM, StoreMisalignedFaultM, input logic LoadAccessFaultM, StoreAccessFaultM, EcallFaultM, InstrPageFaultM, input logic LoadPageFaultM, StorePageFaultM, input logic mretM, sretM, uretM, input logic [1:0] PrivilegeModeW, NextPrivilegeModeM, input logic [`XLEN-1:0] MEPC_REGW, SEPC_REGW, UEPC_REGW, UTVEC_REGW, STVEC_REGW, MTVEC_REGW, input logic [11:0] MIP_REGW, MIE_REGW, SIP_REGW, SIE_REGW, input logic STATUS_MIE, STATUS_SIE, input logic [`XLEN-1:0] PCM, input logic [`XLEN-1:0] InstrMisalignedAdrM, MemAdrM, input logic [31:0] InstrM, input logic StallW, input logic InstrValidM, CommittedM, output logic TrapM, MTrapM, STrapM, UTrapM, RetM, output logic InterruptM, output logic ExceptionM, output logic PendingInterruptM, output logic [`XLEN-1:0] PrivilegedNextPCM, CauseM, NextFaultMtvalM // output logic [11:0] MIP_REGW, SIP_REGW, UIP_REGW, MIE_REGW, SIE_REGW, UIE_REGW, // input logic WriteMIPM, WriteSIPM, WriteUIPM, WriteMIEM, WriteSIEM, WriteUIEM ); logic MIntGlobalEnM, SIntGlobalEnM; logic [11:0] PendingIntsM; //logic InterruptM; logic [`XLEN-1:0] PrivilegedTrapVector, PrivilegedVectoredTrapVector; logic Exception1M; // Determine pending enabled interrupts // interrupt if any sources are pending // & with a M stage valid bit to avoid interrupts from interrupt a nonexistent flushed instruction (in the M stage) // & with ~CommittedM to make sure MEPC isn't chosen so as to rerun the same instr twice assign MIntGlobalEnM = (PrivilegeModeW != `M_MODE) || STATUS_MIE; // if M ints enabled or lower priv 3.1.9 assign SIntGlobalEnM = (PrivilegeModeW == `U_MODE) || ((PrivilegeModeW == `S_MODE) && STATUS_SIE); // if in lower priv mode, or if S ints enabled and not in higher priv mode 3.1.9 assign PendingIntsM = ((MIP_REGW & MIE_REGW) & ({12{MIntGlobalEnM}} & 12'h888)) | ((SIP_REGW & SIE_REGW) & ({12{SIntGlobalEnM}} & 12'h222)); assign PendingInterruptM = (|PendingIntsM) & InstrValidM; assign InterruptM = PendingInterruptM & ~CommittedM; //assign ExceptionM = TrapM; assign ExceptionM = Exception1M; // *** as of 7/17/21, the system passes with this definition of ExceptionM as being all traps and fails if ExceptionM = Exception1M // with no interrupts. However, Ross intended the datacache to use Exception without interrupts, so there is something subtle // to sort out here. // *** as of 8/13/21, switching to Exception1M does not seem to cause any failures. It's possible the bug was // fixed inadvertantly as the dcache was debugged. // Trigger Traps and RET // According to RISC-V Spec Section 1.6, exceptions are caused by instructions. Interrupts are external asynchronous. // Traps are the union of exceptions and interrupts. assign Exception1M = InstrMisalignedFaultM | InstrAccessFaultM | IllegalInstrFaultM | LoadMisalignedFaultM | StoreMisalignedFaultM | InstrPageFaultM | LoadPageFaultM | StorePageFaultM | BreakpointFaultM | EcallFaultM | LoadAccessFaultM | StoreAccessFaultM; assign TrapM = Exception1M | InterruptM; // *** clean this up later DH assign MTrapM = TrapM & (NextPrivilegeModeM == `M_MODE); assign STrapM = TrapM & (NextPrivilegeModeM == `S_MODE) & `S_SUPPORTED; assign UTrapM = TrapM & (NextPrivilegeModeM == `U_MODE) & `N_SUPPORTED; assign RetM = mretM | sretM | uretM; always_comb if (NextPrivilegeModeM == `U_MODE) PrivilegedTrapVector = UTVEC_REGW; else if (NextPrivilegeModeM == `S_MODE) PrivilegedTrapVector = STVEC_REGW; else PrivilegedTrapVector = MTVEC_REGW; // Handle vectored traps (when mtvec/stvec/utvec csr value has bits [1:0] == 01) // For vectored traps, set program counter to _tvec value + 4 times the cause code // // POSSIBLE OPTIMIZATION: // From 20190608 privielegd spec page 27 (3.1.7) // > Allowing coarser alignments in Vectored mode enables vectoring to be // > implemented without a hardware adder circuit. // For example, we could require m/stvec be aligned on 7 bits to let us replace the adder directly below with // [untested] PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:7], CauseM[3:0], 4'b0000} generate if(`VECTORED_INTERRUPTS_SUPPORTED) begin always_comb if (PrivilegedTrapVector[1:0] == 2'b01 && CauseM[`XLEN-1] == 1) PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2] + {CauseM[`XLEN-5:0], 2'b00}, 2'b00}; else PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2], 2'b00}; end else begin assign PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2], 2'b00}; end endgenerate always_comb if (mretM) PrivilegedNextPCM = MEPC_REGW; else if (sretM) PrivilegedNextPCM = SEPC_REGW; else if (uretM) PrivilegedNextPCM = UEPC_REGW; else PrivilegedNextPCM = PrivilegedVectoredTrapVector; // Cause priority defined in table 3.7 of 20190608 privileged spec // Exceptions are of lower priority than all interrupts (3.1.9) always_comb if (reset) CauseM = 0; // hard reset 3.3 else if (PendingIntsM[11]) CauseM = (1 << (`XLEN-1)) + 11; // Machine External Int else if (PendingIntsM[3]) CauseM = (1 << (`XLEN-1)) + 3; // Machine Sw Int else if (PendingIntsM[7]) CauseM = (1 << (`XLEN-1)) + 7; // Machine Timer Int else if (PendingIntsM[9]) CauseM = (1 << (`XLEN-1)) + 9; // Supervisor External Int else if (PendingIntsM[1]) CauseM = (1 << (`XLEN-1)) + 1; // Supervisor Sw Int else if (PendingIntsM[5]) CauseM = (1 << (`XLEN-1)) + 5; // Supervisor Timer Int else if (InstrPageFaultM) CauseM = 12; else if (InstrAccessFaultM) CauseM = 1; else if (InstrMisalignedFaultM) CauseM = 0; else if (IllegalInstrFaultM) CauseM = 2; else if (BreakpointFaultM) CauseM = 3; else if (EcallFaultM) CauseM = {{(`XLEN-2){1'b0}}, PrivilegeModeW} + 8; else if (LoadMisalignedFaultM) CauseM = 4; else if (StoreMisalignedFaultM) CauseM = 6; else if (LoadPageFaultM) CauseM = 13; else if (StorePageFaultM) CauseM = 15; else if (LoadAccessFaultM) CauseM = 5; else if (StoreAccessFaultM) CauseM = 7; else CauseM = 0; // MTVAL // 3.1.17: on instruction fetch, load, or store address misaligned access or page fault // mtval is written with the faulting virtual address. // On illegal instruction trap, mtval may be written with faulting instruction // For other traps (including interrupts), mtval is set to 0 // *** hardware breakpoint is supposed to write faulting virtual address per priv p. 38 // *** Page faults not yet implemented // Technically always_comb if (InstrMisalignedFaultM) NextFaultMtvalM = InstrMisalignedAdrM; else if (LoadMisalignedFaultM) NextFaultMtvalM = MemAdrM; else if (StoreMisalignedFaultM) NextFaultMtvalM = MemAdrM; else if (BreakpointFaultM) NextFaultMtvalM = PCM; else if (InstrPageFaultM) NextFaultMtvalM = PCM; else if (LoadPageFaultM) NextFaultMtvalM = MemAdrM; else if (StorePageFaultM) NextFaultMtvalM = MemAdrM; else if (IllegalInstrFaultM) NextFaultMtvalM = {{(`XLEN-32){1'b0}}, InstrM}; else NextFaultMtvalM = 0; endmodule