      ====================================================================
	DR  6502    AER 201S Engineering Design 6502 Execution Simulator
      ====================================================================

      Supplementary Notes                                   By: M.J.Malone


			  6502 Assembly Code Examples
			  ===========================

	   The remainder of this file will be in a  format  acceptable  to
      TASM for direct assembly.  The following are the basic routines used
      in a stack based mathematics system very similar to that used in the
      FORTH  or  PostScript languages.  It is a good example of addressing
      modes and use and reuse of the most common  6502  instructions.   It
      introduces  the user to the assembly language level maintenance of a
      stack, movement of data and use of the zero page.  Note there may be
      errors in the code, it is  not  intended  that  it  be  cut  up  and
      included  in  students  files.  It is intended only as an example of
      addressing modes and instructions.

;==============================================================================
;                 Coding Examples for the Students of AER201S
;==============================================================================
;
;
.ORG $E000
	   SEI             ; INITIALIZING THE STACK POINTER
	   LDX #$FF
	   TXS
;
	   LDX #$00        ; Initial
	   LDY #$00
Delay      DEX
	   BNE Delay
	   DEY
	   BNE Delay
;
;
; =================================
; Definitions and memory allocation
; =================================
;
Start_Page  = $10          ; Stack goes from $1000-$1FFF or pages $10-$20
End_Page    = $20
;
Stack_Ptr   = $FE          ; Address of the pointer to the next free byte in
			   ; the stack
Memory_Ptr  = $FC          ; Address of a pointer to a piece of data in
			   ; memory
MTemp       = $FB          ; Temporary Variable used in memory routines
MTemp1      = $FA          ; Temporary Variable used in memory routines
;
Reg_Len     = $08               ; Use 8 byte utility registers
;
Utl_Reg0    = $00               ; Utility Register 0    Used for Math and stack
Utl_Reg1    = Utl_Reg0+Reg_len  ; Utility Register 1    manipulations
Utl_reg2    = Utl_Reg1+Reg_Len  ; Utility Register 2
;
;
;
 
 
 
 
 
 
                                                            page 2 
 
	   LDA #Start_Page  ; Initialize the stack pointer to point to the
	   STA Stack_Ptr+1  ; first byte of the space allotted to be stack
	   LDA #$00         ; space
	   STA Stack_Ptr
;
	   JMP Main         ; Jump to the main program, what follows are
			    ; subroutines
;
;
;
;
; ==============
; Halt execution
; ==============
;
Halt          JMP Halt     ; In case of an error, the program jumps here
;
;
;
;
;
;
;                   =====================================
;                       Stack Maintenance Subroutines
;                   =====================================
;
;
;
; ======================================================================
; Will a (.A) byte long number pushed into the stack overflow the stack?
; ======================================================================
;
;  Call Name: Overrun
;
;  Input Variables: .A Holds the number of bytes you want to push onto the
;                      stack
;
;  Output Variables:  None.  The Routine stops execution when an overflow
;                     occurs.  Ideally it would call an error trap routine
;                     and give some output.
;
Overrun       CLC
	      ADC Stack_Ptr     ; Add the number of bytes to the current
	      BCS Try_Page      ; stack pointer low byte - if less than a page
	      RTS               ; then it could not have overrun.
Try_Page      LDA #$01          ; It overrun a page, check to see if the next
	      ADC Stack_Ptr+1   ; page is part of the stack area.
	      CMP #End_Page
	      BEQ Halt          ; If it has overrun then Halt!
	      RTS               ; otherwise RTS - everything is OK
;
;
;
;
 
 
 
 
 
 
 
 
 
 
                                                            page 3 
 
; =======================================================================
; Will a (.A) byte long number pulled from the stack underflow the stack?
; =======================================================================
;
;  Call Name:  Underrun
;
;  Input Variables: .A Holds the number of bytes you want to pull from the
;                      stack
;
;  Output Variables:  None.  The Routine stops execution when an underflow
;                     occurs.  Ideally it would call an error trap routine
;                     and give some output.
;
Underrun      STA MTemp
	      LDA Stack_Ptr     ; Subtract the number of bytes from the stack
	      SEC               ; pointer.
	      SBC MTemp
	      BCC Try_Page      ; If it has not underrun an page, then
	      RTS               ; RTS - everything is OK
