;
; Ullrich von Bassewitz, 19.03.2001
;
; Stack checking code. These are actually two routines, one to check the C
; stack, and the other one to check the 6502 hardware stack.
; For performance reasons (to avoid having to pass a parameter), the compiler
; calls the cstkchk routine *after* allocating space on the stack. So the
; stackpointer may already be invalid if this routine is called. In addition
; to that, pushs and pops that are needed for expression evaluation are not
; checked (this would be way too much overhead). As a consequence we will
; operate using a safety area at the stack bottom. Once the stack reaches this
; safety area, we consider it an overflow, even if the stack is still inside
; its' bounds.
;

 	.export	 	stkchk, cstkchk
 	.constructor	initstkchk, 25
	.import	 	__STACKSIZE__			; Linker defined
       	.import	       	pusha0, _exit
 	.importzp	sp

	; Use macros for better readability
	.macpack	generic
        .macpack        cpu


; ----------------------------------------------------------------------------
; Initialization code. This is a constructor, so it is called on startup if
; the linker has detected references to this module.

.segment        "INIT"

.proc	initstkchk

     	lda  	sp
     	sta  	initialsp
     	sub  	#<__STACKSIZE__
     	sta  	lowwater
     	lda  	sp+1
     	sta  	initialsp+1
     	sbc  	#>__STACKSIZE__
.if (.cpu .bitand ::CPU_ISET_65SC02)
       	ina                     ; Add 256 bytes safety area
.else
       	add    	#1     	        ; Add 256 bytes safety area
.endif
     	sta  	lowwater+1
     	rts

.endproc

; ----------------------------------------------------------------------------
; 6502 stack checking routine. Does not need to save any registers.
; Safety zone for the hardware stack is 12 bytes.

.code

stkchk:	tsx
       	cpx  	#12
       	bcc    	Fail	     	; Jump on stack overflow
     	rts	  		; Return if ok

; ----------------------------------------------------------------------------
; C stack checking routine. Does not need to save any registers.

.code

cstkchk:

; Check the high byte of the software stack

@L0:   	lda  	lowwater+1
       	cmp  	sp+1
       	bcs    	@L1
       	rts

; Check low byte

@L1: 	bne	CStackOverflow
     	lda	lowwater
     	cmp	sp
      	bcs	CStackOverflow
Done: 	rts

; We have a C stack overflow. Set the stack pointer to the initial value, so
; we can continue without worrying about stack issues.

CStackOverflow:
	lda	initialsp
	sta	sp
	lda	initialsp+1
	sta	sp+1

; Generic abort entry. We should output a diagnostic here, but this is
; difficult, since we're operating at a lower level here.

Fail:	lda	#4
        ldx     #0
 	jmp	_exit

; ----------------------------------------------------------------------------
; Data

.bss

; Initial stack pointer value. Stack is reset to this in case of overflows to
; allow program exit processing.
initialsp: 	.word	0

; Stack low water mark.
lowwater:  	.word	0