/**************************************************************************** OS/A65 Version 2.0.0 Multitasking Operating System for 6502 Computers Copyright (C) 1989-1998 Andre Fachat This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************/ /* TODO: make stack addr computation a table lookup, which is faster */ /* Struct Task Environment Entry */ /* we have three structs now: * TE_* for task environment handling - not needed for system without * memory management * TT_* task table, contains STD streams, etc * TH_* thread table, has stack info and state */ #define TE_SLEN 0 /* we don't have envs */ /************************************************************************ * These routines are needed in the env section! * inienv * setthread * initsp * push * pull * memtask * memsys * * sbrk * getenv * freenv */ &&enmem = notimp ; to enable memory blocks to the kernel &&setblk = notimp ; to set memory blocks in MMU mapping #ifdef STACKCOPY .zero zp .word 0 .data Stacks .dsb MAXNTHREADS * STACKSIZE .text #endif &inienv .( lda #<-1 sta actThread sta actTask lda #1 sta Syscnt clc rts .) setthread .( .data newThread .byt 0 .text cmp actThread bne doit rts doit sta newThread ldx actThread cpx #<-1 beq nosave lda THREADSAVE sta threadTab + TH_LIBSAVE,x lda THREADSAVE+1 sta threadTab + TH_LIBSAVE+1,x #ifdef STACKCOPY txa ; stack is 8 * TH_SLEN = 64 ldy #0 sty zp+1 asl rol zp+1 asl rol zp+1 asl rol zp+1 clc adc #<Stacks sta zp lda #>Stacks adc zp+1 sta zp+1 ;bcc l1 ;inc zp+1 ;l1 lda threadTab + TH_SP,x tay iny l2 cpy #STACKSIZE bcs savetask lda $100,y sta (zp),y iny bne l2 #endif savetask ldy threadTab + TH_TASK,x lda TASKSAVE sta taskTab + TT_LIBSAVE,y lda TASKSAVE + 1 sta taskTab + TT_LIBSAVE + 1,y nosave loadtask ldx newThread stx actThread cpx #<-1 bne load stx actTask beq noload load ldy threadTab + TH_TASK,x sty actTask lda taskTab + TT_LIBSAVE,y sta TASKSAVE lda taskTab + TT_LIBSAVE + 1,y sta TASKSAVE + 1 loadthread lda threadTab + TH_LIBSAVE,x sta THREADSAVE lda threadTab + TH_LIBSAVE+1,x sta THREADSAVE+1 #ifdef STACKCOPY txa ldy #0 sty zp+1 asl rol zp+1 asl rol zp+1 asl rol zp+1 clc adc #<Stacks sta zp lda #>Stacks adc zp+1 sta zp+1 ;bcc l3 ;inc zp+1 ;l3 lda threadTab + TH_SP,x tay iny l4 cpy #STACKSIZE bcs endset lda (zp),y sta $100,y iny bne l4 #endif noload endset rts .) initsp .( #ifdef STACKCOPY lda #STACKSIZE-1 ;ldx actThread sta threadTab + TH_SP,x rts #else .data divsp .byt 0 .text ;ldx actThread txa clc adc #TH_SLEN sta divsp asl asl ; split stack clc adc divsp sta threadTab + TH_SP,x dec threadTab + TH_SP,x rts #endif .) pull .( ldx actThread inc threadTab + TH_SP,x lda threadTab + TH_SP,x tay lda $0100,y rts .) &push .( pha ldx actThread lda threadTab + TH_SP,x tay pla sta $0100,y dec threadTab + TH_SP,x rts .) .( .zero AC .byt 0 XR .byt 0 YR .byt 0 SR .byt 0 ADR .word 0 &SSP .byt 0 .text /* * this one is used to return from an interrupt. We do not need to save * any registers. so for brevity, we do it as macro * This doesn't check for interrupted devices, as we do not have them * without MMU (so far). */ #define MEMTASK2() \ .( :\ sei :\ dec Syscnt :\ bne mtask :\ tsx :\ stx SSP :\ ; ldy actTask :\ ; ldx taskTab+TT_ENV,y :\ ; beq system :\ ; ldx #%10001100 :\ ; stx $fff0 :\ ;system :\ ldy actThread :\ ldx threadTab+TH_SP,y :\ txs :\ mtask .) /* * This is the standard return to user space. the kernel jumps here, * so we need not save any return address, but use the one on the * user stack. */ &&memtask .( php sei dec Syscnt ; wieder in Task bne mtask ; nein dann Ende bit adev ; Ruecksprung in Device bpl mtask ; ja dann Ende sty YR ; sonst Task-Env setzen stx XR sta AC pla ; SR tsx stx SSP ldy actThread ldx threadTab+TH_SP,y txs ; ldy actTask ; ldx taskTab+TT_ENV,y ; beq system ; ldx #%10001100 ; map alternate 8x96 memory bank ; stx $fff0 ;system pha ; SR lda AC ldy YR ldx XR mtask plp rts .) /* * This is the kernel entry routine. It leaves all registers as they * are, except for the stack pointer, which is set to the system stack. * also the return address is moved from user stack to system stack, * to allow "JSR"-ing to memsys. */ &&memsys php sei pha ; lda #%11100000 ; map system memory ; sta $fff0 lda Syscnt inc Syscnt cmp #0 bne mse bit adev ; called by device bmi msys ; no then save stack mse pla plp rts msys pla sta AC pla sta SR stx XR ; sty YR pla sta ADR pla sta ADR+1 tsx txa ldx actThread sta threadTab+TH_SP,x ldx SSP txs lda ADR+1 pha lda ADR pha lda SR pha lda AC ldx XR ; ldy YR plp cld rts .) &&sbrk .( bcc ok sec lda #E_NOMEM rts ok lda #>ROMSTART ; return available memory clc rts .) kgetenv .( ldx #0 ; tya ; bne system ; inx system clc rts .) freenv .( clc rts .) /* * MAPSYSBUF() maps the PCBUF of the active task into the system memory * at address SYSBUF. It's not needed in a C64... */ #undef MAPSYSBUF #define SYSBUF $200 /* * MAPENV() maps the address given in a/y in env x to somewhere in the * kernel map. returns mapped address in a/y * MAPAENV() does the same but for the actual task (env) */ #define MAPENV() #define MAPAENV() /* * needed for GETINFO, gives RAM available for task */ #define GETTASKMEM lda #>ROMSTART /* * copy routines for SEND/RECEIVE and FORK */ #undef CPPCBUFRX #undef CPPCBUFTX #define CPFORKBUF() /* * needed in device code to get active environment in AC */ #define GETACTENV() lda #<-1