Try_Page      LDA Stack_Ptr+1   ; It has underrun a page - check to see if
	      SBC #$00          ; the previous page is part of the stack.
	      CMP #Start_Page
	      BMI Halt          ; If not then Halt - there was an underrun
; The BMI instruction assumes the stack will never be allowed 32K.  It assumes
; the 'N' flag will never be set from comparing two numbers more different
; then $80 resulting from a stack of $8000 length or more - 32K
	      RTS
;
;
;
;
; ==========================================================
; Copy .Y bytes of data from the memory pointer to the stack
; ==========================================================
;
; Call Name: Mem_to_Stk
;
; Input Variables:  .Y  is the number of bytes of memory to move to the stack
;                   Memory_Ptr points to the first address of the piece of data
;
; Output Variables: None.
;
;
Mem_to_Stk    TYA
	      JSR Overrun           ; Check for a Stack Overrun
	      STY MTemp             ; Store #bytes temporarily
	      LDY #$00
F_Ag          LDA (Memory_Ptr),y    ; Move data from Memory to
	      STA (Stack_Ptr),y     ; stack
	      INY
	      CPY MTemp
	      BNE F_Ag              ; until .Y=#bytes
;
	      LDA MTemp             ; Add the number of bytes to the stack
	      CLC                   ; pointer so that it points to the next
	      ADC Stack_Ptr         ; free byte of stack space
 
 
 
 
 
 
 
 
                                                            page 4 
 
	      STA Stack_Ptr
	      LDA #$00
	      ADC Stack_Ptr+1
	      STA Stack_Ptr+1
	      RTS
;
;
;
;
; ==========================================================
; Copy .Y bytes of data from the stack to the memory pointer
; ==========================================================
;
; Call Name: Stk_To_Mem
;
; Input Variables:  .Y  is the number of bytes of stack data to move to memory
;                   Memory_Ptr points to the first address of the piece of data
;
; Output Variables: None.
;
Stk_To_Mem    TYA
	      JSR Underrun          ; Check for a Stack Underrun
	      STY MTemp             ; Store #bytes temporarily
	      LDA Stack_Ptr         ; Subtract to find first address of
	      SEC                   ; a .Y byte length piece of data in the
	      SBC MTemp             ; stack.  Nothing prevents the user from
	      STA Stack_Ptr         ; pulling a different size data piece
	      LDA Stack_Ptr+1       ; from the stack than was pushed in.  In
	      SBC #$00              ; fact that makes the stack useful in
	      STA Stack_Ptr+1       ; doing string manipulations.
;
	      LDY #$00
T_Ag          LDA (Stack_Ptr),y     ; Move data from the stack
	      STA (Memory_Ptr),y    ; to memory
	      INY
	      CPY MTemp
	      BNE T_Ag              ; until .Y=#bytes
;
	      RTS
;
;
;
;
; ================================================================
; Copy .Y bytes of data from the memory pointer to the Utl_Reg(.X)
; ================================================================
;
; Call Name: Mem_to_Reg
;
; Input Variables: - .Y  is the number of bytes of memory to move
;                   to Utl_Reg(.X) from a location pointed to by
;                   Memory_Ptr
;                  - .X  is the number of the Utility register
;                  - Memory_Ptr points to the first address of the piece of
;                   data
;
 
 
 
 
 
 
 
 
                                                            page 5 
 
; Output Variables: None.
;
Mem_to_Reg    CPX #$03              ; .X must be less than 3
	      BPL JHalt
	      CPY #Reg_Len+1        ; .Y must be less than (Reg_Len+1)
	      BPL JHalt
	      JMP MR_Cont
JHalt         JMP Halt
MR_Cont       TXA
	      STY MTemp             ; Store #bytes temporarily
;
; The following assumes Reg_Len=8 and must be adjusted otherwise
;
	      CLC
	      ASL A                 ; Multiply .X by 8 to get the
	      ASL A                 ; first address of the Utl_Reg(.X)
	      ASL A
;
	      STA MTemp1            ; Store the beginning address
	      ADC MTemp             ; Add the length of Number
	      STA MTemp             ; Store the ending of move address
