1.1 --- a/switcher.oph Sun Jun 28 19:23:06 2015 +0200
1.2 +++ b/switcher.oph Sun Jun 28 23:19:19 2015 +0200
1.3 @@ -38,7 +38,7 @@
1.4 ; "user space" stack for the main program where the invocations might be
1.5 ; interrupted and where the CPU stack might be disrupted
1.6
1.7 -.alias main_stack $1ffc
1.8 +.alias main_stack_base $1ffc
1.9 .alias ABSTEMP $1ffe
1.10
1.11
1.12 @@ -51,17 +51,65 @@
1.13 ; main program, installing the handler and adding example tasks
1.14
1.15 main:
1.16 - .invoke store16 tasks, ARG1
1.17 - .invoke store16 main_stack, USER
1.18 + .invoke store16 tasks, ARG1 ; for debugging
1.19 +
1.20 + ; initialise a user stack and add this program as a task
1.21 +
1.22 + .invoke store16 main_stack_base, USER
1.23 + .invoke store16 main_task, ARG0
1.24 + .invoke call new_task, +
1.25 +
1.26 + ; install the interrupt handler
1.27 +
1.28 +* jsr install_handler
1.29 +
1.30 + ; perform task installation
1.31 +
1.32 .invoke store16 first_task, ARG0
1.33 .invoke call new_task, +
1.34 * .invoke store16 second_task, ARG0
1.35 .invoke call new_task, +
1.36 * .invoke store16 third_task, ARG0
1.37 - .invoke call new_task, +
1.38 -* jsr install_handler
1.39 + .invoke call new_task, wait
1.40 +
1.41 + ; loop while other tasks exist
1.42 +
1.43 wait:
1.44 - jmp wait ; wait for the switcher to take over
1.45 + ldx #7
1.46 + sei
1.47 + lda tasks, x ; check for the third task
1.48 + cli
1.49 + cmp #0
1.50 + bne wait
1.51 +
1.52 + ; where no other tasks exist, remove this task by updating its PC to the
1.53 + ; end label and removing its entry
1.54 +
1.55 + .invoke store16 end, main_task+6
1.56 + lda #0
1.57 + .invoke call remove_task, shutdown
1.58 +
1.59 + ; wait for shutdown
1.60 +
1.61 +shutdown:
1.62 + jmp shutdown
1.63 +
1.64 + ; return here with the initial main program stack
1.65 +
1.66 +end:
1.67 + rts
1.68 +
1.69 +
1.70 +
1.71 +; main program task structure
1.72 +
1.73 +main_task:
1.74 + .word main_stack_base ; user stack pointer
1.75 + .byte 0 ; Y
1.76 + .byte 0 ; X
1.77 + .byte 0 ; A
1.78 + .byte 0 ; saved flags
1.79 + .word 0 ; saved PC
1.80
1.81
1.82
1.83 @@ -86,21 +134,24 @@
1.84 pha ; A -> stack
1.85 txa
1.86 pha ; X -> stack
1.87 - tsx ; capture the stack pointer now for later use
1.88 - ; (stack is <empty>, X, A, F, LSB, MSB)
1.89 tya
1.90 pha ; Y -> stack
1.91
1.92 + tsx ; capture the stack pointer now for later use
1.93 + ; (stack is <empty>, Y, X, A, F, LSB, MSB)
1.94 +
1.95 ; save zero-page locations used in the handler
1.96
1.97 .invoke push16 SP
1.98 .invoke push16 NEXT
1.99 .invoke push16 CURRENT
1.100 + .invoke push16 TEMP
1.101
1.102 init_sp:
1.103
1.104 ; initialise the stack frame pointer
1.105
1.106 + dex ; make the frame compatible with the task structure
1.107 txa
1.108 sta SP
1.109 lda #$01 ; $01xx
1.110 @@ -113,7 +164,7 @@
1.111
1.112 ; obtain the stack location of the stored PC MSB
1.113
1.114 - ldy #5 ; offset of MSB (Y, X, A, F, LSB, MSB)
1.115 + ldy #7 ; offset of MSB (_, _, Y, X, A, F, LSB, MSB)
1.116 lda (SP), y
1.117
1.118 ; reference the stack location and compute PC MSB & $80
1.119 @@ -123,16 +174,35 @@
1.120 ; exit if PC MSB & $80 != 0
1.121 beq exit_handler
1.122
1.123 -load_task:
1.124 +evict_task:
1.125
1.126 - ; load next task
1.127 + ; obtain the current task using the task offset
1.128
1.129 ldx task_offset
1.130 lda tasks, x
1.131 - sta NEXT
1.132 + sta CURRENT
1.133 inx
1.134 lda tasks, x
1.135 - sta NEXTH
1.136 + sta CURRENTH
1.137 + dex
1.138 +
1.139 + ; store the user stack for the task
1.140 +
1.141 + .invoke mov16_to_ref USER, CURRENT
1.142 +
1.143 + ; store registers, flags, PC in current task structure
1.144 +
1.145 + ldy #7 ; offset of MSB (_, _, Y, X, A, F, LSB, MSB)
1.146 +* .invoke mov8_refs SP, CURRENT
1.147 + dey
1.148 + cpy #2
1.149 + bpl -
1.150 +
1.151 +load_task:
1.152 +
1.153 + ; examine the next task
1.154 +
1.155 + inx
1.156 inx
1.157
1.158 ; reset the task index if necessary
1.159 @@ -142,43 +212,55 @@
1.160 ldx #0
1.161
1.162 test_task:
1.163 +
1.164 + ; obtain task location MSB
1.165 +
1.166 + inx
1.167 + lda tasks, x
1.168 + sta NEXTH
1.169 +
1.170 + ; install if not a null task (tasks do not reside in zero page)
1.171 +
1.172 + cmp #0
1.173 + bne restore_task
1.174 +
1.175 + ; test against the start index
1.176 + ; where a complete circuit of the task table has not been performed,
1.177 + ; continue
1.178 +
1.179 + dex
1.180 + txa
1.181 + cmp task_offset
1.182 + bne load_task
1.183 +
1.184 + ; where a complete circuit has been performed without finding any tasks
1.185 + ; uninstall the handler and install the details of the end handler
1.186 +
1.187 + sei
1.188 + .invoke mov16 old_handler, IRQ1V
1.189 + cli
1.190 +
1.191 + ; the end handler resides at the end of the task table
1.192 +
1.193 + ldx #TASK_TABLE_LENGTH
1.194 + inx
1.195 + lda tasks, x
1.196 + sta NEXTH
1.197 +
1.198 +restore_task:
1.199 +
1.200 + dex
1.201 + lda tasks, x
1.202 + sta NEXT
1.203 stx task_offset
1.204
1.205 - ; exit if null task
1.206 -
1.207 - lda NEXTH
1.208 - cmp #0
1.209 - beq exit_handler
1.210 -
1.211 -switch_task:
1.212 -
1.213 - ; store flags, PC in current task structure
1.214 -
1.215 - .invoke mov16 current_task, CURRENT
1.216 -
1.217 - ; store the user stack for the task
1.218 -
1.219 - .invoke mov16_to_ref USER, CURRENT
1.220 + ; load registers, flags, PC from next task structure
1.221
1.222 - ldy #5 ; offset of MSB (Y, X, A, F, LSB, MSB)
1.223 - .invoke mov8_refs SP, CURRENT
1.224 - dey
1.225 - .invoke mov8_refs SP, CURRENT
1.226 + ldy #7 ; offset of MSB (_, _, Y, X, A, F, LSB, MSB)
1.227 +* .invoke mov8_refs NEXT, SP
1.228 dey
1.229 - .invoke mov8_refs SP, CURRENT
1.230 -
1.231 - ; load flags, PC from next task structure
1.232 -
1.233 - .invoke mov8_refs NEXT, SP
1.234 - iny
1.235 - .invoke mov8_refs NEXT, SP
1.236 - iny
1.237 - .invoke mov8_refs NEXT, SP
1.238 - iny
1.239 -
1.240 - ; make the next task the current one
1.241 -
1.242 - .invoke mov16 NEXT, current_task
1.243 + cpy #2
1.244 + bpl -
1.245
1.246 ; set the user stack for the task
1.247
1.248 @@ -188,6 +270,7 @@
1.249
1.250 ; restore zero-page locations used in the handler
1.251
1.252 + .invoke pull16 TEMP
1.253 .invoke pull16 CURRENT
1.254 .invoke pull16 NEXT
1.255 .invoke pull16 SP
1.256 @@ -205,10 +288,6 @@
1.257
1.258 old_handler: .word 0
1.259
1.260 -; location of current task (duplicated from the table)
1.261 -
1.262 -current_task: .word 0
1.263 -
1.264 ; offset of current task in table (in multiples of 2)
1.265
1.266 task_offset: .byte 0
1.267 @@ -220,7 +299,9 @@
1.268 .word 0
1.269 .word 0
1.270 .word 0
1.271 - .word 0
1.272 + .word 0 ; last entry
1.273 +end_handler:
1.274 + .word main_task ; end handler entry
1.275
1.276
1.277
1.278 @@ -294,51 +375,58 @@
1.279
1.280 first_task:
1.281 .word 0 ; user stack pointer
1.282 - .byte 0 ; currently unused
1.283 + .byte 0 ; Y
1.284 + .byte 0 ; X
1.285 + .byte 0 ; A
1.286 .byte 0 ; saved flags
1.287 .word first_task_start ; saved PC
1.288 first_task_start:
1.289 lda #1
1.290 + sta $7000
1.291 first_task_continue:
1.292 - sta $7000
1.293 - adc #1
1.294 + inc $7000
1.295 jmp first_task_continue
1.296
1.297
1.298
1.299 second_task:
1.300 .word 0 ; user stack pointer
1.301 - .byte 0 ; currently unused
1.302 + .byte 0 ; Y
1.303 + .byte 0 ; X
1.304 + .byte 0 ; A
1.305 .byte 0 ; saved flags
1.306 .word second_task_start ; saved PC
1.307 second_task_start:
1.308 lda #1
1.309 + sta $7010
1.310 second_task_continue:
1.311 - sta $7008
1.312 - adc #1
1.313 + inc $7010
1.314 jmp second_task_continue
1.315
1.316
1.317
1.318 third_task:
1.319 .word third_task_stack_base ; user stack pointer
1.320 - .byte 0 ; currently unused
1.321 + .byte 0 ; Y
1.322 + .byte 0 ; X
1.323 + .byte 0 ; A
1.324 .byte 0 ; saved flags
1.325 .word third_task_start ; saved PC
1.326 third_task_start:
1.327 - ldx #0
1.328 + ldx #2
1.329 _begin:
1.330 ldy #0 ; reset counter LSB
1.331 lda #0 ; reset counter MSB
1.332 - sta $7011
1.333 + sta $7021
1.334 _loop:
1.335 - sty $7010
1.336 + stx $7028
1.337 + sty $7020
1.338 cpy #$ff
1.339 bne _continue
1.340 clc
1.341 - lda $7011 ; next MSB
1.342 + lda $7021 ; next MSB
1.343 adc #1
1.344 - sta $7011
1.345 + sta $7021
1.346 cmp #$ff
1.347 bne _continue
1.348 txa
1.349 @@ -348,6 +436,11 @@
1.350 tax
1.351 inx ; move to next offset
1.352 inx ; which is 2 locations away
1.353 + cpx #TASK_TABLE_LENGTH
1.354 + beq _next
1.355 + jmp _begin
1.356 +_next:
1.357 + ldx #0
1.358 jmp _begin
1.359 _continue:
1.360 iny