; ==== ISUAL Flight Software -- Univ of California, Berkeley, SSL ====
; TASK.A -- non-preemptive multi-tasking for 8085
;
; Revision History:
;  18-Dec-2002 - SPG - ISUAL Flight Software rev 7.3
;    First Official Release

        include task.i
        include ioports.i

NTASKS  equ 16  ; maximum number of tasks

ptcb    ds 2    ; points to current TCB
ptcba   ds 2    ; points to next TCB to allocate
TCB0    ds NTASKS*2  ; TCB list
new_ptcb ds 2
old_sp  ds 2
new_sp  ds 2

task_init:
        push h
        lxi h,TCB0
        shld ptcb       ; point to current TCB 
        inx h
        inx h
        mvi M,255       ; mark end of TCB list
        shld ptcba      ; next TCB to allocate
        pop h
        ret

; To start a new task:
;       lxi d,new_task_starts_here
;       lxi h,new_stack
;       call task_new
; (old task resumes here)

task_new:               ; return addr and
        push psw        ; register set on old stack
        push b
        push d
        push h
        shld new_sp
; get current SP 
        lxi h,0
        dad sp
        shld old_sp
; switch to new stack
        lhld new_sp
        sphl            
; push a register set for new task, on new stack
        push d          ; push return to new task
        push psw        ; push new task register set
        in BANK_SELECT_I
        push psw        ; bank
        push b
        push d
        push h
        lxi h,0
        dad sp
        shld new_sp
; back to old stack
        lhld old_sp
        sphl            

; Allocate new TCB, save new SP in it
        lhld new_sp
        xchg
        lhld ptcba      ; next TCB to allocate
        mov M,d         ; save new SP in new TCB
        inx h
        mov M,e
        inx h
        mvi M,255       ; mark end of TCB list
        shld ptcba      ; pointer to next TCB to alloc
; return to caller as old task
        pop h
        pop d
        pop b
        pop psw
        ret


task:   push psw        ; save caller's regs
        in BANK_SELECT_I
        push psw        ; bank too
        push b          ; on current stack
        push d
        push h
 
; save SP in current TCB
        lxi h,0
        dad SP          ; HL now has SP
        xchg            ;  move to DE
        lhld ptcb       ; pointer to current TCB
        mov M,d         ; save task's SP in TCB
        inx h
        mov M,e

; step to next TCB
        inx h           ; step to next TCB
        mov a,M
        cpi 255         ; past end of TCB list?
        jnz L1          ; no
        lxi h,TCB0      ; yes, point to 1st TCB
L1:     shld new_ptcb   ; pointer to TCB of new task

; set new task's stack pointer
        mov d,M         ; get new task's SP             
        inx h
        mov e,M         ; DE = new task's stack pointer
        xchg            ;   move to HL
; Switch to new Stack
        sphl            

; switch to new TCB
        lhld new_ptcb   ; point to next TCB
        shld ptcb       ; set as current TCB
; pop new stack, return to caller as new task
        pop h
        pop d
        pop b
        pop psw
        out BANK_SELECT_O  ; restore bank
        pop psw
; return to new task
        ret