;
	      LDX MTemp1            ; Load address of beginning of data
	      TXA                   ; on zero page (by .X index offset)
	      CLC
	      ADC #Reg_Len          ; Add on the length of the register to
	      STA MTemp1            ; find the end of the register
;
	      LDY #$00
MR_Ag         LDA (Memory_Ptr),Y    ; Move Data from Memory_Ptr
	      STA Utl_Reg0,X        ;   to the Utl_Reg
	      INY
	      INX
	      CPX MTemp             ; Until .X=end of move address
	      BNE MR_Ag
;
	      LDA #$00
MR_Zero       CPX MTemp1            ; While the entire Utl_Reg is not
	      BEQ MR_Done           ; yet full (not reached end of register),
	      STA Utl_Reg0,X        ; Put #$00's in the rest of the locations
	      INX
	      JMP MR_Zero
;
MR_Done       RTS
;
;
;
;
; ============================================================
; Copy .Y bytes of data from Utl_Reg(.X) to the memory pointer
; ============================================================
;
; Call Name: Reg_to_Mem
;
 
 
 
 
 
 
 
 
 
 
                                                            page 6 
 
; Input Variables: - .Y  is the number of bytes of register data to move
;                   to memory
;                  - .X  is the register number
;                  - Memory_Ptr points to the first address of the piece of data
;
; Output Variables: None.
;
Reg_to_Mem    CPX #$03              ; .X must be less than 3
	      BPL JHalt
	      CPY #Reg_Len+1        ; .Y must be less than Reg_Len+1
	      BPL JHalt
	      JMP RM_Cont
JHalt         JMP Halt
RM_Cont       TXA
	      STY MTemp             ; Store #bytes temporarily
;
; The following assumes Reg_Len=8 and must be adjusted otherwise
;
	      CLC
	      ASL A                 ; Multiply .X by 8 to get the
	      ASL A                 ; first address of the Utl_Reg(.X)
	      ASL A
;
	      STA MTemp1            ; Store the beginning address
	      ADC MTemp             ; Add the length of Number
	      STA MTemp             ; Store the ending address
;
	      LDX MTemp1            ; Load address of beginning of data
	      LDY #$00
RM_Ag         LDA Utl_Reg0,X        ; Move data from Utl_Reg
	      STA (Memory_Ptr),Y    ;  to the Memory_Ptr
	      INY
	      INX
	      CPX MTemp             ; Until .X=end address
	      BNE RM_Ag
 
	      RTS
;
;
;
;
; ===============================================================
; Copy .Y bytes of data from the stack pointer to the Utl_Reg(.X)
; ===============================================================
;
; Call Name: Stk_to_Reg
;
; Input Variables: - .Y  is the number of bytes of memory to move
;                   to Utl_Reg(.X) from a location pointed to by
;                   Memory_Ptr
;                  - .X  is the number of the Utility register
;                  - Memory_Ptr points to the first address of the piece of
;                   data
;
; Output Variables: None.
;
 
 
 
 
 
 
 
 
                                                            page 7 
 
Stk_to_Reg    CPX #$03              ; .X must be less than 3
	      BPL JHalt
	      CPY #Reg_Len+1        ; .Y must be less than Reg_Len+1
	      BPL JHalt
	      JMP SR_Cont
SRHalt        JMP Halt
;
SR_Cont       TYA
	      JSR Underrun          ; Check for a Stack Underrun
	      STY MTemp             ; Store #bytes temporarily
	      LDA Stack_Ptr         ; Subtract to find first address of
	      SEC                   ; a .Y length data element in the stack
	      SBC MTemp
	      STA Stack_Ptr
	      LDA Stack_Ptr+1
	      SBC #$00
	      STA Stack_Ptr+1
;
	      TXA
;
; The following assumes Reg_Len=8 and must be adjusted otherwise
;
	      CLC
	      ASL A                 ; Multiply .X by 8 to get the
	      ASL A                 ; first address of the Utl_Reg(.X)
	      ASL A
;
	      STA MTemp1            ; Store the beginning address
	      ADC MTemp             ; Add the length of Number
	      STA MTemp             ; Store the ending of move address
