base:launching_long_tasks_from_irq_handler
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
base:launching_long_tasks_from_irq_handler [2016-02-02 20:08] – bitbreaker | base:launching_long_tasks_from_irq_handler [2016-11-23 10:54] (current) – bitbreaker | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Launching long tasks from inside a IRQ handler ====== | ====== Launching long tasks from inside a IRQ handler ====== | ||
+ | |||
+ | by Bitbreaker/ | ||
When executing code within an IRQ handler you have to finish things before the next IRQ occurs. But sometimes tasks just take some more time, for that you can spin off those tasks from inside the handler, and allow then upcoming IRQs to happen. | When executing code within an IRQ handler you have to finish things before the next IRQ occurs. But sometimes tasks just take some more time, for that you can spin off those tasks from inside the handler, and allow then upcoming IRQs to happen. | ||
- | When the IRQ handler | + | |
+ | Basically there is two scenarios that we can handle in an easy and an more sophisticated way. The first scenario is, if you have a long task that takes several frames, and that is only spin off seldom. Imagine you shift a bitmap 8 pixels wide and move the whole bitmap each 8 frames. Lets say the moving takes 7 frames. This can all be done from IRQ. | ||
+ | |||
+ | When the IRQ handler | ||
< | < | ||
irq | irq | ||
;save registers | ;save registers | ||
- | | + | |
- | | + | |
- | | + | |
;... your desired irq handler code goes here | ;... your desired irq handler code goes here | ||
- | + | lda some_condition | |
+ | beq skip_long | ||
+ | |||
;now push 3 more bytes on stack | ;now push 3 more bytes on stack | ||
lda #>task | lda #>task | ||
Line 21: | Line 28: | ||
lda #$00 | lda #$00 | ||
pha | pha | ||
- | + | ||
+ | skip_long | ||
+ | ; | ||
+ | |||
+ | ; | ||
+ | lda reg_a | ||
+ | ldx reg_x | ||
+ | ldy reg_y | ||
;rti will now finish this interrupt and continue with the new task instead of the code | ;rti will now finish this interrupt and continue with the new task instead of the code | ||
; | ; | ||
Line 27: | Line 41: | ||
| | ||
task | task | ||
- | ; | + | ;store registers again |
+ | sta reg_a_ | ||
+ | stx reg_x_ | ||
+ | sty reg_y_ | ||
+ | |||
+ | ; | ||
| | ||
; | ; | ||
- | | + | |
- | | + | |
- | | + | |
- | ;now finally continue with code being executed before IRQ | + | ;now finally continue with code being executed before IRQ that spun of our task |
rti | rti | ||
</ | </ | ||
- | Alternatively one can just clear the irq flag and let the next irq happen, but this only works if the next irq is a different | + | The second scenario spins off a task in every frame, with the task being finished until the next IRQ occurs. |
+ | In this case it is sufficient to just clear the IRQ flag and let the next IRQ happen. But this only works if the next IRQ is a different | ||
< | < | ||
irq1 | irq1 | ||
dec $d019 | dec $d019 | ||
+ | ;save your registers | ||
sta reg_a | sta reg_a | ||
stx reg_x | stx reg_x | ||
Line 55: | Line 76: | ||
sta $d012 | sta $d012 | ||
| | ||
- | ;now allow irq2 happen on top of this task and return to this task when done | + | ;now allow irq2 to happen on top of this task and return to this task when done |
cli | cli | ||
| | ||
... effect that takes much cycles ... | ... effect that takes much cycles ... | ||
| | ||
+ | ;restore registers | ||
ldy reg_y | ldy reg_y | ||
ldx reg_x | ldx reg_x | ||
Line 67: | Line 89: | ||
irq2 | irq2 | ||
dec $d019 | dec $d019 | ||
- | ;use different locations to store registers | + | ;use different locations to store registers |
sta reg_a_ | sta reg_a_ | ||
stx reg_x_ | stx reg_x_ | ||
Line 88: | Line 110: | ||
rti | rti | ||
</ | </ | ||
+ | |||
+ | A even more convenient variant is to use the stack for register saving: | ||
+ | |||
+ | < | ||
+ | irq1 | ||
+ | pha | ||
+ | txa | ||
+ | pha | ||
+ | tya | ||
+ | pha | ||
+ | dec $d019 | ||
+ | | ||
+ | dec counter | ||
+ | bne + | ||
+ | | ||
+ | lda #$08 | ||
+ | sta counter | ||
+ | cli | ||
+ | jsr long_task | ||
+ | + | ||
+ | pla | ||
+ | tay | ||
+ | pla | ||
+ | tax | ||
+ | pla | ||
+ | rti | ||
+ | </ | ||
+ | |||
+ | Now you can run a long task that can finish somewhen between the next 8 interrupts. |
base/launching_long_tasks_from_irq_handler.1454440135.txt.gz · Last modified: 2016-02-02 20:08 by bitbreaker