The file ARM\IntARM5.fth contains generic ARM interrupt handlers, plus alternative handlers for CPUs with vectored interrupt controllers. It replaces ARM\IntARM3/4.fth for new code with no changes to word usage. The main difference in IntARM5.fth is that R8 is assumed to be the floating point stack pointer. If you are using MPE-supplied VFP floating point or separate stack code, you should use IntARM5.fth. You are recommended to use INTARM5.fth for new code. In most cases, the only change required is to change the file name in your control file.
IntARM5.fth requires ARM\ARMDEF.FTH to be compiled before the SFRxxxx file for your particular CPU. The file ARM/STACKDEF.FTH* provides default main task and stack layouts and should be compiled from the control file or copied into your control file. Default stack initialisation code is provided by the assembler routine InitStacks in ARM\InitStacks.fth. This routine can be referenced from your initialisation code.
The IntARM5/4/3.fth interrupt handlers are much more paranoid, and hence safer, than previous releases. The default diagnostic code gives much more information when an abort occurs. The files INTARM.FTH, INTARM2.FTH, ARM\IntARM3.fth, INTS3C4510.FTH and INTAT91.FTH remain in the distribution but are no longer supported.
Separate sections are provided for CPUs with vectored interrupt controllers, e.g. AT91 and Samsung, and these may have a different word set for initialising interrupts. Be careful with these to distinguish between Forth words (denoted by XTs) and the interrupt service routines (denoted by ISRs) that despatch the Forth words.
Each exception (interrupt) type requires a predefined stack frame on which the interrupt handler builds the Forth stacks and USER area. The system initialisation code must preset the banked R13 registers to the top of the frames. This code requires the Forth return stack pointer to be R13.
The IRQ handlers all share a common "stack of stacks". On entry to the interrupt handler, Forth system registers are allocated. Your initialisation code MUST set up R13 for each CPU mode. See ARM\CONFIGS\LPC2106U.CTL (contains stack layout) and ARM\HARDWARE\INITLPC210X.FTH (contains initialisation code) for examples.
From IntARM4.fth onwards, FIQ handlers take more advantage of the banked registers to speed up the FIQ entry and exit code. Nesting of FIQ interrupts is not supported.
In order to support exception nesting the equate #IRQs in the control file must be set to the maximum number of nestings required for ALL modes. When #IRQs is greater than 1 (to indicate IRQ nesting), the exception handler entry and exit code is extended to handle all exceptions in SVC mode. This avoids corruption of R14 (the LINK register) when nesting occurs. The equate #IRQs is used to calculate the size and layout of the IRQ and SVC mode stacks along with the equates #SWIs and #FIQs in the control file.
Note that each interrupt has its own USER area, but that NO USER VARIABLES ARE INITIALISED except for S0 and R0 in SWI handlers.
Note that it is assumed that the banked stack pointers have already been set up by the hardware initialisation code.
Note that it is implicit throughout the code that the four system registers UP, PSP, FSP, RSP are always set so that:
UP > PSP > FSP > RSP
Because of this layout, data stack underflows may corrupt the first part of the USER area. You have been warned. During testing, it may be as well to set the equate SP-GUARD to 2 or 3 in your control file to leave a few guard cells on the data stack.
The floating point stack (FSP = ARM R8) will be set up if the equate FP-SIZE is non-zero.
0 equ FP-SIZE \ -- 0
Set FP-SIZE to zero if undefined.
The following equates define values used for the equate ARM-VIC? that controls how IRQ and FIQ exceptions are processed. Note that if ARM-VIC? contains any other values, no IRQ or FIQ code will be compiled, permitting you to define different versions for other CPUs in another file. If you find and code other vectored interrupt controllers for ARMs, we will be happy to include your code in this file in future releases.
0 equ NO-VIC \ -- n
specifies that no vectored interrupt controller is present.
1 equ AT91-VIC \ -- n
specifies that the AT91 AIC vectored interrupt controller
is present.
2 equ S3C-VIC \ -- n
specifies that the Samsung vectored interrupt controller
as used in the S3C4510B is present.
3 equ PL190-VIC \ -- n
Specifies that the ARM PL190 vectored interrupt controller
as used by the Philips LPC210x is present.
4 equ AT91GIC-VIC \ -- n
specifies that the AT91 GIC vectored interrupt controller
as used in AT91SAMxxx devices is present.
5 equ PL192-VIC \ -- n
Specifies that the ARM PL192 vectored interrupt controller
as used by the Philips LPC23xx/24xx is present.
NO-VIC equ ARM-VIC? \ -- n
If the equate ARM-VIC? is undefined before this file is compiled,
the generic (no vectored controller) will be compiled for FIQ and
IRQ handling.
The following equates define what code is compiled. If they are defined before IntARM4.fth the default values below will be overridden.
1 equ test-isr? \ -- n ; non-zero to compile test code
Non-zero to compile test and diagnostic code.
0 equ SimpleAborts? \ -- n
If this equate is non-zero, simple DAbort, PAbort, and Undef
handlers are installed.
The simple high level action receives only a pointer to the instruction
that caused the abort and issues a simple message.
If this equate is zero, a more complex DAbort handler is installed.
The complex high level action receives a pointer to a status
frame and a pointer to the instruction that caused the abort.
The complex handlers are compiled if TEST-ISR? is nonzero.
They perform a register dump and a return stack trace.
The additional code space required for complex handlers is
about 2300 bytes.
0 equ Reserved_ISR? \ -- n
When non-zero, a handler will be installed for the RESERVED
exception (vector at $0000:0014). This vector was used by the
26 bit architecture, but is now reserved for future expansion.
It is used for other purposes by some CPUs, e.g. Philips LPC2xxx.
: !call \ xt addr --
An INTERPRETER word to create a call opcode to xt at addr.
proc initFIQ \ --
Initialise FIQ banked registers. R0 contains the top of the
FIQ stack frame. R0 and R5 must not be changed. Modifies
RSP, PSP, UP and R4. This routine is called by InitStacks.
code EFI \ -- ; enable FIQ interrupt
Global enable FIQ interrupt.
code DFI \ -- ; disable interrupts
Global disable FIQ interrupt.
code EI \ -- ; enable interrupts
Global enable IRQ.
code DI \ -- ; disable interrupts
Global disable IRQ.
code [I \ R: -- x ; preserve I/F status on return stack, disable ints
Preserve I/F status on return stack, disable IRQ.
The state is restored by I].
code I] \ R: x -- ; restore int. status from r. stack
Restore interrupt status saved by [I from the return stack.
The interrupt structure of the ARM is such that the simplest way to display exception information without large code and RAM overheads is to use polled operation of the comms link without interrupts. By default, the fault handler only transmits, it does not use KEY. If your serial driver normally uses interrupt-driven transmit routines, you must provide the word +FaultConsole which switches it into polled operation. An example can be found in ARM/Drivers/serLPC210xqi.fth.
By default, there is no return from a fault handler, the system is reset using REBOOT. From experience, attempting to restart the system by executing the boot vector is not enough. Rebooting by triggering the watchdog always works.
In the (rare) case that SWIs are used, perform I/O and return, you must be careful with interrupt re-enabling if you want to use the interrupt driven I/O drivers inside the SWI handler. Your serial driver will also have to provide -FaultConsole.
: intoFault \ --
Set up I/O for a fault handler.
The SWI handler is only compiled if the equate #SWIs is non-zero.
The SWI handler assumes that we may already be in supervisor mode, and that the RSP must be preserved. A new RSP stack is allocated, and the original RSP, R4..R12 and LINK are saved on the new RSP stack. New data stack and USER area are then allocated, parameters R0..R2 and the SWI# are put on the new data stack, and the handler is executed. On return, registers RSP and R3..12 are restored. R2 will be destroyed. Return data (if any) may be placed in R0 and R1.
By default, on entry to SWI_HANDLER, TOS contains the SWI#, and the next three items contain R0..2. This is done so that the standard ARM SWI calls can be emulated. Although it is not strictly necessary to remove this data, a canonical handler will have the stack effect:
SWI_ACTION \ r2 r1 r0 swi# -- r1' r0'
defer SWI_handler \ r2 r1 r0 swi# -- r1' r0' ; default action
The default action is 2DROP. Assign your own action
to this word.
assign mySwi to-do SWI_handler
PROC SWI_exception \ --
The actual SWI handler which calls SWI_handler above.
It assumes RSP=R13, R0-2 are parameters, R2 will be destroyed,
Return parameters are in R0-R1, R3..R13 will be preserved
: testswi \ r2 r1 r0 -- r1' r0' ; executes swi0
An example SWI handler.
code run-swi0 \ r2 r1 r0 -- r1 r0
Test execution of SWI 0.
The complex exception handlers store the ARM CPU state in a data frame. The frame is 72 bytes long (18 4 byte cells), whose format is:
|
struct /exframe \ -- n
structure defining the exception frame
: .item \ addr -- addr+4
Display a cell item at addr and increment addr.
: .items \ addr n -- addr+4n
Display n items at addr and increment addr.
: .frame \ ^frame --
Display the CPU state pointed to by the data frame.
: name? \ addr -- flag
Check to see if the supplied address is a valid NFA.
This word is implementation dependent.
A valid NFA for MPE embedded systems satisfies the following:
: ip>nfa \ addr -- nfa
Attempt to move backwards from an address within a definition
to the relevant NFA.
: check-aligned \ addr -- addr'
Check addr for cell alignment, report and correct if
misaligned.
: ?Clip32 \ xsp xspTop -- xsp xspTop'
Clip the stack display to 32 items.
: .rsframe \ ^frame --
Display the return stack indicated by the frame, assuming
the Forth RSP=R13 and RUP=R11.
: .psframe \ ^frame --
Display the data stack indicated by the frame, assuming
the Forth PSP=R12 and RUP=R11.
defer Undef_handler \ ^ins --
The place holder for the Undefined Instruction handler has
a default action of DROP.
: testundef \ ^ins -- ; handle undefined instruction
Test handler for Undefined Instructions.
: run-undef \ --
Causes an Undefined Instruction exception.
defer Undef_handler \ ^frame ^ins -- fixed? ; true if instruction fixed up
Given a pointer to a data frame and a pointer to the instruction,
returns true if a fixup has been performed. If the return value
is non-zero, the instruction is rerun otherwise the instruction
is skipped.
: testundef \ ^frame ^ins -- fixed? ; handle undefined instruction
Test handler for Undefined Instructions.
: run-undef \ --
Causes an Undefined Instruction exception.
defer PAbort_handler \ ^ins -- fixed?
Given a pointer to an instruction, returns true if a fixup has been
performed. If the return value is non-zero, the instruction is rerun
otherwise the instruction is skipped.
: testpabort \ ^ins -- fixed?
Test PAbort handler.
: run-pabort \ --
Run the test PAbort handler.
: run-pabort \ --
Run the test PAbort handler.
defer PAbort_handler \ ^frame ^ins -- fixed? ; true if instruction fixed up
Given a pointer to a data frame and a pointer to the instruction,
returns true if a fixup has been performed. If the return value
is non-zero, the instruction is rerun otherwise the instruction
is skipped.
: testPabort \ ^frame ^ins -- fixed?
Test PABORT handler.
: run-Pabort $05000000 execute ; \ hardware specific
Run test PAbort handler.
defer DAbort_handler \ ^ins -- fixed? ; true if instruction fixed up
Given a pointer to an instruction, returns true if a fixup has been
performed. If the return value is non-zero, the instruction is rerun
otherwise the instruction is skipped.
: testdabort \ ^ins -- fixed?
Test DABORT handler.
: run-dabort $04000000 @ ; \ hardware specific
Run test PAbort handler.
defer DAbort_handler \ ^frame ^ins -- fixed? ; true if instruction fixed up
Given a pointer to a data frame and a pointer to the instruction,
returns true if a fixup has been performed. If the return value
is non-zero, the instruction is rerun otherwise the instruction
is skipped. The frame format is as for the PAbort handler above.
: testdabort \ ^frame ^ins -- fixed?
Test DABORT handler.
: run-dabort $05000000 @ drop ; \ hardware specific
Run test DAbort handler.
This exception is only used for systems and compilers which support the 26 bit PC mode of early ARM cores. The ARM/Cortex compilers do not support 26 bit mode, but ARM only compilers do.
defer Unused_handler \ ^ins -- fixed?
Given a pointer to an instruction, returns true if a fixup has been
performed. If the return value is non-zero, the instruction is rerun
otherwise the instruction is skipped.
PROC Unused_exception \ --
The UNUSED exception handler calls UNUSED_handler above.
: testunused \ --
Test code for the UNUSED exception.
The ARM architecture does not define a vectored interrupt controller, although several CPUs provide one. If the CPU has a vectored controller, it should be used. This implementation provides a linked list of routines to be called, each of which tests for its own interrupt and then handles it if required. The last item in the chain is the return from IRQ routine. The variable NEXT-IRQ points to the first ISR to execute.
Note that this routine must be modified to support nested interrupts. Because the IRQ mode link register (R11) is set by an interrupt response, as well as by the BL instruction, if an interrupt is accepted after a BL instruction but before R11 is saved, R11 will be corrupted. The result of this is that nestable interrupt handlers must switch to another mode (e.g. SVC) before re-enabling interrupts. This is handled by code in the IRQ_EXCEPTION and IRQ_RETI routines below.
The required modification is performed if the EQUate #IRQs is greater than one, whereupon IRQ nesting is supported with the penalty of greater overhead. IF IRQ nesting is required, the IRQ stack size should be at least 64*#IRQs bytes, and TASK-SIZE*#IRQs bytes should be added to the SWI stack. If IRQ nesting is not required the IRQ stack must be at least TASK-SIZE bytes.
variable next-irq \ -- addr
Holds pointer to next ISR to run.
ISRs are added to this chain.
PROC IRQ_exception \ -- ; IRQ entry code
The IRQ handler entry point which executes the chain.
The USER variables S0 and R0 are initialised.
proc IRQ_reti \ -- ; IRQ exit code
This code cleans up after the IRQ and is the first item added
to the IRQ chain.
: br24, \ xt opcode --
Given an opcode (B or BL) and an execution address,
compiles a branch or call to it.
: add-isr \ xt chain -- ; ' <name> <chain_var> ADD-ISR adds name to the ISR handler list
An action is added to the IRQ or FIQ chain by a phrase of the form:
' <name> <chain_var> ADD-ISR
: add-irq \ xt -- ; ' <name> ADD-IRQ adds name to the IRQ handler list
An action is added to the IRQ chain by a phrase of the form:
' <name> ADD-IRQ
Note that FIQ interrupt nesting is NOT supported by default. If it is required, use the Generic IRQ handler as a model, and do not forget to switch back to FIQ mode rather than IRQ mode.
variable next-fiq \ -- addr
Holds pointer to next ISR to run. FIQ ISRs are
added to this chain
PROC FIQ_exception \ --
FIQ entry code.
proc FIQ_reti \ --
FIQ exit code.
: add-fiq \ xt -- ; adds action to FIQ handler list
An action is added to the FIQ chain by a phrase of the form:
' <name> ADD-FIQ
This section is not a treatise on the Atmel Advanced Interrupt Controller. These words provide a fairly basic set of tools for using the AIC. The notes in the Generic IRQ section about interrupt nesting apply here.
This code requires Kernel62.fth and the equate COLDCHAIN? must be set non-zero in the control file.
Basic clock enabling of the AIC should be performed in the CPU specific startup file, e.g. ARM\HARDWARE\EB55\INITARM55800.FTH.
If the EQUate #IRQs is greater than one, IRQ nesting is supported with the penalty of greater overhead. IF IRQ nesting is required, the IRQ stack size should be at least 64*#IRQs bytes, and TASK-SIZE*#IRQs bytes should be added to the SWI stack. If IRQ nesting is not required the IRQ stack must be at least TASK-SIZE bytes.
PROC IRQ_entry \ --
This is the template code for vectored IRQ interrupt handlers.
It is also used as the spurious interrupt handler.
PROC FIQ_entry \ --
This is the template code for vectored FIQ interrupt handlers.
: IRQ: \ xt "<name>" -- ; -- isr
Creates an IRQ ISR that runs the given Forth word. At run
time the entry point of the ISR is returned. Use in the form:
' <action> IRQ: <actionISR>
: FIQ: \ xt "<name>" -- ; -- isr
Creates an FIQ ISR that runs the given Forth word. At run
time the address of the ISR is returned. Use in the form:
' <action> FIQ: <actionISR>
: SetDefIRQ \ xt --
Set the spurious IRQ handler to call the Forth word whose xt
is given. Use interpretively in the form:
' <word> SetDefIRQ
The compiler sets this action to NOOP unless you use SetDefIRQ.
: InitSPU \ --
Initialise the spurious interrupt vector.
This word is executed as part of the cold chain.
: EnInt \ int# --
Enable the requested AIC interrupt.
: DisInt \ int# --
Disable the requested AIC interrupt.
: SetIRQisr \ isr mode int# --
Set the ISR to be the action of IRQ INT# with mode being
set into the relevant AIC SMR register. Then enable the
interrupt. The FIQ interrupt is set with INT#=0 for which
the priority is unused. Note that Forth IRQ interrupt handlers
must be created with IRQ: and Forth FIQ handlers with
FIQ:. Assembler routines may be created using:
PROC <name> ... END-CODE
Interrupt numbers may be found in the AIC section of the CPU data sheet.
The mode value is a combination of priority 0..7 and interrupt type as follows. Only the first two should be used for internal interrupts.
$000 equ ISR_low \ -- n
Low level sensitive.
$020 equ ISR_nedge \ -- n
Negative edge triggered.
$040 equ ISR_high \ -- n
High level sensitive.
$080 equ ISR_pedge \ -- n
Positive edge triggered.
An example of setting up an interrupt follows.
|
This implementation does NOT support nested FIQ interrupts. The notes in the Generic IRQ section about interrupt nesting apply here.
If the EQUate #IRQs is greater than one, IRQ nesting is supported with the penalty of greater overhead. IF IRQ nesting is required, the IRQ stack size should be at least 64*#IRQs bytes, and TASK-SIZE*#IRQs bytes should be added to the SWI stack. If IRQ nesting is not required the IRQ stack must be at least TASK-SIZE bytes.
create despatch_table \ -- addr ; 21 entry interrupt despatch table
This table holds the addresses (XTs) of the service routines
for each of the 20 interrupts plus a dummy for false interrupts.
Equates for the interrupt numbers and their bit positions may
be found in the file SFRS3C4510.FTH. This table is defined
in the CDATA section because it is assumed that the code is run
from RAM. If this is not so, change the CDATA above the definition
as required, usually to IDATA.
: SetFIQ \ xt int# --
Set the XT to be the action of FIQ INT#.
: SetIRQ \ xt int# --
Set the XT to be the action of IRQ INT#.
: EnInt \ int# --
Enable the requested interrupt.
: DisInt \ int# --
Disable the requested interrupt.
This section is not a treatise on the ARM PL190 Vectored Interrupt Controller. These words provide a fairly basic set of tools for using the ARM PL190 VIC, which is fully documented in the ARM Technical Publications CD available free of charge from www.arm.com. The notes in the Generic IRQ section about interrupt nesting apply here.
This code requires Kernel62.fth and the equate COLDCHAIN? must be set non-zero in the control file. The VIC addresses should be defined in the SFRxxxx.fth file which defines the peripheral address for the silicon.
If the EQUate #IRQs is greater than one, IRQ nesting is supported with the penalty of greater overhead. IF IRQ nesting is required, the IRQ stack size should be at least 64*#IRQs bytes, and TASK-SIZE*#IRQs bytes should be added to the SWI stack. If IRQ nesting is not required the IRQ stack must be at least TASK-SIZE bytes.
FIQ nesting is not supported by this code. The FIQ stack must be at least TASK-SIZE bytes.
1 equ #VICs \ -- n
If this equate has not already been set, a value of 1 is used.
If more than one is defined, the base addresses must be named
_VICn, and the primary VIC must also be named _VIC.
PROC IRQ_entry \ --
This is the template code for vectored IRQ interrupt handlers.
It is also used as the default interrupt handler.
PROC FIQ_entry \ --
This is the wrapper code for FIQ interrupt handlers.
: IRQ: \ xt -- ; -- isr
Creates an IRQ ISR that runs the given Forth word. At run
time the entry point of the ISR is returned. Use in the form:
' <action> IRQ: <actionISR>
: SetDefIRQ \ xt --
Set the default IRQ handler to call the Forth word whose xt
is given. Use interpretively in the form:
' <word> SetDefIRQ
The compiler sets this action to NOOP unless you use SETDEFIRQ.
: SetFIQ \ xt --
Set the FIQ interrupt to call the Forth word whose xt is
given. Use interpretively in the form:
' <word> SetFIQ
: InitVIC \ --
Initialise the VIC Default interrupt vector.
This word is executed as part of the cold chain.
: EnInt \ src# --
Enable the requested VIC interrupt source.
: DisInt \ src# --
Disable the requested VIC interrupt source.
: SetIrqIsr \ isr src# slot# --
Set the ISR to be the action of the source interrupt number
src# (0..31) being set into the corresponding slot
(slot# = 0..15) where slot# corresponds to priority
(0 = highest priority). Then enable the
interrupt. Note that Forth IRQ interrupt handlers
must be created with IRQ: <name>.
Assembler routines may be created using:
PROC <name> ... END-CODE
Interrupt source numbers may be found in the VIC section of the CPU data sheet and the relevant SFRxxxx.FTH file.
: setFIQsrc \ src# --
Set src# to be an enabled FIQ interrupt. During
cross compilation the ISR address must have been set with
SetFIQ above. The FIQ interrupt can be enabled and
disabled by EnInt and DisInt.
An example of setting up an interrupt follows.
|
: .VIC \ --
Show status of the VIC.
: SWINT \ int# --
Generate interrupt from software.
This section is not a treatise on the ARM PL192 Vectored Interrupt Controller. These words provide a fairly basic set of tools for using the ARM PL192 VIC, which is fully documented in the ARM Technical Publications CD available free of charge from www.arm.com. The notes in the Generic IRQ section about interrupt nesting apply here.
This code requires Kernel62.fth and the equate COLDCHAIN? must be set non-zero in the control file. The VIC addresses should be defined in the SFRxxxx.fth file which defines the peripheral address for the silicon.
If the EQUate #IRQs is greater than one, IRQ nesting is supported with the penalty of greater overhead. If IRQ nesting is required, the IRQ stack size should be at least 64*#IRQs bytes, and TASK-SIZE*#IRQs bytes should be added to the SWI stack. If IRQ nesting is not required the IRQ stack must be at least TASK-SIZE bytes.
FIQ nesting is not supported by this code. The FIQ stack must be at least TASK-SIZE bytes.
1 equ #VICs \ -- n
If this equate has not already been set, a value of 1 is used.
If more than one is defined, the base addresses must be named
_VICn, and the primary VIC must also be named _VIC.
PROC IRQ_entry \ --
This is the template code for vectored IRQ interrupt handlers.
PROC FIQ_entry \ --
This is the template code for FIQ interrupt handlers.
: IRQ: \ xt -- ; -- isr
Creates an IRQ ISR that runs the given Forth word. At run
time the entry point of the ISR is returned. Use in the form:
' <action> IRQ: <actionISR>
: SetFIQ \ xt --
Set the FIQ interrupt to call the Forth word whose xt is
given. Use interpretively in the form:
' <word> SetFIQ
: EnInt \ src# --
Enable the requested VIC interrupt source.
: DisInt \ src# --
Disable the requested VIC interrupt source.
: SetIrqIsr \ isr src# prio# --
Set the ISR to be the action of the source interrupt number
src# (0..31) with priority prio# (0..15, 0 = highest priority)
Then enable the interrupt. Note that Forth IRQ interrupt
handlers must be created with IRQ: <name>.
Assembler routines may be created using:
PROC <name> ... END-CODE
Interrupt source numbers may be found in the VIC section of the CPU data sheet and the relevant SFRxxxx.FTH file.
: setFIQsrc \ src# --
Set src# to be an enabled FIQ interrupt. During
cross compilation the ISR address must have been set with
SetFIQ above. The FIQ interrupt can be enabled and
disabled by EnInt and DisInt.
An example of setting up an interrupt follows.
|
: .VIC \ --
Show status of the VIC.
: SWINT \ int# --
Generate interrupt from software.
The example below comes from typing
55 0 !
on the Forth console. The device is an NXP LPC2388 and address zero is Flash to which writes have not been permitted.
|
The exception occurred in the instruction at $1C64. It was a data abort exception, which means that it was a data load or store at an invalid address.
Assuming that restart is to a Forth console, you can find out where the fault occurred if you have compiled the file Common\DebugTools.fth or Powernet\DebugTools.fth.
$1C64 ip>nfa .name<Enter> ! ok
The return stack dump shows that CATCH was used, in turn called by QUIT, the text interpreter.
Further interpretation requires some knowledge of the use of the CPU registers.
For Cortex-M the following register usage is the default:
|
The VFX optimiser reserves R0 and R1 for internal operations. CODE definitions must use R10 as TOS with NOS pointed to by R12 as a full descending stack in ARM terminology. R0..R8 are free for use by CODE definitions and need not be preserved or restored. You should assume that any register can be affected by other words.
On the ARM the following register usage is the default:
|
The VFX optimiser reserves R0 and R1 for internal operations. CODE definitions must use R10 as TOS with NOS pointed to by R12 as a full descending stack in ARM terminology. R0..R8 are free for use by CODE definitions and need not be preserved or restored. You should assume that any register can be affected by other words.
Using the ARM example above, we can learn more.
|
The exception occurred in the instruction at $1C64. It was a data abort exception, which means that it was a data load or store at an invalid address.
|
In general, UP > PSP > RSP. In this case that's good. TOS=0, which we would expect from the phrase:
55 0 !
We now switch back to the cross compiler, which you did leave running, didn't you? Since we now know that $1C64 is in !, we can disassemble it.
|
From this, we can see that the offending instruction is
( 0000:1C64 00008AE5 ...e ) str r0, [ r10, # $00 ]
Since R10 is 0, we now know that it was attempting a write to 0, which is not permitted.
Provided that you keep words small, the register contents at the crash point, with the stack contents and the disassembly often provide enough information to reconstruct the state of stack on entry to the word.