;
	      LDX MTemp1            ; Load address of beginning of data
	      TXA
	      CLC
	      ADC #Reg_Len          ; Add on the length of the register
	      STA MTemp1            ; to find the last address and store it
;
	      LDY #$00
SR_Ag         LDA (Stack_Ptr),Y     ; Move Data from Memory_Ptr
	      STA Utl_Reg0,X        ;   to the Utl_Reg
	      INY
	      INX
	      CPX MTemp             ; until .X=end of move address
	      BNE MR_Ag
;
	      LDA #$00
SR_Zero       CPX MTemp1            ; While the entire 8 byte Utl_Reg is not
	      BEQ SR_Done           ; yet full (not at last address),
	      STA Utl_Reg0,X        ; Put Zero's in the higher order locations
	      INX
	      JMP SR_Zero
;
SR_Done
	      RTS
;
;
;
;
 
 
 
 
 
 
                                                            page 8 
 
; ===========================================================
; Copy .Y bytes of data from Utl_Reg(.X) to the stack pointer
; ===========================================================
;
; Call Name: Reg_to_Stk
;
; Input Variables: - .Y  is the number of bytes of register data to move
;                   to memory
;                  - .X  is the register number
;                  - Memory_Ptr points to the first address of the piece of data
;
; Output Variables: None.
;
Reg_to_Stk    CPX #$03              ; .X must be less than 3
	      BPL JHalt
	      CPY #Reg_Len+1        ; .Y must be less than Reg_Len+1
	      BPL JHalt
	      JMP RM_Cont
JHalt         JMP Halt
RM_Cont       TXA
	      STY MTemp             ; Store #bytes temporarily
;
; The following assumes Reg_Len=8 and must be adjusted otherwise
;
	      CLC
	      ASL A                 ; Multiply .X by 8 to get the
	      ASL A                 ; first address of the Utl_Reg(.X)
	      ASL A
;
	      TAX                   ; Store the beginning address
	      ADC MTemp             ; Add the length of move
	      STA MTemp1            ; Store the end of move address
;
	      LDY #$00
RM_Ag         LDA Utl_Reg0,X        ; Move data from Utl_Reg
	      STA (Memory_Ptr),Y    ;  to the Memory_Ptr
	      INY
	      INX
	      CPX MTemp1            ; Until .X=end of move address
	      BNE RM_Ag
 ;
	      LDA MTemp             ; Take the number of bytes moved and add
	      CLC                   ; it to the old stack pointer to make it
	      ADC Stack_Ptr         ; point at the next free byte of stack
	      STA Stack_Ptr         ; space
	      LDA #$00
	      ADC Stack_Ptr+1
	      STA Stack_Ptr+1
 
	      RTS
;
;
;
;
 
 
 
 
 
 
 
 
 
 
                                                            page 9 
 
;                      ===============================
;                          Mathematics Subroutines
;                      ===============================
;
;  We will assume that all one byte manipulations can be handled in the
;  user software or in user subroutines and any address calculations IE
;  2 byte math can be done most quickly by specialized user routines.
;  Here then are a basic set of single precision and 4 byte integer math
;  subroutines.
;
;  Storage format:
;
; Offset of byte:  +3       +2       +1        0
;
;    Integer:   SIIIIIII IIIIIIII IIIIIIII IIIIIIII      S-Sign bit
;                                                        I-Integer bits
;
;    Single:    EEEEEEEE SMMMMMMM MMMMMMMM MMMMMMMM      E-Exponent bits
;                        /                               S-Mantissa Sign
;                     Decimal Point                      M-Mantissa Bits
;
;    In single precision storage, the exponent is offset by $80 and the
;    mantissa is assumed to be normalize so that the mantissa begins with
;    %1.MMMMMMM... .  The '1' is omitted and the decimal point is assumed
;    leading to one more bit of significance.  IEEE single precision
;    format has the sign bit precede the 8 exponent bits however this leads
;    to the exponent bits not being aligned on an even byte.  Since this
;    would slow manipulations of the numbers on an 8 bit computer,
;    requiring the exponent to be reassembled each time, it is not used
;    here.
;
;
Sign1    = $F9       ; Variables that keep track of the sign bits of the
Sign2    = $F8       ; two arguments and the answer
Ans_Sign = $F7
;
;
Exp1     = $F6       ; Variables to hold the exponent bytes of the arguments
Exp2     = $F5       ; and either the common exponent (used in add and
Com_Exp  = $F4       ; subtract) or the answer's exponent.
;
;
; ======================================
;   Move Utl_Reg2 to Utl_Reg0 (4 byte)
; ======================================
;
; Call name: Two_to_0
;
; No Input or Output variables
;
Two_to_0
	      LDA Utl_Reg2
	      STA Utl_Reg0
	      LDA Utl_Reg2+1
	      STA Utl_Reg0+1
	      LDA Utl_Reg2+2
 
 
 
 
 
 
 
 
                                                            page 10 
 
	      STA Utl_Reg0+2
	      LDA Utl_Reg2+3
	      STA Utl_Reg0+3
	      RTS
