- The cc65 assembler variable 'ptr1' (a general zero page pointer) is actually part of the cc65 zero page area so it's a bad idea (tm) to use it in swapping that very area.

- The cc65 assembler variable 'sp' (the pointer to the C stack) is actually part of the cc65 zero page area so there's no need to manage it explicitly. Furthermore it is known to reside at the very start of the area so it can be initialized there for new threads.
This commit is contained in:
oliverschmidt 2007-08-10 10:45:35 +00:00
parent f8bf3e1428
commit 1c77f6f1d5
3 changed files with 120 additions and 90 deletions

View file

@ -30,15 +30,12 @@
; ;
; Author: Adam Dunkels <adam@sics.se> ; Author: Adam Dunkels <adam@sics.se>
; ;
; $Id: mtarch-asm.S,v 1.1 2007/04/21 22:15:45 oliverschmidt Exp $ ; $Id: mtarch-asm.S,v 1.2 2007/08/10 10:45:35 oliverschmidt Exp $
; ;
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
.importzp ptr1
.importzp sp
.import __ZP_START__ .import __ZP_START__
.import _mtarch_asm_threadspreg .import _mtarch_asm_threadspreg
.import _mtarch_asm_threadsp
.import _mtarch_asm_threadzp .import _mtarch_asm_threadzp
.import _mtarch_asm_threadstack .import _mtarch_asm_threadstack
@ -48,68 +45,77 @@
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
.bss .bss
kernelsp: .res 2
kernelspreg: .res 1 kernelspreg: .res 1
zpsave: .res 2
zpsize = 32 zpspace = 26 ; see <cc65 source>/asminc/zeropage.inc
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
.code .code
; Switch to thread defined by threadsp, threadstack and threadspreg. ; Switch to thread defined by threadzp, threadstack and threadspreg.
; The kernel stack is swapped onto the threadstack, and the ; The kernel CPU stack is swapped onto the threadstack, and the
; sp and spreg are saved to the local variables "kernelsp" and ; CPU stack pointer is saved to the local variable "kernelspreg".
; "kernelspreg". Also, the zeropage variables are saved. ; Also, the zeropage variables are saved.
_mtarch_asm_exec: _mtarch_asm_exec:
sei sei
; Save current stack pointer
lda sp
sta kernelsp
lda sp+1
sta kernelsp+1
; Save kernel CPU stack pointer
tsx tsx
stx kernelspreg stx kernelspreg
lda _mtarch_asm_threadzp ; Save zp locations FE/FF
sta ptr1 lda $FE
lda _mtarch_asm_threadzp+1 sta zpsave
sta ptr1+1 lda $FF
sta zpsave+1
; Get zero page buffer addr
lda _mtarch_asm_threadzp
sta $FE
lda _mtarch_asm_threadzp+1
sta $FF
; Swap zero page content with buffer content
ldy #0 ldy #0
: lda <__ZP_START__,y : lda <__ZP_START__,y
tax tax
lda (ptr1),y lda ($FE),y
sta <__ZP_START__,y sta <__ZP_START__,y
txa txa
sta (ptr1),y sta ($FE),y
iny iny
cpy #zpsize cpy #zpspace
bne :- bne :-
; Get CPU stack buffer addr
lda _mtarch_asm_threadstack lda _mtarch_asm_threadstack
sta ptr1 sta $FE
lda _mtarch_asm_threadstack+1 lda _mtarch_asm_threadstack+1
sta ptr1+1 sta $FF
; Get CPU stack size
ldy kernelspreg ; Determine the smallest of the two stack pointers, ldy kernelspreg ; Determine the smallest of the two stack pointers,
cpy _mtarch_asm_threadspreg ; as we only need to swap the used part of the stack. cpy _mtarch_asm_threadspreg ; as we only need to swap the used part of the stack.
bcc :+ bcc :+
ldy _mtarch_asm_threadspreg ldy _mtarch_asm_threadspreg
; Swap CPU stack content with buffer content
: lda $0100,y : lda $0100,y
tax tax
lda (ptr1),y lda ($FE),y
sta $0100,y sta $0100,y
txa txa
sta (ptr1),y sta ($FE),y
iny iny
bne :- bne :-
lda _mtarch_asm_threadsp ; Restore zp locations FE/FF
sta sp lda zpsave
lda _mtarch_asm_threadsp+1 sta $FE
sta sp+1 lda zpsave+1
sta $FF
; Set thread CPU stack pointer
ldx _mtarch_asm_threadspreg ldx _mtarch_asm_threadspreg
txs txs
@ -121,10 +127,10 @@ _mtarch_asm_exec:
rti rti
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
; Switch from thread defined by threadsp, threadstack and threadspreg. ; Switch from thread defined by threadzp, threadstack and threadspreg.
; The kernel stack is swapped back from the threadstack, and the ; The kernel CPU stack is swapped back from the threadstack, and the
; sp and spreg are restored from the local variables "kernelsp" and ; CPU stack pointer is restored from the local variable "kernelspreg".
; "kernelspreg". ; Also, the zeropage variables are restored.
_mtarch_asm_yield: _mtarch_asm_yield:
php php
pha pha
@ -144,54 +150,63 @@ _mtarch_asm_yield:
adc #0 adc #0
sta $0106,x sta $0106,x
lda sp ; Save thread CPU stack pointer
sta _mtarch_asm_threadsp
lda sp+1
sta _mtarch_asm_threadsp+1
tsx tsx
stx _mtarch_asm_threadspreg stx _mtarch_asm_threadspreg
lda _mtarch_asm_threadzp ; Save zp locations FE/FF
sta ptr1 lda $FE
lda _mtarch_asm_threadzp+1 sta zpsave
sta ptr1+1 lda $FF
sta zpsave+1
; Get zero page buffer addr
lda _mtarch_asm_threadzp
sta $FE
lda _mtarch_asm_threadzp+1
sta $FF
; Swap zero page content with buffer content
ldy #0
: lda <__ZP_START__,y
tax
lda ($FE),y
sta <__ZP_START__,y
txa
sta ($FE),y
iny
cpy #zpspace
bne :-
; Get CPU stack buffer addr
lda _mtarch_asm_threadstack
sta $FE
lda _mtarch_asm_threadstack+1
sta $FF
; Get CPU stack size
ldy kernelspreg ; Determine the smallest of the two stack pointers, ldy kernelspreg ; Determine the smallest of the two stack pointers,
cpy _mtarch_asm_threadspreg ; as we only need to swap the used part of the stack. cpy _mtarch_asm_threadspreg ; as we only need to swap the used part of the stack.
bcc :+ bcc :+
ldy _mtarch_asm_threadspreg ldy _mtarch_asm_threadspreg
: lda <__ZP_START__,y ; Swap CPU stack content with buffer content
tax
lda (ptr1),y
sta <__ZP_START__,y
txa
sta (ptr1),y
iny
cpy #zpsize
bne :-
lda _mtarch_asm_threadstack
sta ptr1
lda _mtarch_asm_threadstack+1
sta ptr1+1
ldy #0
: lda $0100,y : lda $0100,y
tax tax
lda (ptr1),y lda ($FE),y
sta $0100,y sta $0100,y
txa txa
sta (ptr1),y sta ($FE),y
iny iny
bne :- bne :-
lda kernelsp ; Restore zp locations FE/FF
sta sp lda zpsave
lda kernelsp+1 sta $FE
sta sp+1 lda zpsave+1
sta $FF
; Set kernel CPU stack pointer
ldx kernelspreg ldx kernelspreg
txs txs
@ -199,16 +214,31 @@ _mtarch_asm_yield:
rts rts
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
_mtarch_asm_start: _mtarch_asm_start:
lda _mtarch_asm_threadzp ; Save zp locations FE/FF
sta ptr1 lda $FE
lda _mtarch_asm_threadzp+1 sta zpsave
sta ptr1+1 lda $FF
sta zpsave+1
ldy #0 ; Get zero page buffer addr
lda _mtarch_asm_threadzp
sta $FE
lda _mtarch_asm_threadzp+1
sta $FF
; Copy zero page content to buffer
ldy #$00
: lda <__ZP_START__,y : lda <__ZP_START__,y
sta (ptr1),y sta ($FE),y
iny iny
cpy #zpsize cpy #zpspace
bne :- bne :-
; Restore zp locations FE/FF
lda zpsave
sta $FE
lda zpsave+1
sta $FF
rts rts
;--------------------------------------------------------------------- ;---------------------------------------------------------------------

