The Reset, Soft Reset, and NMI exceptions are always vectored to location 0xBFC00000 (uncached, start-up safe KSEG1 region).
Addresses for all other exceptions are a combination of a vector base address and a vector offset.
Exception Vector "Base" Addresses
In MIPS32® Release 2 and higher architectures, software is allowed to specify the vector base address via the CP0 Ebase register for exceptions that occur when CP0 StatusBEV equals 0.
StatusBEV:
MIPS32® architectures provide a "bootstrap" mode (referred to as Boot-Exception Vector (BEV) mode) whereby exception entry points are reallocated into the uncached, start-up-safe KSEG1 region.
Bootstrap mode is controlled by the CP0 Status register flag StatusBEV
- StatusBEV = 1: Exceptions vector to an uncached entry point in KSEG1: 0xBFC00xxx
- StatusBEV = 0: Exceptions vector to cached entry points in KSEG0: defined by CP0 Ebase register, plus some offset
Note: StatusBEV = 1 at reset.
The following table gives the vector base address as a function of the exception and whether the BEV bit is set in the Status register:
MPLAB® XC32 start-up code initializes Ebase to the value defined by the symbol _ebase_address in the PIC32MX device linker script (for PIC32MX795F512L, _ebase_address = 0x9FC01000)
If Ebase is to be changed, it must be done with StatusBEV = 1 (i.e. at system boot). The operation of the CPU is UNDEFINED if Ebase is written when StatusBEV = 0.
Vector "Offsets"
Next, we have fixed vector offsets which are added to the above exception base addresses as a function of the exception:
CauseIV:
Setting the CP0 CauseIV bit to 1 causes Interrupt exceptions to use a dedicated exception vector offset (0x200), rather than having to use the general exception vector offset (0x180).
MPLAB® XC32 start-up code initializes CauseIV to 1.
"Final" Entry Point Addresses
PIC32MX Interrupt exception vector addresses have an additional computed offset component which is added to Ebase and the fixed offset (0x200) shown above:
- Computed Offset = Interrupt Vector Number (0-63) * Interrupt Vector Spacing (as defined by CP0 register/bitfield IntCtlVS)
We can now list the complete vector addresses for the most common exceptions (not incl. EJTAG or TLB exceptions):
IntCtlVS:
These bits specify the spacing between each interrupt vector for CPUs supporting Computed Interrupt Vector Offsets (PIC32MX).
MPLAB® XC32 start-up code initializes IntCtlVS to 0x01, which encodes a spacing of 32 bytes (8 words) between interrupt exception vectors.
Ebase:
MPLAB® XC32 start-up code initializes Ebase to the value defined by the symbol _ebase_address in the PIC32MX device linker script (for PIC32MX795F512L, _ebase_address = 0x9FC01000)
Therefore, for normal interrupt operations on PIC32MX,
- The Interrupt Exception Vector Base Address = 0x9FC01000
- The Interrupt Exception Vector Final Address = 0x9FC01000 + 0x200 + (VectNum*IntCtlVS)
For an illustration, see the Timer 2 Interrupt Vector Address calculation example below.
StatusEXL:
Exception Level: Set by the processor when any exception other than Reset, Soft Reset, NMI or Cache Error exception are taken
- StatusEXL = 0: Normal level
- StatusEXL = 1: Exception level; when EXL is set
- The processor is running in Kernel Mode
- Hardware and Software Interrupts are disabled
- EPC, BD, and SRSCtl will not be updated if another exception is taken
Note: StatusEXL must be cleared by the exception handler in order to re-enable interrupts. MIPS® CPUs have an instruction, eret, that both clears StatusEXL and returns control to the address stored in EPC.
Interrupt Exception Vectors
As discussed above, PIC32MX interrupt controllers operating in Multi-Vector Mode implement a "computed offset" mode for calculating the final interrupt vector address:
- Interrupt Exception Vector Final Address = Ebase + 0x200 + (VectNum * IntCtlVS)
The MPLAB® XC32 Compiler calculates & initializes the vector address for each defined application interrupt service routine (see Table 7.1 in the PIC32MX data sheet for a listing of vector numbers assigned to each interrupt source).
Example
The following example illustrates how the Timer 2 Interrupt Vector Entry Point is calculated/initialized:
Ebase
- 0x9FC01000 (initialized by the C-Run-time startup)
IntCtlVS
- 0x01 (Interrupt Vector Spacing = 32 bytes (0x20) - initialized by the default C-Run-time startup code)
Timer 2 Interrupt Vector Number
- 8 (from Table 7.1)
Timer 2 Interrupt Exception Vector Final Address
- 0x9FC01000 + 0x200 + (8 * 32) = 0x9FC01300
In most cases, since the spacing between interrupt exception vectors is insufficient to hold the entire handler routine, the compiler will insert an unconditional jump to the start address of the handler routine as shown in this example:
An interrupt handler function can be associated with an interrupt vector either as the target of a dispatch function located at the exception vector address (as shown in the above example), or as being located directly at the exception vector address.
Handler functions that are linked directly to the vector will be executed faster. Although the vector spacing can be adjusted, there is limited space between vectors and linking a substantial handler function directly at a vector may cause it to overlap the higher vector locations, preventing their use. In such situations, using a dispatch function is a safer option.
MPLAB® XC32 start-up code initializes IntCtlVS to the value defined by the symbol _vector_spacing in the PIC32MX device linker script (for PIC32MX795F512L, _vector_spacing = 0x00000001, which corresponds to the spacing of 32 bytes or 8 words), however, by using function attributes, a handler can be located directly at the vector address. See the MPLAB® XC32 User's Manual for details.