;
;
;
;
; ======================================
;   Move Utl_Reg2 to Utl_Reg1 (4 byte)
; ======================================
;
; Call name: Two_to_1
;
; No Input or Output variables
;
Two_to_1
	      LDA Utl_Reg2
	      STA Utl_Reg1
	      LDA Utl_Reg2+1
	      STA Utl_Reg1+1
	      LDA Utl_Reg2+2
	      STA Utl_Reg1+2
	      LDA Utl_Reg2+3
	      STA Utl_Reg1+3
	      RTS
;
;
;
;
; =============================
;   Internal Addition Routine
; =============================
;
;  Simple add of Utl_Reg2=Utl_Reg0 + Utl_Reg1 with no sign considerations
;
In_Add
	      CLC
	      LDA Utl_Reg0
	      ADC Utl_Reg1
	      STA Utl_Reg2
	      LDA Utl_Reg0+1
	      ADC Utl_Reg1+1
	      STA Utl_Reg2+1
	      LDA Utl_Reg0+2
	      ADC Utl_Reg1+2
	      STA Utl_Reg2+2
	      LDA Utl_Reg0+3
	      ADC Utl_Reg1+3
	      STA Utl_Reg2+3
	      RTS
;
;
;
;
 
 
 
 
 
 
 
 
 
                                                            page 11 
 
; ================================
;   Internal Subtraction Routine
; ================================
;
;  Simple subtract of Utl_Reg2=Utl_Reg0 - Utl_Reg1 with no sign considerations
;
In_Subt
	      SEC
	      LDA Utl_Reg0
	      SBC Utl_Reg1
	      STA Utl_Reg2
	      LDA Utl_Reg0+1
	      SBC Utl_Reg1+1
	      STA Utl_Reg2+1
	      LDA Utl_Reg0+2
	      SBC Utl_Reg1+2
	      STA Utl_Reg2+2
	      LDA Utl_Reg0+3
	      SBC Utl_Reg1+3
	      STA Utl_Reg2+3
	      RTS
;
;
;
;
; ========================================
;   Internal Reverse Subtraction Routine
; ========================================
;
;  Simple subtract of Utl_Reg2=Utl_Reg1 - Utl_Reg0 with no sign considerations
;
In_R_Subt
	      SEC
	      LDA Utl_Reg1
	      SBC Utl_Reg0
	      STA Utl_Reg2
	      LDA Utl_Reg1+1
	      SBC Utl_Reg0+1
	      STA Utl_Reg2+1
	      LDA Utl_Reg1+2
	      SBC Utl_Reg0+2
	      STA Utl_Reg2+2
	      LDA Utl_Reg1+3
	      SBC Utl_Reg0+3
	      STA Utl_Reg2+3
	      RTS
;
;
;
;
; ======================
;   Integer 4 byte Add
; ======================
;
; Call Name: IADD4
;
 
 
 
 
 
 
 
 
                                                            page 12 
 
; Input Variables:   The two numbers to be added are assumed to be in Utl_Reg0
;                    and Utl_Reg1
;
; Output Variables:  The answer appears in Utl_Reg2.
;
;
------------------------------------------------------------------------------
				    .
				    .
				    .
		 The remainder of the file has been omitted.
				    .
				    .
				    .
-------------------------------------------------------------------------------
;
;
;
.ORG $FFFC
.WORD $E000
.END
<eof>
