# HG changeset patch # User William Astle # Date 1703839239 25200 # Node ID a6a53e5c04bd0667c39a33c9241a2cfff458dd18 # Parent cddbe8bc07e5a20a9b45173548896155f6c7a80a Make a call stack implementation that is more complete and maybe cleaner. diff -r cddbe8bc07e5 -r a6a53e5c04bd Makefile --- a/Makefile Thu Dec 28 22:00:32 2023 -0700 +++ b/Makefile Fri Dec 29 01:40:39 2023 -0700 @@ -1,7 +1,7 @@ .PHONY: all all: bin/lwbasic.rom bin/lwbasic-coco2b.rom bin/lwbasic-coco3.rom bin/coco.zip bin/coco2.zip bin/coco2b.zip bin/coco3.zip -lwb_srcs := consscr.s defs.s error.s expr.s fps.s genio.s init.s int.s interp.s irq.s keyb.s keywords.s miscdata.s number.s print.s progctrl.s token.s vars.s +lwb_srcs := consscr.s defs.s error.s expr.s fps.s genio.s init.s int.s interp.s irq.s keyb.s keywords.s miscdata.s number.s print.s progctrl.s stack.s token.s vars.s lwb_srcs := $(addprefix src/,$(lwb_srcs)) bin/lwbasic.rom: src/lwbasic.s $(lwb_srcs) diff -r cddbe8bc07e5 -r a6a53e5c04bd src/error.s --- a/src/error.s Thu Dec 28 22:00:32 2023 -0700 +++ b/src/error.s Fri Dec 29 01:40:39 2023 -0700 @@ -27,7 +27,7 @@ jsr print_uint16d ; display the line number ERROR3 lds freetop ; reset the stack pointer (error routine could be called anywhere) clr ,-s ; reset the call stack - sts stackptr + sts cstackptr jmp immediate ; go back to immediate mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Error messages diff -r cddbe8bc07e5 -r a6a53e5c04bd src/init.s --- a/src/init.s Thu Dec 28 22:00:32 2023 -0700 +++ b/src/init.s Fri Dec 29 01:40:39 2023 -0700 @@ -214,7 +214,7 @@ leax -200,x ; allocate 200 bytes of string space stx freetop ; save top of free memory clr ,-x ; make a hole for the "end of call stack" flag - stx stackptr ; save the new call stack pointer + stx cstackptr ; save the new call stack pointer leas ,x ; put the actual stack below the above ldx #heapstart ; point to start of free memory clr ,x+ ; put a NUL before the start of the program diff -r cddbe8bc07e5 -r a6a53e5c04bd src/lwbasic.s --- a/src/lwbasic.s Thu Dec 28 22:00:32 2023 -0700 +++ b/src/lwbasic.s Fri Dec 29 01:40:39 2023 -0700 @@ -44,6 +44,7 @@ include genio.s include interp.s include progctrl.s + include stack.s include print.s include error.s include expr.s diff -r cddbe8bc07e5 -r a6a53e5c04bd src/progctrl.s --- a/src/progctrl.s Thu Dec 28 22:00:32 2023 -0700 +++ b/src/progctrl.s Fri Dec 29 01:40:39 2023 -0700 @@ -48,7 +48,7 @@ ldx ,s ; get return address lds freetop ; reset stack to top of memory clr ,-s ; put a flag to stop stack searches (NEXT, RETURN) - sts stackptr ; reset pointer for call stack + sts cstackptr ; reset pointer for call stack clr contstmt ; clear "CONT" destination clr contstmt+1 jmp ,x ; return to caller @@ -106,7 +106,7 @@ ; GOSUB command cmd_gosub jsr parse_lineno ; parse the destination line so return location is after the line number ldd #tok_gosub*256+4 ; stack frame details - bsr callstack_alloc ; make a stack frame + jsr cstack_alloc ; make a stack frame ldx curline ; save current line pointer stx ,u ldx inputptr ; save current input pointer @@ -121,11 +121,11 @@ cmd_pop skip1lda ; set nonzero for POP cmd_return clra ; set zero for RETURN pshs a ; save operation type - bsr callstack_first ; get first entry on call stack + jsr cstack_first ; get first entry on call stack bne cmd_return1 ; brif there's a frame - don't error RG_ERROR ldb #err_rg ; raise RETURN without GOSUB jmp ERROR -cmd_return0 bsr callstack_next ; move to next entry +cmd_return0 jsr cstack_next ; move to next entry beq RG_ERROR ; brif end of stack - raise error cmd_return1 cmpb #tok_gosub ; do we have a GOSUB frame? bne cmd_return0 ; brif not - try again @@ -135,54 +135,6 @@ stx curline ldx 2,u ; get back saved input pointer stx inputptr -cmd_return2 bsr callstack_pop ; clean up call stack +cmd_return2 jsr cstack_popto ; clean up call stack bra cmd_data ; move to end of statement (move past any "ON GOSUB" entries -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Point to the first entry on the call stack; yes this is trivial but it points to the payload, not the header. Also -; sets Z if there is nothing on the stack. -callstack_first ldu stackptr ; get stack pointer - ldb ,u++ ; set flags on frame type and adjust pointer - rts -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Move to the next frame on the call stack; enter with U pointing to a stack frame payload area -callstack_next ldb -1,u ; get length of this frame - leau b,u ; move to the next frame - ldb -2,u ; set flags on frame type code - rts -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Create a stack frame. Enter with the frame type flag in A and the size in B. -; -; The stack frame of size B bytes plus 2 bytes for the length and type flag will be allocated between the actual -; hardware stack and the current call stack pointer. Return with the pointer to the allocated frame in U. As long as -; there are no pointers to anything on the hardware stack, this will allow the stack to be entirely intact after -; the call. -callstack_alloc addb #2 ; account for the header bytes - pshs a,b ; save the type and length - negb ; need a negative offset - leax ,s ; point to current bottom of stack - leas b,s ; make a hole below the stack - leau ,s ; get a pointer to the destination for copying -callstack_alloc0 - lda ,x+ ; copy a byte down - sta ,u+ - cmpx stackptr ; have we reached the top of the stack? - blo callstack_alloc0 ; brif not - stu stackptr ; save the new call stack pointer - puls d ; get back the type and length values - std ,u++ ; save type and length - rts -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Pop the call stack to the end of the frame pointed to by U; this will relocate the hardware stack to close the -; newly made gap in memory. -callstack_pop leau -2,u ; move back to header - ldb 1,u ; get length of frame - leax b,u ; point to element after this frame - sts ,--s ; save the current bottom of the stack - stx stackptr ; save new call stack pointer -callstack_pop0 lda ,-u ; copy a byte up - sta ,-x - cmpu ,s ; at the bottom of the call stack? - bhi callstack_pop0 ; brif not - leas 2,x ; reset the stack pointer (and lose the saved stack pointer value) - rts *pragmapop list diff -r cddbe8bc07e5 -r a6a53e5c04bd src/stack.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stack.s Fri Dec 29 01:40:39 2023 -0700 @@ -0,0 +1,80 @@ + *pragmapush list + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Call stack management. +; +; The call stack exists above the interpreter stack. The call stack consists of a sequence of stack records of varying +; sizes which start with an 8 bit length field, then the payload, which will usually begin with an 8 bit type code. The +; bottom of the call stack is stored in cstackptr. The frame sizes must all be <= 125 bytes since a 2 byte frame header +; will be included in the sizing +; +; Allocate a call stack frame of size B and type A. Return a pointer to the payload area of the allocated entry in U +cstack_alloc pshs a ; save type flag + addb #2 ; account for the frame header + negb ; so we can subtract from pointers + leax ,s ; point to current stack pointer + leas b,s ; move the stack pointer down + leau ,s ; point to new stack pointer for data copy +cstack_alloc0 lda ,x+ ; copy a byte in the stack down + sta ,y+ + cmpx cstackptr ; have we reached the original call stack? + bne cstack_alloc0 ; brif not + negb ; get back original size + stu cstackptr ; save the new bottom of the call stack + stb ,u++ ; save size in entry + puls a ; get back type flag + sta -11,u ; put it in the stack frame +cstack_pop0 rts +; Clear call stack without resetting the interpreter stack +cstack_clear ldd stringtab ; point to the bottom of the string space + subd #1 ; make room for a NULL stack frame marking the top of the stack +cstack_pop1 tfr d,u ; save new call stack pointer - destination of copy + subd cstackptr ; subtract out the current call stack pointer + beq cstack_clear1 ; brif the stack is already empty + tfr d,y ; save byte count to move in counter + sts ,--s ; save the current stack pointer - end of copy address + ldx cstackptr ; get current call stack pointer - source of copy + stu cstackptr ; save new call stack pointer + clr ,u ; put the NULL frame at the top of the call stack +cstack_clear0 lda ,-x ; copy a byte upward + sta ,-u + cmpx ,s ; have we reached the end of the copy? + bne cstack_clear0 ; brif not + leas ,u ; reset the main stack to the moved location +cstack_clear1 rts +; Pop the entry pointed to by U off the call stack and all entries below it +cstack_popto ldb ,u ; get size of the current entry + bra cstack_popto0 ; go do the rest of the processing +; Pop the first entry off the call stack +cstack_pop ldu cstackptr ; point to the call stack + ldb ,u ; get size of this frame + beq cstack_pop0 ; brif there's nothing to pop - do nothing +cstack_popto0 leau b,u ; point to the next entry + tfr u,d ; put pointer where we need it + bra cstack_pop1 ; go adjust the call stack +; Search for the first matching stack frame where the second byte matches the value in A. Enter +; at cstack_searchnext to search from the entry following the entry pointed to by X. Return with +; C set if not found. +cstack_search ldx cstackptr ; point to the call stack +cstack_search0 ldb ,x ; get size of this entry + bne cstack_search2 ; brif not the end of the call stack +cstack_search1 comb ; clear C for not found + rts +cstack_search2 cmpa 1,x ; does the type match? + bne cstack_search3 ; brif not + rts ; return result (C is clear from CMPA match) +cstack_searchnext + ldb ,x ; get length of this frame + beq cstack_search1 ; brif we're already at the end of the stack +cstack_search3 abx ; move to next entry + bra cstack_search0 ; check if this one matches +; Point X to the first entry on the call stack +cstack_first ldx cstackptr ; point to stack entry + lda ,x++ ; set Z set if end of stack, move to payload + rts +; Point X to the next entry on the call stack +cstack_next ldb -2,x ; get length of this entry + abx ; adjust to next entry payload + ldb -2,x ; set Z if end of stack + rts + *pragmapop list diff -r cddbe8bc07e5 -r a6a53e5c04bd src/vars.s --- a/src/vars.s Thu Dec 28 22:00:32 2023 -0700 +++ b/src/vars.s Fri Dec 29 01:40:39 2023 -0700 @@ -10,7 +10,7 @@ memsize rmb 2 ; top of memory not reserved freetop rmb 2 ; top of free memory (bottom of string space) stringtab rmb 2 ; bottom of used string space -stackptr rmb 2 ; bottom of the "stack frame" stack (the actual stack is below here) +cstackptr rmb 2 ; bottom of the "stack frame" stack (the actual stack is below here) progtext rmb 2 ; pointer to start of program text vartab rmb 2 ; pointer to start of integer scalars objecttab rmb 2 ; pointer to start of arrays and other variable sized objects