1 ; A task switcher for the Acorn Electron. 2 3 ; Copyright (C) 2015 Paul Boddie <paul@boddie.org.uk> 4 5 ; This program is free software; you can redistribute it and/or modify it under 6 ; the terms of the GNU General Public License as published by the Free Software 7 ; Foundation; either version 3 of the License, or (at your option) any later 8 ; version. 9 10 ; This program is distributed in the hope that it will be useful, but WITHOUT 11 ; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 ; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 ; details. 14 15 ; You should have received a copy of the GNU General Public License along with 16 ; this program. If not, see <http://www.gnu.org/licenses/>. 17 18 .include "macros.oph" 19 20 .alias SP $70 21 .alias SPH $71 22 .alias NEXT $72 23 .alias NEXTH $73 24 .alias CURRENT $74 25 .alias CURRENTH $75 26 27 .org $2000 28 .text 29 main: 30 jsr install_handler 31 test: 32 jmp test 33 34 ; install the interrupt handler address in IRQ1V 35 ; 36 ; affects: A 37 38 install_handler: 39 sei 40 .invoke mov16 $204, old_handler 41 .invoke store16 handler, $204 42 cli 43 rts 44 45 ; handle interrupts 46 ; 47 ; affects: (temporary stack usage) 48 49 handler: 50 pha ; A -> stack 51 txa 52 pha ; X -> stack 53 tsx ; capture the stack pointer now for later use 54 ; (stack is <empty>, X, A, F, LSB, MSB) 55 tya 56 pha ; Y -> stack 57 58 ; save zero-page locations used in the handler 59 60 .invoke push16 SP 61 .invoke push16 NEXT 62 .invoke push16 CURRENT 63 64 init_sp: 65 66 ; initialise the stack frame pointer 67 68 txa 69 sta SP 70 lda #$01 ; $01xx 71 sta SPH 72 73 test_pc: 74 75 ; test PC for execution of ROM routines 76 ; these are probably not re-entrant 77 78 ; obtain the stack location of the stored PC MSB 79 80 ldy #5 ; offset of MSB (Y, X, A, F, LSB, MSB) 81 lda (SP), y 82 83 ; reference the stack location and compute PC MSB & $80 84 and #$80 85 cmp #$80 86 87 ; exit if PC MSB & $80 != 0 88 beq exit_handler 89 90 load_task: 91 92 ; load next task 93 94 ldx task_index 95 lda tasks, x 96 sta NEXT 97 inx 98 lda tasks, x 99 sta NEXTH 100 inx 101 102 ; reset the task index if necessary 103 104 cpx #10 ; length of tasks array 105 bne test_task 106 ldx #0 107 108 test_task: 109 stx task_index 110 111 ; exit if null task 112 113 lda NEXTH 114 cmp #0 115 beq exit_handler 116 117 switch_task: 118 119 ; store flags, PC in current task structure 120 121 .invoke mov16 current_task, CURRENT 122 123 ldy #5 ; offset of MSB (Y, X, A, F, LSB, MSB) 124 lda (SP), y 125 sta (CURRENT), y 126 dey 127 lda (SP), y 128 sta (CURRENT), y 129 dey 130 lda (SP), y 131 sta (CURRENT), y 132 133 ; load flags, PC from next task structure 134 135 lda (NEXT), y 136 sta (SP), y 137 iny 138 lda (NEXT), y 139 sta (SP), y 140 iny 141 lda (NEXT), y 142 sta (SP), y 143 iny 144 145 ; make the next task the current one 146 147 .invoke mov16 NEXT, current_task 148 149 exit_handler: 150 151 ; restore zero-page locations used in the handler 152 153 .invoke pull16 CURRENT 154 .invoke pull16 NEXT 155 .invoke pull16 SP 156 157 pla 158 tay ; stack -> Y 159 pla 160 tax ; stack -> X 161 pla ; stack -> A 162 jmp (old_handler) 163 164 ; location of previous interrupt handler 165 166 old_handler: .word 0 167 168 ; location of current task (duplicated from the table) 169 170 current_task: .word 0 171 172 ; index of current task 173 174 task_index: .byte 0 175 176 ; task table containing locations of each task 177 178 tasks: 179 .word first_task 180 .word second_task 181 .word 0 182 .word 0 183 .word 0 184 185 ; example tasks 186 187 first_task: 188 .byte 0 ; currently unused 189 .byte 0 ; currently unused 190 .byte 0 ; currently unused 191 .byte 0 ; saved flags 192 .word first_task_start ; saved PC 193 first_task_start: 194 .invoke add16 1, $7000 195 jmp first_task_start 196 197 second_task: 198 .byte 0 ; currently unused 199 .byte 0 ; currently unused 200 .byte 0 ; currently unused 201 .byte 0 ; saved flags 202 .word second_task_start ; saved PC 203 second_task_start: 204 .invoke add16 1, $7008 205 jmp second_task_start 206 207 ; vim: tabstop=4 expandtab shiftwidth=4