/*
 * ParamPassing2a.asm
 *   Modified: 6 Feb 2024
 *   Authors:  Dr. Schwartz, Josh Weaver
 *   Purpose: Demonstrate the use of parameters in program memory space
 */ 
.include "ATxmega128A1Udef.inc"
;******************************INITIALIZATIONS***************************************
.equ	stack_init = 0x3FFF ; Initialize stack pointer (between 0x2000 & 0x3FFF)	
                            ; Default is 0x3FFF
.org 0x0000
	jmp MAIN
;*******************************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
		
    rcall AVG                   ; Call subroutine AVG to get the average
DATA: .DB 0x37, 0xA3            ; Define the data in bytes
	
HERE:	
    rjmp HERE
;********************************SUBROUTINES*****************************************
/************************************************************************************
 * Name:     AVG
 * Purpose:  Get the Average of two data bytes in program memory at the successive 
 *           locations pointed to by the return address on the stack.
 * Inputs:   No direct input			 
 * Outputs:  r16 is the place for the result
 * Affected: r16, r17, r18, X, Z
 ***********************************************************************************/
AVG:
    ; 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.
    sts CPU_RAMPX, r18 ; This value is ignored, but in some situations may be needed
                    ; It is moved to RAMPX to handle the third byte of X.
    pop XH          ; Grab High byte of return address from stack
    pop XL          ; Grab Low byte of return addres from stack

    movw Z, X		; Move the address to the Z register to protect their values 
					; during modifications

    lsl ZH          ; Since program memory is offset by a bit, we must left shift
    lsl ZL          ; the Z register by 1.  We must also allow for a carry from the
    ldi r16, 0x00   ; result of the left shift for the low byte of Z.  To handle
    adc ZH, r16     ; this we load r16 with a zero value, then add ZH with r16 and
                    ; the current carry value.  Note that order matters.
					; (Note: could have done the same for ZH and RAMPX)
   
    lpm r16, Z+     ; Load r16 with first point in program memory and increment Z
    lpm r17, Z      ; Load r17 with the second point in program memory
    add r16, r17    ; r16 = r16 + r17
    asr r16         ; Shift A right by 1 bit (divide by 2) keeping bit 7
                    ; (for sign extension) 

    ld r17, X+      ; Increment address location to skip location of parameter pointer.
                    ; Using r17 as a garbage register to force an increment.

    push XL         ; Place the original return address back on the stack
    push XH
    lds r18, CPU_RAMPX
    push r18
    ret             ; Return from subroutine
	