View file

@ -30,7 +30,7 @@
* *
* Author: Adam Dunkels <adam@sics.se> * Author: Adam Dunkels <adam@sics.se>
* *
* $Id: mtarch.c,v 1.1 2007/04/21 22:15:45 oliverschmidt Exp $ * $Id: mtarch.c,v 1.2 2007/08/10 10:45:35 oliverschmidt Exp $
*/ */
#include <string.h> #include <string.h>
@ -38,7 +38,6 @@
#include "mtarch.h" #include "mtarch.h"
unsigned char mtarch_asm_threadspreg; unsigned char mtarch_asm_threadspreg;
unsigned char *mtarch_asm_threadsp;
unsigned char *mtarch_asm_threadzp; unsigned char *mtarch_asm_threadzp;
unsigned char *mtarch_asm_threadstack; unsigned char *mtarch_asm_threadstack;
@ -65,6 +64,10 @@ mtarch_start(struct mtarch_thread *thread,
memset(thread->cpustack, 0, sizeof(thread->cpustack)); memset(thread->cpustack, 0, sizeof(thread->cpustack));
memset(thread->cstack, 0, sizeof(thread->cstack)); memset(thread->cstack, 0, sizeof(thread->cstack));
/* Copy current zero page content as template. */
mtarch_asm_threadzp = &(thread->zp);
mtarch_asm_start();
/* Create a CPU stack frame with the appropriate values. */ /* Create a CPU stack frame with the appropriate values. */
thread->cpustack[MTARCH_CPUSTACKSIZE - 2] = ((unsigned short)function) / 0x100; /* high byte of return address */ thread->cpustack[MTARCH_CPUSTACKSIZE - 2] = ((unsigned short)function) / 0x100; /* high byte of return address */
thread->cpustack[MTARCH_CPUSTACKSIZE - 3] = ((unsigned short)function) % 0x100; /* low byte of return address */ thread->cpustack[MTARCH_CPUSTACKSIZE - 3] = ((unsigned short)function) % 0x100; /* low byte of return address */
@ -75,12 +78,12 @@ mtarch_start(struct mtarch_thread *thread,
thread->spreg = MTARCH_CPUSTACKSIZE - 8; thread->spreg = MTARCH_CPUSTACKSIZE - 8;
/* Setup the C stack with the data pointer. */ /* Setup the C stack with the data pointer. */
thread->cstack[MTARCH_CPUSTACKSIZE - 2] = ((unsigned short)data) / 0x100; /* high byte of data pointer */ thread->cstack[MTARCH_CSTACKSIZE - 2] = ((unsigned short)data) / 0x100; /* high byte of data pointer */
thread->cstack[MTARCH_CPUSTACKSIZE - 3] = ((unsigned short)data) % 0x100; /* low byte of data pointer */ thread->cstack[MTARCH_CSTACKSIZE - 3] = ((unsigned short)data) % 0x100; /* low byte of data pointer */
thread->sp = &thread->cstack[MTARCH_CSTACKSIZE - 3];
mtarch_asm_threadzp = &(thread->zp); /* Setup the C stack pointer. */
mtarch_asm_start(); thread->zp[1] = ((size_t)&thread->cstack[MTARCH_CSTACKSIZE - 3]) / 0x100; /* high byte of C stack pointer */
thread->zp[0] = ((size_t)&thread->cstack[MTARCH_CSTACKSIZE - 3]) % 0x100; /* low byte of C stack pointer */
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
void void
@ -95,14 +98,12 @@ mtarch_exec(struct mtarch_thread *thread)
/* Switch processor stack. The call to mtarch_asm_switch() will not /* Switch processor stack. The call to mtarch_asm_switch() will not
return until the process that we switch to calls yield(). */ return until the process that we switch to calls yield(). */
mtarch_asm_threadspreg = thread->spreg; mtarch_asm_threadspreg = thread->spreg;
mtarch_asm_threadsp = thread->sp;
mtarch_asm_threadstack = &(thread->cpustack[0]); mtarch_asm_threadstack = thread->cpustack;
mtarch_asm_threadzp = &(thread->zp[0]); mtarch_asm_threadzp = thread->zp;
mtarch_asm_exec(); mtarch_asm_exec();
thread->sp = mtarch_asm_threadsp;
thread->spreg = mtarch_asm_threadspreg; thread->spreg = mtarch_asm_threadspreg;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/

View file

@ -30,7 +30,7 @@
* *
* Author: Adam Dunkels <adam@sics.se> * Author: Adam Dunkels <adam@sics.se>
* *
* $Id: mtarch.h,v 1.2 2007/04/21 22:15:45 oliverschmidt Exp $ * $Id: mtarch.h,v 1.3 2007/08/10 10:45:35 oliverschmidt Exp $
*/ */
#ifndef __MTARCH_H__ #ifndef __MTARCH_H__
@ -38,11 +38,10 @@
#define MTARCH_CPUSTACKSIZE 256 #define MTARCH_CPUSTACKSIZE 256
#define MTARCH_CSTACKSIZE 256 #define MTARCH_CSTACKSIZE 256
#define MTARCH_ZPSIZE 32 #define MTARCH_ZPSIZE 26 // see <cc65 source>/asminc/zeropage.inc
struct mtarch_thread { struct mtarch_thread {
unsigned char spreg; unsigned char spreg;
unsigned char *sp;
unsigned char cpustack[MTARCH_CPUSTACKSIZE]; unsigned char cpustack[MTARCH_CPUSTACKSIZE];
unsigned char cstack [MTARCH_CSTACKSIZE]; unsigned char cstack [MTARCH_CSTACKSIZE];
unsigned char zp [MTARCH_ZPSIZE]; unsigned char zp [MTARCH_ZPSIZE];