# HG changeset patch # User Paul Boddie # Date 1435425663 -7200 # Node ID 4ffa83fa5fe119443ed7db2c4b57771ed2f1c6f9 # Parent c18aa3a5597fddccc0fc62a41f43e5115f43064b Introduced the switching mechanism plus example tasks, fixing stack access. diff -r c18aa3a5597f -r 4ffa83fa5fe1 switcher.oph --- a/switcher.oph Sat Jun 27 18:28:12 2015 +0200 +++ b/switcher.oph Sat Jun 27 19:21:03 2015 +0200 @@ -17,12 +17,19 @@ .include "macros.oph" +.alias SP $70 +.alias SPH $71 +.alias NEXT $72 +.alias NEXTH $73 +.alias CURRENT $74 +.alias CURRENTH $75 + .org $2000 .text - main: jsr install_handler - rts +test: + jmp test ; install the interrupt handler address in IRQ1V ; @@ -43,22 +50,35 @@ pha ; A -> stack txa pha ; X -> stack + tsx ; capture the stack pointer now for later use + ; (stack is , X, A, F, LSB, MSB) tya pha ; Y -> stack - .invoke push16 $70 + + ; save zero-page locations used in the handler + + .invoke push16 SP + .invoke push16 NEXT + .invoke push16 CURRENT + +init_sp: + + ; initialise the stack frame pointer + + txa + sta SP + lda #$01 ; $01xx + sta SPH + +test_pc: ; test PC for execution of ROM routines ; these are probably not re-entrant ; obtain the stack location of the stored PC MSB - tsx - txa - sta $70 - lda #$01 ; $01xx - sta $71 - ldy #6 ; offset of MSB (, Y, X, A, F, LSB, MSB) - lda ($70), y + ldy #5 ; offset of MSB (Y, X, A, F, LSB, MSB) + lda (SP), y ; reference the stack location and compute PC MSB & $80 and #$80 @@ -67,11 +87,73 @@ ; exit if PC MSB & $80 != 0 beq exit_handler - ; increment a counter - .invoke add16 1, $7000 +load_task: + + ; load next task + + ldx task_index + lda tasks, x + sta NEXT + inx + lda tasks, x + sta NEXTH + inx + + ; reset the task index if necessary + + cpx #10 ; length of tasks array + bne test_task + ldx #0 + +test_task: + stx task_index + + ; exit if null task + + lda NEXTH + cmp #0 + beq exit_handler + +switch_task: + + ; store flags, PC in current task structure + + .invoke mov16 current_task, CURRENT + + ldy #5 ; offset of MSB (Y, X, A, F, LSB, MSB) + lda (SP), y + sta (CURRENT), y + dey + lda (SP), y + sta (CURRENT), y + dey + lda (SP), y + sta (CURRENT), y + + ; load flags, PC from next task structure + + lda (NEXT), y + sta (SP), y + iny + lda (NEXT), y + sta (SP), y + iny + lda (NEXT), y + sta (SP), y + iny + + ; make the next task the current one + + .invoke mov16 NEXT, current_task exit_handler: - .invoke pull16 $70 + + ; restore zero-page locations used in the handler + + .invoke pull16 CURRENT + .invoke pull16 NEXT + .invoke pull16 SP + pla tay ; stack -> Y pla @@ -79,6 +161,47 @@ pla ; stack -> A jmp (old_handler) +; location of previous interrupt handler + old_handler: .word 0 +; location of current task (duplicated from the table) + +current_task: .word 0 + +; index of current task + +task_index: .byte 0 + +; task table containing locations of each task + +tasks: + .word first_task + .word second_task + .word 0 + .word 0 + .word 0 + +; example tasks + +first_task: + .byte 0 ; currently unused + .byte 0 ; currently unused + .byte 0 ; currently unused + .byte 0 ; saved flags + .word first_task_start ; saved PC +first_task_start: + .invoke add16 1, $7000 + jmp first_task_start + +second_task: + .byte 0 ; currently unused + .byte 0 ; currently unused + .byte 0 ; currently unused + .byte 0 ; saved flags + .word second_task_start ; saved PC +second_task_start: + .invoke add16 1, $7008 + jmp second_task_start + ; vim: tabstop=4 expandtab shiftwidth=4