1.1 --- a/macros.oph Sat Jun 27 20:35:31 2015 +0200
1.2 +++ b/macros.oph Sun Jun 28 14:08:35 2015 +0200
1.3 @@ -52,6 +52,51 @@
1.4 sta _2+1
1.5 .macend
1.6
1.7 +; copy word from location to indirect location
1.8 +;
1.9 +; _1: source
1.10 +; _2: target reference
1.11 +;
1.12 +; affects: A, Y
1.13 +
1.14 +.macro mov16_to_ref
1.15 + ldy #0
1.16 + lda _1
1.17 + sta (_2), y
1.18 + iny
1.19 + lda _1+1
1.20 + sta (_2), y
1.21 +.macend
1.22 +
1.23 +; copy word from indirect location to location
1.24 +;
1.25 +; _1: source reference
1.26 +; _2: target
1.27 +;
1.28 +; affects: A, Y
1.29 +
1.30 +.macro mov16_from_ref
1.31 + ldy #0
1.32 + lda (_1), y
1.33 + sta _2
1.34 + iny
1.35 + lda (_1), y
1.36 + sta _2+1
1.37 +.macend
1.38 +
1.39 +; copy byte between indirect locations
1.40 +;
1.41 +; _1: source reference
1.42 +; _2: target reference
1.43 +;
1.44 +; Y: offset
1.45 +; affects: A
1.46 +
1.47 +.macro mov8_refs
1.48 + lda (_1), y
1.49 + sta (_2), y
1.50 +.macend
1.51 +
1.52 ; copy word from location to stack
1.53 ;
1.54 ; _1: source
1.55 @@ -95,4 +140,47 @@
1.56 sta _2+1
1.57 .macend
1.58
1.59 +; subtract word from locations
1.60 +;
1.61 +; _1: valueW
1.62 +; _2: {valueL, valueH} -> {valueL', valueH'}
1.63 +
1.64 +.macro sub16
1.65 + sec
1.66 + lda _2
1.67 + sbc #<_1
1.68 + sta _2
1.69 + lda _2+1
1.70 + sbc #>_1
1.71 + sta _2+1
1.72 +.macend
1.73 +
1.74 +; negate accumulator
1.75 +;
1.76 +; affects: A, C
1.77 +
1.78 +.macro negate
1.79 + clc
1.80 + eor #$ff
1.81 + adc #1
1.82 +.macend
1.83 +
1.84 +; push PC onto a "user space" stack and jump to subroutine
1.85 +;
1.86 +; _1: target
1.87 +
1.88 +.macro call
1.89 + sei ; prevent CPU stack disturbance
1.90 + jsr copy_to_user_stack
1.91 + cli ; permit CPU stack access again
1.92 + jmp _1
1.93 + nop
1.94 +.macend
1.95 +
1.96 +; pull PC from a "user space" stack and return from subroutine
1.97 +
1.98 +.macro return
1.99 + jmp copy_from_user_stack
1.100 +.macend
1.101 +
1.102 ; vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/switcher.oph Sat Jun 27 20:35:31 2015 +0200
2.2 +++ b/switcher.oph Sun Jun 28 14:08:35 2015 +0200
2.3 @@ -25,24 +25,158 @@
2.4 .alias NEXTH $73
2.5 .alias CURRENT $74
2.6 .alias CURRENTH $75
2.7 +.alias USER $76
2.8 +.alias ARG0 $80
2.9 +.alias ARG0H $81
2.10 +.alias ARG1 $82
2.11 +.alias ARG1H $83
2.12
2.13 .alias TASK_TABLE_LENGTH 10
2.14
2.15 +; "user space" stack for the main program where the invocations might be
2.16 +; interrupted and where the CPU stack might be disrupted
2.17 +
2.18 +.alias main_stack $1fff
2.19 +
2.20 +
2.21 +
2.22 .org $2000
2.23 .text
2.24 +
2.25 +
2.26 +
2.27 +; main program, installing the handler and adding example tasks
2.28 +
2.29 main:
2.30 jsr install_handler
2.31 - .invoke store16 first_task, $76
2.32 - jsr new_task
2.33 - .invoke store16 second_task, $76
2.34 - jsr new_task
2.35 - .invoke store16 third_task, $76
2.36 - jsr new_task
2.37 + .invoke store16 tasks, ARG1
2.38 + .invoke store16 main_stack, USER
2.39 + .invoke store16 first_task, ARG0
2.40 + .invoke call new_task
2.41 + .invoke store16 second_task, ARG0
2.42 + .invoke call new_task
2.43 + .invoke store16 third_task, ARG0
2.44 + .invoke call new_task
2.45 wait:
2.46 jmp wait ; wait for the switcher to take over
2.47
2.48
2.49
2.50 +; move CPU stack data to the "user space" stack
2.51 +;
2.52 +; affects: USER (gains LSB, MSB)
2.53 +
2.54 +copy_to_user_stack:
2.55 + pha ; A -> stack
2.56 + txa
2.57 + pha ; X -> stack
2.58 + tsx ; capture the stack pointer now for later use
2.59 + ; (stack is Y, X, A, LSB, MSB)
2.60 + tya
2.61 + pha ; Y -> stack
2.62 +
2.63 + ; save zero-page locations used
2.64 +
2.65 + .invoke push16 SP
2.66 +
2.67 + ; initialise the stack frame pointer
2.68 +
2.69 + txa
2.70 + sta SP
2.71 + lda #$01 ; $01xx
2.72 + sta SPH
2.73 +
2.74 + ; allocate "user space" stack space to be compatible with the CPU stack
2.75 +
2.76 + .invoke sub16 5, USER
2.77 +
2.78 + ; copy the PC, updated by 4 (see the call macro)
2.79 +
2.80 + ldy #3
2.81 + clc
2.82 + lda (SP), y
2.83 + adc #4
2.84 + sta (USER), y
2.85 + iny
2.86 + lda (SP), y
2.87 + adc #0
2.88 + sta (USER), y
2.89 +
2.90 + ; correct "user space" stack
2.91 +
2.92 + .invoke add16 3, USER
2.93 +
2.94 + ; restore zero-page locations used
2.95 +
2.96 + .invoke pull16 SP
2.97 +
2.98 + ; return to the caller
2.99 +
2.100 + pla
2.101 + tay ; stack -> Y
2.102 + pla
2.103 + tax ; stack -> X
2.104 + pla ; stack -> A
2.105 + rts
2.106 +
2.107 +
2.108 +
2.109 +; move CPU stack data from the "user space" stack
2.110 +;
2.111 +; affects: USER (loses LSB, MSB)
2.112 +
2.113 +copy_from_user_stack:
2.114 + pha ; padding
2.115 + pha ; padding
2.116 + pha ; A -> stack
2.117 + txa
2.118 + pha ; X -> stack
2.119 + tsx ; capture the stack pointer now for later use
2.120 + ; (stack is Y, X, A, LSB, MSB)
2.121 + tya
2.122 + pha ; Y -> stack
2.123 +
2.124 + ; save zero-page locations used
2.125 +
2.126 + .invoke push16 SP
2.127 +
2.128 + ; initialise the stack frame pointer
2.129 +
2.130 + txa
2.131 + sta SP
2.132 + lda #$01 ; $01xx
2.133 + sta SPH
2.134 +
2.135 + ; adjust the "user space" stack pointer to be compatible with the PC stack
2.136 +
2.137 + .invoke sub16 3, USER
2.138 +
2.139 + ; copy the PC
2.140 +
2.141 + ldy #3
2.142 + .invoke mov8_refs USER, SP
2.143 + iny
2.144 + .invoke mov8_refs USER, SP
2.145 +
2.146 + ; update the "user space" stack pointer
2.147 +
2.148 + .invoke add16 5, USER
2.149 +
2.150 + ; restore zero-page locations used
2.151 +
2.152 + .invoke pull16 SP
2.153 +
2.154 + ; return to the stored PC
2.155 +
2.156 + pla
2.157 + tay ; stack -> Y
2.158 + pla
2.159 + tax ; stack -> X
2.160 + pla ; stack -> A
2.161 + rts
2.162 +
2.163 +
2.164 +
2.165 ; install the interrupt handler address in IRQ1V
2.166 ;
2.167 ; affects: A
2.168 @@ -134,32 +268,34 @@
2.169
2.170 .invoke mov16 current_task, CURRENT
2.171
2.172 + ; store the user stack for the task
2.173 +
2.174 + .invoke mov16_to_ref USER, CURRENT
2.175 +
2.176 ldy #5 ; offset of MSB (Y, X, A, F, LSB, MSB)
2.177 - lda (SP), y
2.178 - sta (CURRENT), y
2.179 + .invoke mov8_refs SP, CURRENT
2.180 dey
2.181 - lda (SP), y
2.182 - sta (CURRENT), y
2.183 + .invoke mov8_refs SP, CURRENT
2.184 dey
2.185 - lda (SP), y
2.186 - sta (CURRENT), y
2.187 + .invoke mov8_refs SP, CURRENT
2.188
2.189 ; load flags, PC from next task structure
2.190
2.191 - lda (NEXT), y
2.192 - sta (SP), y
2.193 + .invoke mov8_refs NEXT, SP
2.194 iny
2.195 - lda (NEXT), y
2.196 - sta (SP), y
2.197 + .invoke mov8_refs NEXT, SP
2.198 iny
2.199 - lda (NEXT), y
2.200 - sta (SP), y
2.201 + .invoke mov8_refs NEXT, SP
2.202 iny
2.203
2.204 ; make the next task the current one
2.205
2.206 .invoke mov16 NEXT, current_task
2.207
2.208 + ; set the user stack for the task
2.209 +
2.210 + .invoke mov16_from_ref NEXT, USER
2.211 +
2.212 exit_handler:
2.213
2.214 ; restore zero-page locations used in the handler
2.215 @@ -202,9 +338,8 @@
2.216
2.217 ; add a new task to the table
2.218 ;
2.219 -; $76, $77: location of task structure
2.220 +; ARG0, ARG0H: location of task structure
2.221 ; affects: A, Y
2.222 -; returns: A = 0 (success); A = 1 (failure)
2.223
2.224 new_task:
2.225
2.226 @@ -230,19 +365,17 @@
2.227 ; copy the task structure location to the table
2.228
2.229 sei
2.230 - lda $77
2.231 + lda ARG0H
2.232 sta tasks, y
2.233 dey
2.234 - lda $76
2.235 + lda ARG0
2.236 sta tasks, y
2.237 cli
2.238
2.239 - lda #0
2.240 - rts
2.241 + .invoke return
2.242
2.243 no_new_task:
2.244 - lda #1
2.245 - rts
2.246 + .invoke return
2.247
2.248
2.249
2.250 @@ -262,14 +395,14 @@
2.251 iny
2.252 sta tasks, y
2.253 cli
2.254 - rts
2.255 + .invoke return
2.256 +
2.257
2.258
2.259 ; example tasks
2.260
2.261 first_task:
2.262 - .byte 0 ; currently unused
2.263 - .byte 0 ; currently unused
2.264 + .word 0 ; user stack pointer
2.265 .byte 0 ; currently unused
2.266 .byte 0 ; saved flags
2.267 .word first_task_start ; saved PC
2.268 @@ -280,8 +413,7 @@
2.269
2.270
2.271 second_task:
2.272 - .byte 0 ; currently unused
2.273 - .byte 0 ; currently unused
2.274 + .word 0 ; user stack pointer
2.275 .byte 0 ; currently unused
2.276 .byte 0 ; saved flags
2.277 .word second_task_start ; saved PC
2.278 @@ -292,8 +424,7 @@
2.279
2.280
2.281 third_task:
2.282 - .byte 0 ; currently unused
2.283 - .byte 0 ; currently unused
2.284 + .word third_task_stack_base ; user stack pointer
2.285 .byte 0 ; currently unused
2.286 .byte 0 ; saved flags
2.287 .word third_task_start ; saved PC
2.288 @@ -308,10 +439,18 @@
2.289 cmp #$ff
2.290 bne _continue
2.291 txa
2.292 - jsr remove_task
2.293 + .invoke call remove_task
2.294 inx
2.295 _continue:
2.296 .invoke add16 1, $7010
2.297 jmp _loop
2.298 +third_task_stack:
2.299 + .word 0
2.300 + .word 0
2.301 + .word 0
2.302 + .word 0
2.303 + .word 0
2.304 + .word 0
2.305 +third_task_stack_base:
2.306
2.307 ; vim: tabstop=4 expandtab shiftwidth=4