Page 1 of 1
user traps
Posted: Thu Sep 13, 2018 9:12 am
by steve64
It's not clear if it is possible to assign a procedure to a user-defined trap number.
I tried to do something like:
PROCEDURE MyTrapper;
BEGIN
Out.String("MY TRAPPER"); Out.Ln
END MyTrapper;
...
Traps.ShowRegs(FALSE); (* simplified trap log *)
Traps.Assign(100, MyTrapper);
ASSERT(FALSE, 100);
...
but I just get the standard trap error log:
Trap @080045C4H in Test, Line: 218, Code: 100
my procedure seems not invoked at all
Re: user traps
Posted: Thu Sep 13, 2018 12:40 pm
by cfbsoftware
ASSERT generates the ARM SVC instruction which is a software interrupt. The interrupt handler that is invoked is the one that is assigned to the address of the SVC interrupt handler (Traps.SVCVector). In a standard Astrobe installation the interrupt handler is the procedure Traps.SVCTrap. The assertion code is just displayed as a number in the error message.
You could use the assertion code to signify that the trap handler should do something different by modifying the source code of Traps.SVCTrap.
For example (* Warning: none of this has been compiled or tested *) in Traps you could declare an array of procedures:
Code: Select all
VAR
userProcs: ARRAY 155 OF InterruptHandler;
and a procedure
Code: Select all
PROCEDURE AssignSVC*(code: INTEGER; p: InterruptHandler);
BEGIN
IF code >= 100 THEN userProcs[code - 100] := p END
END AssignSVC;
and modify Traps.SVCTrap to call your function instead of executing the normal trap code:
Code: Select all
PROCEDURE SVCTrap;
...
SYSTEM.GET(trapAddr - 4, instr);
code := LSR(instr, 16) MOD 100H;
(* modifications start here: *)
procNo := code - 100;
IF (procNo >= 0) & (userProcs[procNo] # NIL) THEN
userProcs[procNo]
ELSE ...
Don't forget to initialise the array in Traps.Init:
Code: Select all
FOR i := 0 TO LEN(userProcs) - 1 DO userProcs[i] := NIL END;
Then in your own code you would write:
Thank you for prompting this idea. I like it and will consider implementing it in the standard Astrobe distribution ...
Re: user traps
Posted: Sun Feb 10, 2019 9:49 pm
by cfbsoftware
v7.0 of Astrobe for Cortex-M now supports user-customisable trap handlers. See the attached source code example of its use. The output from the example is:
- UserTraps.gif (2.57 KiB) Viewed 43837 times
Re: user traps
Posted: Mon Feb 18, 2019 9:26 am
by gray
I want to use the SVC call/mechanism not only for error handling, but also executing code that is safe from interference by interrupt service routines (ISR), eg. to avoid race conditions. Thusly executed code must be small and fast for the least possible interference with the incoming interrupts. As Traps.mod is focused on error handling, there's a lot going on before a user trap handler is even called, including saving the regs, and collecting all the error info, which is not ideal for what I have in mind. However, I don't want to lose the error handling in Traps.mod by simply assigning my own handler to the SVC vector, so I adapted Traps.mod as outlined below.
Code: Select all
CONST
...
SVC_Instruction = 0DF00H;
VAR
...
svcHandler: InterruptHandler;
PROCEDURE SVCall*(h: InterruptHandler);
BEGIN
svcHandler := h;
SYSTEM.EMIT(SVC_Instruction)
END SVCall;
PROCEDURE SVCTrap;
VAR
id: ID;
regNo, addr, procNo: INTEGER;
BEGIN
IF svcHandler # NIL THEN
svcHandler;
svcHandler := NIL
ELSE
SaveRegs();
SYSTEM.GET(SYSTEM.SP + 128, id.addr);
SYSTEM.GET(id.addr - 4, id.instr);
...
END SVCTrap;
PROCEDURE Init*;
VAR
i, addr: INTEGER;
BEGIN
...
svcHandler := NIL
END Init;
Now I can call
to execute 'myproc' in handler mode with minimal overhead and still get the standard error handling.
Thoughts? Something I have overlooked?
PS: FWIW, my use case is a simple task scheduler using a ticker counter on the 'SysTick' interrupt, the value of which the scheduler loop needs to read out and reset.
PPS: I guess I also could swap out and then back in the SVC handler on the fly, if I wanted to avoid changes to a library module, which I am always reluctant to do for future compatibility; haven't tried that yet.
Re: user traps
Posted: Mon Feb 18, 2019 10:12 am
by gray
Here's a version that works without changing Traps.mod, using the vector swapping technique (relevant excerpt from my Kernel.mod module, leaving out the SysTick business).
Code: Select all
CONST
...
SVC_Instruction = 0DF00H;
SVC_Vector = 02CH;
VAR
...
sysHandler: PROCEDURE;
svcTrapAddr: INTEGER;
PROCEDURE svcHandler;
BEGIN
ASSERT(sysHandler # NIL, 100);
sysHandler
END svcHandler;
PROCEDURE SVCall*(h: PROCEDURE);
VAR
currentHandler: PROCEDURE;
BEGIN
sysHandler := h;
SYSTEM.GET(svcTrapAddr, currentHandler);
Traps.Assign(svcTrapAddr, svcHandler);
SYSTEM.EMIT(SVC_Instruction);
SYSTEM.PUT(svcTrapAddr, currentHandler)
END SVCall;
PROCEDURE initSVC;
VAR
trapAddrBase: INTEGER;
BEGIN
sysHandler := NIL;
SYSTEM.GET(MCU.VTOR, trapAddrBase);
svcTrapAddr := trapAddrBase + SVC_Vector;
END initSVC;
BEGIN
initSVC
END ...
Caveat: I haven't done any in depth testing yet, but it works in my test set-up: the tasks get scheduled (SVCall works), and they can ASSERT errors (standard Traps work, ie. I am back to the unchanged Traps.mod here).
Re: user traps
Posted: Tue Feb 19, 2019 12:08 pm
by cfbsoftware
A couple of things I'm uneasy about that I think you should consider:
1. What are the consequences when the ASSERT in svcHandler fails? It might be sufficient just to skip the call to sysHandler if it is NIL.
2. What happens if sysHandler causes an exception?
Re: user traps
Posted: Tue Feb 19, 2019 2:09 pm
by gray
ad 1.) true, that's a bad idea. It would result in a Hard fault. The ASSERT needs to be in SVCall:
Code: Select all
PROCEDURE SVCall*(h: PROCEDURE);
VAR
currentHandler: PROCEDURE;
BEGIN
ASSERT(h # NIL, 100);
sysHandler := h;
...
ad 2.) as sysHandler runs as exception handler, it will result in a Hard fault. But that's true for UserHandlers set via Traps.mod as well, isn't it, as they also run as exception handlers, being called from SVCTrap. Or do I miss something?
Exactly for this reason, exception/interrupt handlers are tricky to write in general. I get uneasy, if they are longer than a few lines...
Re: user traps
Posted: Tue Feb 19, 2019 8:41 pm
by cfbsoftware
gray wrote:ad 2.) as sysHandler runs as exception handler, it will result in a Hard fault. But that's true for UserHandlers set via Traps.mod as well, isn't it, as they also run as exception handlers, being called from SVCTrap. Or do I miss something?
Yes - you are right. The same thing occurred to me after I had posted my reply!
Back to your original question, you can probably reorganise the Traps code for user handlers so that it skips the code that saves registers, gets the module name etc. when making one of your SVC calls. You could do what ASSERT does and include a trap number with your SVC call so Traps can know whether it's an error trap or otherwise.