I am currently doing work with the Cortex-M3 and am having trouble understanding the use of the xPSR. I am not sure why the ISR number is stored in lowest 8 bits.
Online sources and datasheets give no clue to why the number must be stored in the xPSR. On the ARM7-TDMI the current mode (FIQ, IRQ, SVC, USR, ABT, UND) is stored in the lowest 8 bits of the CPSR. I assume it is stored there so when an exception is raised and the mode is switched the processor knows which bank of registers to save the state of the CPSR to. However the Cortex-M3 doesn't have banked registers and the xPSR is saved onto the stack when an ISR is needed to be serviced.
Can anyone enlighten me?
Is this what you are talking about?
The IPSR
The processor writes to the IPSR on exception entry and exit. Software can use an MRS instruction, to read
the IPSR, but the processor ignores writes to the IPSR by an MSR instruction. The IPSR Exception Number
field is defined as follows:
• in Thread mode, the value is 0
• in Handler mode, holds the exception number of the currently-executing exception.
An exception number indicates the currently executing exception and its entry vector, see Exception number
definition on page B1-633 and The vector table on page B1-634.
On reset, the processor is in Thread mode and the Exception Number field of the IPSR is cleared to 0. As a
result, the value 1, the exception number for reset, is a transitory value, that software cannot see as a valid
IPSR Exception Number.
I would see that as similar to the cpsr in the ARMv4/ARM7TDMI as it gives you the state in which you are executing. if you are executing in an exception and if so which one. It likely has meaning to the chip designers for similar reasons and that is where that information or a copy of that information is held. Perhaps to not re-enter an exception handler if already in that exception mode for example. Or if a second exception of some type, say a prefetch abort while executing the prefetch abort perhaps the processor hangs on purpose or chooses a different exception.
Well, I'm not entirely sure I understand the question - are you asking "why is it different" or "what is the point"?
In the first case - the answer is the same as for "why does it not support the ARM instruction set", "why are there only 2 execution modes", "why is the vector table huge and contains addresses rather than instructions" and "why are there only 2 possible stack pointers": "because". Because the M-profile has a completely different exception model.
(And because the exception model is different, what was the mode bits in the CPSR was free to use for something else.)
In the second case ... well, that's up to the developer, isn't it?
There happens to be a register that holds the currently active interrupt ID. If this is of benefit to you, do use it.
You could (for example) use it to have a single interrupt handler address stored into multiple locations in the vector table and then use the interrupt ID to identify which specific device had triggered the interrupt.
It also sounds handy from the point of view of reentrant exception handling.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/CHDBIBGJ.html
Related
I'm running on a Raspberry Pi Pico (RP2040, Cortex-M0+ core, debugging via VSCode cortex-debug using JLink SWD), and I'm seeing strange behaviour regarding PendSV.
Immediately prior, the SVCall exception handler requested PendSV via the ICSR register. But on exception return, rather than tail-chaining the PendSV, execution instead returns to the calling code and continues non-exception execution.
All the while the ICSR register shows the pending PendSV, even while thread code instructions are repeatedly stepped. System handler priorities are all zero, IRQ priorities are lower.
According to the ARMv6-M reference manual, PendSV cannot be disabled.
So, what am I missing that would cause this behaviour?
Edited to add:
Perhaps it's a debugger interaction? The JLink software (v4.95d) is still in Beta...
I see that the debugger can actually disable PendSV and Systick - C1.5.1 Debug Stepping: "Optionally, the debugger can set DHCSR.C_MASKINTS to 1 to prevent PendSV, SysTick, and external configurable interrupts from occurring. This is described as masking these interrupts. Table C1-7 on page C1-326 summarizes instruction stepping control."
It turns out that the problem is caused by single-stepping the instruction that writes to the PENDSVSET bit in the ICSR: the bit is set, and the VECTPENDING field shows 0xe, but the PendSV never fires.
Free-running over that instruction to a later breakpoint sees the PendSV fire correctly.
So it is indeed a debugger interaction.
Whether that's to do with interrupts being inhibited as #cooperised suggests isn't clear - the DHCSR's C_MASKINTS bit reads as zero throughout, but how that bit is manipulated during the actual step operation isn't visible at this level.
Which makes me wonder whether the way the JLink is performing the step induces unpredictable/indeterminate behaviour - e.g. as per the warning in the C_MASKINTS description. Or perhaps this is simply what happens in an M0+ under these circumstances, and I've never single-stepped this instruction before.
In any case, the workaround is simply to not single-step the instruction that sets PENDSVSET.
Edited to add:
Finally, #cooperised was correct.
On taking more care to distinguish exactly between stepping (including stepping over function calls) and running (including running to the very next instruction), it's clear that stepping disables interrupts including PendSV.
The same thing happened to me but I found that the reason was that I was not closing the previous PensSV interrupt by returning through LR containing 0xFFFFFFF9. Instead I was returning via the PC to a previous routine's return address.
Since I did not return via 0xFFFFFFF9 it was not properly closing the previous PendSV and did not recognize subsequent ones.
How the processor detects that an exception is occurred? Where is the checkpoint for this? Does processor goes and checks after each F-D-E cycle for exception check or something similar? If it is processor specific, how it happens in arm?
Example: When we assert the IRQ or FIQ line, when system will go and check that line?
Every processor will have flag registers(also known as status register) at the hardware level to represent exceptions. The bits in the registers will be hardwired so as to notify an exception. The next instructions will be executed based on these registers.
Actually there isn't any checkpoint. An exception signal can be triggered at any stage of the pipeline. As a couple of examples, a division by zero on execute stage, an unknown instruction at decode stage, etc... Whenever these exceptions occur, the pipeline is flushed, and the program counter (PC) is updated with the address of the corresponding vector table entry. The bottom line is that the processor doesn't periodically check if there is an exception or not. When an exception is signalled it handles it instantly.
Reading 'ARM Architecture' on Wikipedia and found the following statement:
Registers R0-R7 are the same across all CPU modes; they are never
banked.
R13 and R14 are banked across all privileged CPU modes except system
mode.
What does banking a register mean?
Register banking refers to providing multiple copies of a register at the same address.
Taken from section 1.4.6 of the arm docs
The term is referring to a solution for the problem that not all registers can be seen at once.
There is a different register bank for each processor mode. The banked registers give rapid context switching for dealing with processor exceptions and privileged operations.
If your looking for a more theoretical reasoning, I recommend this paper.
Edit: A much deeper answer than mine is given here
When the processor enters an exception, the banked registers are switched automatically with another set of these registers.
Virtually, the exception handler routine doesn't have to save these registers on the stack to prevent them from being clobbered later on (by the exception handler functions). The processor just keeps a safe copy of that set; and will restore the original set on exception return.
This clip explains it well
https://youtu.be/7LqPJGnBPMM?t=1419
Banked registers are registers which are not needed and accessible by the current execution mode. When the execution mode changes, the registers needed for the new mode will become usable.
I'm currently reading/learning about ARM architecture ...
and I was wondering why there are so many modes
(FIQ, User, System, Supervisor, IRQ, ...).
My question is why do we need so many modes? Wouldn't just User and System be enough?
Thanks in advance.
It's just an architectural decision. The big advantage of the multiple modes is that they have some banked registers. Those extra registers allow you to write much less complicated exception routines.
If you were to pick only two, just USR and SYS are probably as good a choice as any, but what would happen when you took an exception? The normal ARM model is to go to an exception mode, set the banked link register for that exception mode to point to the instruction you want to return to after you resolve the exception, save the processor state in the exception mode's SPSR register, and then jump to the exception vector. USR and SYS share all their registers - using this model, you'd blow away your function return address (in LR) every time you took an interrupt!
The FIQ mode in particular has even more banked registers than the other exception modes. Those extra registers are in keeping with the "F" part of FIQ - it stands for "Fast". Not having to save and restore more processor context in software will speed up your interrupt handler.
Not too much to add to Carl's answer. Not sure what family / architecture of ARM processors you're talking about, so I'll just assume based on your question (FIQ, IRQ, etc.) that you're talking about ARM7/9/11. I won't enumerate every difference between every mode in every ARM architecture variant.
In addition to what Carl said, a few other advantages of having different modes for different circumstances:
for example, in the FIQ, you don't have to branch off right away, you can just keep on executing. With other exceptions you have to branch right away
with different modes, you have natural support for separate stacks. If you're multitasking (e.g., RTOS) and you don't have a separate stack when you're in an interrupt mode, you have to build-in extra space onto each task stack for the worst-case interrupt situation
with different modes, certain registers (e.g. CPSR, MMU regs, etc. - depends on architecture) are off-limits. Same thing with certain instructions. You don't want to let user code modify privileged registers, now do you?
Why should an ARM controller return to ARM state from THUMB state, when an exception occurs?
One explanation might be that ARM mode is the CPU's "native" operating mode, and that it's possible to do more operations in that mode than in the limited Thumb mode. The Thumb mode, as far as I've understood, is optimized for code size, which might mean it lacks certain instructions that perhaps are necessary in exception processing.
This page mentions that exception processing is always done in ARM mode. It doesn't provide any reasons why, so maybe it's just The Way It Is, by design. It does talk about ways to exit from exception processing back to the proper (ARM or Thumb) mode though, so as long as you're not writing the exception handler yourself, you might be able to ignore this issue. That, of course, assumes that your system is set up with a "default" exception handler that does retain the execution mode.
On the other hand, this page says this, about the interrupt vectors of the Cortex-M3 ARM implementation:
The LSB of each exception vector indicates whether the exception is to
be executed in the Thumb state.
So it doesn't seem to be universally true, perhaps you can make your particular exception run in Thumb mode.
Perhaps it is because that the interrupt vector table is really an ARM instruction and to process it requires being in ARM mode. This reduces the programmers job as you dont have to write two handlers one for arm mode and one for thumb mode. How would you even know there is one entry point for an exception and you can only have one instruction type to handle it. You can certainly switch to thumb mode once entered no different than switching to thumb mode after a reset exception.
The cortex-m3 has re-defined the interrupt vector table to be more traditional (an address instead of an instruction). By necessity I would assume, the cortex-m3 is a thumb(2) only processor so either they re-define the vector table to hold thumb instructions or they re-define the table with addresses, or they have just enough of an arm core to process the load or jump that you normally see in a vector table entry.
Basically you would either need two entries per exception, one for the arm based handler and one for the thumb based handler or you require the user to write their handler with an entry point that is one mode specifically.
Even with the one mode entry point into a handler, you still have to be aware of the mode the processor was in when the exception occurred to know what address to return to and how to inspect the instruction in question that caused the exception.
It depends which CPU you have, as there are two thumb instruction sets. The original thumb instruction set (used in armv4t, armv5te) lacked instructions to be able to deal with interrupts; the newer thumb2 set (in the cortex series) has extra instructions so you can remain in thumb2 mode to service an interrupt routine.
Traditional ARM systems boot into ARM mode and jumps to reset exception vector after reset. This means that all exception vectors have to be written in ARM assembly. If your exceptions are ARM instructions naturally the CPU is forced to change its mode to ARM mode before exception handling; if this does not happen it will result in an undefined exception, which will cause another one and so on and on in an infinite loop.
Initial ARM systems only had ARM instructions, the THUMB instructions were later added on; this might be another explanation.