diff src/stack.s @ 119:a6a53e5c04bd

Make a call stack implementation that is more complete and maybe cleaner.
author William Astle <lost@l-w.ca>
date Fri, 29 Dec 2023 01:40:39 -0700
parents
children
line wrap: on
line diff
--- /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