From: Matthias T. <mt...@we...> - 2010-09-26 11:58:44
|
hi Al, > > Howeer, if you use int! to set a "Forth" interrupt vector, the default isr > sets the "T" flag when an interrupt trips. It also stores the current vector in > a location where the interpreter can find it. > > When the interpreter is about to dispatch it looks to see if the T flag is set > and, if it is, it forces the XT you set with int! for the given vector. Sounds > good. And it works for all cases where the hardware does not need to be reset to some "interrupt-handled" state. e.g. some interrupts need to be cleared somehow (mostly by reading one or more bytes from pre-defined IO registers). If that is _not_ done within the ISR, the interrupt will re-fire immediatly after the reti instruction. Other interrupt sources such as timer interrupts do not need to acknowledged and they work absolutly fine with forth words. > > However, it seems like using reti in the generic ISR is a bad idea. When an > interrupt fires, the AVR clears the global interrupt enable in status and it > stays clear until the reti. But that means you could get a nested interrupt > which would cause the previous interrupt to be dropped. > I changed the reti to ret and then, of course, my "Forth" handler has to > execute +int before it exits to get interrupts back on again. I also added a > few lines of code so that if the Forth vector is 0, it doesn't try to execute > it. This all seems to work (although I'm having another apparently unrelated > problem with the code I actually want to write). moving the reti instruction to some other place is crazy, but it could work and could solve the interrupt handling problem. following algorithm: the forth system executes some code. An interrupt fires and the ISR routine will start immediatly. Until now, it only sets the T flag, saves the interrupt number and finishes with reti. This is changed to a final ret in the generic isr. That means that the interrupted code will continue to work and whenever the inner interpreter gets called, the forth-level interrupt code can be executed. The basic trick is: for the controller the interrupt handling is still active. Thus no other interrupt will disturb us. Whenever the forth level interrupt word finishes, the inner interpreter will call the reti and signals the controller "yeah, interrupt handled". There are a few downsides: Any primitive word that changes the SREG flags will need to take care for the externally set t flag. The most important word is probably i!, which needs both a lot of time and disables interruptes internally. The following (not really tested) patch should contain the basic ideas so far.. diff --git a/core/amforth.asm b/core/amforth.asm index b339829..c6707c3 100644 --- a/core/amforth.asm +++ b/core/amforth.asm @@ -87,15 +87,16 @@ DO_EXECUTE: DO_INTERRUPT: ; here we deal with interrupts the forth way clt + savetos lds temp0, intcur ldi zl, LOW(intvec) ldi zh, HIGH(intvec) add zl, temp0 adc zh, zeroh - ldd wl, Z+0 - ldd wh, Z+1 - - clt ; clear the t flag to indicate that the interrupt is handled + ldd tosl, Z+0 + ldd tosh, Z+1 + ldi wl, low(XT_ISREXEC) + ldi wl, high(XT_ISREXEC) rjmp DO_EXECUTE .include "dict_appl_core.inc" diff --git a/core/dict_core.inc b/core/dict_core.inc index 09af97d..624fdc2 100644 --- a/core/dict_core.inc +++ b/core/dict_core.inc @@ -3,6 +3,8 @@ .include "words/int-on.asm" .include "words/int-off.asm" .include "words/int-restore.asm" +.include "words/isr-exec.asm" +.include "words/isr-end.asm" .include "words/exit.asm" .include "words/execute.asm" diff --git a/core/words/isr-end.asm b/core/words/isr-end.asm new file mode 100644 index 0000000..105a1ca --- /dev/null +++ b/core/words/isr-end.asm @@ -0,0 +1,15 @@ +; ( -- ) Interrupt +; R( -- ) +; re-enables interrupts in an ISR +VE_ISREND: + .dw $ff07 + .db "isr-end",0 + .dw VE_HEAD + .set VE_HEAD = VE_ISREND +XT_ISREND: + .dw PFA_ISREND +PFA_ISREND: + rcall PFA_ISREND1 ; clear the interrupt flag for the controller + rjmp DO_NEXT +PFA_ISREND1: + reti diff --git a/core/words/isr-exec.asm b/core/words/isr-exec.asm new file mode 100644 index 0000000..94851da --- /dev/null +++ b/core/words/isr-exec.asm @@ -0,0 +1,14 @@ +; ( xt -- ) Interrupt +; R( -- ) +; executes an interrupt service routine +VE_ISREXEC: + .dw $ff08 + .db "isr-exec" + .dw VE_HEAD + .set VE_HEAD = VE_ISREXEC +XT_ISREXEC: + .dw DO_COLON +PFA_ISREXEC: + .dw XT_EXECUTE + .dw XT_ISREND + .dw XT_EXIT |