textfiles/programming/exam2_65.txt

752 lines
20 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

====================================================================
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>