/*
 * ParamPassing3b.asm
 *   Modified: 6 Feb 2024
 *   Authors:  Dr. Schwartz, Josh Weaver
 *   Purpose:  Demonstrate the use of parameter pointers with the stack
 */ 
.include "ATxmega128A1Udef.inc"
;******************************INITIALIZATIONS***************************************
.equ	stack_init = 0x3FFF ; Initialize stack pointer (between 0x2000 & 0x3FFF)	
                            ; Default is 0x3FFF
.org 0x0000
	jmp MAIN+

.org 0x100                  ; Place Data at address 0x100
LOCAT1: .db 0x37            ; Define the data in bytes
.org 0x106
LOCAT2: .db 0xA3            ; Define the data in bytes
;*******************************PROGRAM START****************************************
.org 0x200
MAIN:
    ldi r16, low(stack_init)
    out CPU_SPL, r16	        ; Initialize low byte of stack pointer
    ldi r16, high(stack_init)
    out CPU_SPH, r16	        ; Initialize high byte of stack pointer
		
    ldi ZL, low(LOCAT2 << 1)    ; Push the address of LOCAT2 to the stack.
    push ZL                     ; This address represents the pointer to parameter 2.
    ldi ZH, high(LOCAT2 << 1)
    push ZH

    ldi ZL, low(LOCAT1 << 1)    ; Push the address of LOCAT1 to the stack.
    push ZL                     ; This address represents the pointer to parameter 1.
    ldi ZH, high(LOCAT1 << 1)
    push ZH

    rcall AVGA                  ; Call subroutine AVGA to get the average
;   rcall AVGB                  ; Call subroutine AVGB to get the average
	
HERE:	
    rjmp HERE
;********************************SUBROUTINES*****************************************
/************************************************************************************
 * Name:     AVGA
 * Purpose:  Get the Average of parameters pointed to by addresses on the stack
 * Inputs:   No direct input (from stack)
 * Outputs:  r16 is the place for the result
 * Affected: r16, r17, r18, X, Z, Stack
 ***********************************************************************************/
AVGA:
    ; We will use r18 and X to get the return address from the stack.  These
    ; registers will not be changed and will be used to return the address back to
    ; the stack.  Since the address for program memory must be shifted by 1, it will
    ; be placed into Z and modified as needed.
    pop r18      ; Using r18 to handle third byte (HIGHEST) of address location.
    pop XH       ; Grab High byte of return address from stack
    pop XL       ; Grab Low byte of return addres from stack

    pop ZH       ; Grab the high byte of the address pointing to the first parameter
    pop ZL       ; Grab the low byte of the address pointing to the first parameter
   
    lpm r16, Z   ; Grab the first parameter and place in r16

    pop ZH       ; Grab the high byte of the address pointing to the second parameter
    pop ZL       ; Grab the low byte of the address pointing to the second parameter

    lpm r17, Z   ; Grab the second parameter and place in r17

    add r16, r17 ; r16 = r16 + r17
    asr r16      ; Shift A right by 1 bit (divide by 2) keeping bit 7
                 ; (for sign extension) 

    push XL      ; Place the original return address back on the stack
    push XH
    push r18
    ret          ; Return from subroutine
/************************************************************************************
 * Name:     AVGB
 * Purpose:  Get the Average of parameters pointed to by addresses on the stack
 * Inputs:   No direct input (from stack)
 * Outputs:  r16 is the place for the result
 * Affected: r16, r17, Y, Z, Stack 
 *           ***Modified AND THUS HAS LEFT OVER INFO. EVERY
 *           CALL INCREASES THE SIZE OF THE DATA ON THE STACK!!!
 ***********************************************************************************/
AVGB:
    in YL, CPU_SPL      ; Grab low byte of stack pointer
    in YH, CPU_SPH      ; Grab high byte of stack pointer

    ldd ZH, Y+4         ; Grab address from the stack offset from the stack pointer
    ldd ZL, Y+5

    lpm r16, Z          ; Grab parameter 1

    ldd ZH, Y+6         ; Grab address from the stack offset from the stack pointer
    ldd ZL, Y+7         

    lpm r17, Z          ; Grab parameter 2

    add r16, r17        ; r16 = r16 + r17
    asr r16             ; Shift A right by 1 bit (divide by 2) keeping bit 7
                        ; (for sign extension) 
    ret             ; Return from subroutine
	