;*------------------------------------------------------------------* ;* * ;* Mini Multitasking Kernel * ;* for 6502 Systems * ;* * ;* by Joachim Deboy * ;* * ;* This mini kernel uses IRQ interrupts from a free running * ;* 6522-timer for task switching. It currently supports 4 * ;* concurrent tasks. The tasks receive control for fixed time * ;* slices in a round robin method. It should be easily possible * ;* to implement a priority driven task selector in the inter- * ;* rupt service routine. * ;* * ;* For performance reasons, the stack page will not be copied * ;* for every task switch, but is divided into 4 parts, one for * ;* each task. Because of that only the stack pointer and the * ;* other processor registers must be saved and loaded, when * ;* performing a task switch. A disadvantage is the 'home made' * ;* further limitation of the already short stack area. * ;* * ;* Two macros are implemented to allow a simple kind of seria- * ;* lization between concurrent tasks. A call of the enq-macro * ;* locks task switching until the deq-macro is used. This also * ;* prevents a discuption of a time critical process. * ;* * ;* This software is part of a heater control software, which * ;* runs at my home for several years now. * ;* It may be freely used and modified to suit other possible * ;* applications, but i can't guarantee for the usablity * ;* in any way. Use it at for own risk. * ;* * ;* If you have any comments, questions, further ideas or if you * ;* find any bugs, please contact me under joachim@deboy.de * ;* * ;*------------------------------------------------------------------* ;* page 0 addresses * ;*------------------------------------------------------------------* mtarlow =$00 ; multitasking kernel, ret-addr., low mtarhig =$01 ; multitasking kernel, ret-addr.,high mtatemp =$02 ; multitasking kernel, temp. work mtatask =$03 ; multitasking kernel, actual task mtastab =$04 ; multitasking kernel, stack pointers mtastbe =$07 ; multitasking kernel, end of st-ptrs reserved =$08 ; reserved mtalock =$09 ; multitasking lock x'00' = free ;*------------------------------------------------------------------* ;* 6522 ports * ;*------------------------------------------------------------------* orb =$c310 ; output-register a ora =$c311 ; output-register b ddrb =$c312 ; data direction register b ddra =$c313 ; data direction register a t1csl =$c314 ; read: counter, low ; ; write: preset, low t1csh =$c315 ; read & write: counter, high t1lsl =$c316 ; read & write preset low, low t1lsh =$c317 ; read & write preset, high acr =$c31b ; acr-helpregister pcr =$c31c ; pcr-register ifr =$c31d ; interrupt-flag-register ier =$c31e ; interrupt-enable-register orahlp =$c31f ; output-register a w/o handshaking ;*------------------------------------------------------------------* ;* define macros * ;*------------------------------------------------------------------* #define enq() inc mtalock #define deq() dec mtalock \ beq $+8 \ jsr mtaentry \ inc $100 ;*------------------------------------------------------------------* ;* initialization routine * ;*------------------------------------------------------------------* .org $f000 init: lda #$00 ; init output ports of pia 2 sta mtalock ; reset multitasking lock lda #$40 ; setup timer for free running sta acr lda #$c0 ; enable timer interrupts sta ier ldy #0 lda #0 stinit: sta $100,y ; reset stack to x'00' iny bne stinit lda #$00 ; set actual task # to 0 sta mtatask ldy #maxtask-1 ; get max. number of tasks initloop: lda mtasini,y ; get initial stackpointer value sta mtastab,y ; and save value in page 0 table tax ; move stack pointer value to reg x lda #$b0 ; set initial flag register contents sta $0104,x ; save flag register on stack tya ; get actual task number asl a ; multiply with 2 tax ; and move result to reg x stx mtatemp ; save reg x lda ent_tab,x ; get pcl-value ldx mtastab,y ; get stack pointer value sta $0105,x ; save pcl register on stack ldx mtatemp ; get reg x lda ent_tab+1,x ; get pch-value ldx mtastab,y ; get stack pointer value sta $0106,x ; save pch register on stack dey bpl initloop ; ==> loop for all tasks ldx #$3f ; set stack for task 0 txs lda #0 ; initial load timer sta t1lsl lda #40 ; about 1/100 sec timer value sta t1csh cli ; enable interrupts jmp ent_task0 ; enter task 0 ;*------------------------------------------------------------------* ;* table of task entry addresses * ;*------------------------------------------------------------------* ent_tab: .word ent_task0 .word ent_task1 .word ent_task2 .word ent_task3 ;*------------------------------------------------------------------* ;* program call entry to interrupt service routine * ;*------------------------------------------------------------------* mtaentry: php ; save processor status on stack ; ; for interrupt simulation pha ; save registers on current stack txa pha tya pha tsx inc $105,x ; add 1 to return address bne mtaent01 ; because of jsr command inc $106,x mtaent01: lda #$00 ; reset task lock sta mtalock jmp mtaswitch ; and process task switch ;*------------------------------------------------------------------* ;* interrupt service routine * ;*------------------------------------------------------------------* irq: pha ; save registers on current stack txa pha tya pha lda t1csl ; enable interrupt lda #$c0 ; reset flag sta ifr lda mtalock ; is task locked ? beq mtaswitch ; ==> no, then process task change inc mtalock ; indicate task switch requested jmp irq_ret ; ==> and skip task change mtaswitch: ; task switcher ldy mtatask ; get actual task number tsx ; get actual stack pointer stx mtastab,y ; and save it in table iny ; calculate next task number cpy #maxtask ; valid task number ? bcc mtanumok ; ==> yes ldy #0 ; else start with task 0 mtanumok: sty mtatask ; save new task number ldx mtastab,y ; get new stack pointer txs ; and load it in sp-register irq_ret: pla ; load registers from current stack tay pla tax pla rti ; ==> go and process task mtasini .byte $39,$79,$b9,$f9 ; initial stackpointer values maxtask =$-mtasini .org $fffa nmivector .word init ; nmi vector resvector .word init ; reset vector irqvector .word irq ; irq vector .end