==================================================================== 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. Note there may be errors in the code, it is not intended that it be cut up and included in students files. It is meant only as an example of addressing modes and instructions. ;============================================================================== ; Coding Examples for the Students of AER201S ;============================================================================== ; ;<=== Note the semicolon is a comment indicator ; .ORG $E000 SEI ; INITIALIZING THE STACK POINTER LDX #$FF TXS ; LDX #$00 ; Initial delay to allow spurious Resets to LDY #$00 ; to subside. At this point accept that this code Delay DEX ; must appear at the beginning of every EPROM BNE Delay ; that will ever be used for the 6502 project board. DEY BNE Delay ; ; We are now ready to try some simple examples ; ; ; 1) Add the numbers $65 and $27 and place the answer in the memory ; location 'ANSWER'. ; ; First we must assign the location to the label 'ANSWER' ; ANSWER = $0000 ; ; OK now we do the addition: LDA #$65 ; Load the number (#) $65 into the accumulator. CLC ; Clear the carry flag to prevent carries from a ; previous and unrelated computation. ADC #$27 ; Add the number (#) $27, the result goes in the ; accumulator STA ANSWER ; Store the result into the memory location ANSWER ; ; Remarks: Note that the # number sign preceded the numbers $65 and $27 to ; indicate that these were in fact CONSTANTS, NUMBERS. If the # sign were ; omitted, TASM would interpret LDA $65 to mean 'load the accumulator from ; the memory location $0065'. ; Looking back at the assignment of ANSWER, we could have said: ; ANSWER = $00. This, when used in the statement STA ANSWER would still ; be interpreted as referring to the memory location $0000 but it would ; allow the 6502 to use something called 'Zero Page' addressing, a faster ; method of accessing the memory locations between $0000-$00FF. ; ; ; page 2 ; 2) Subtract the number $27 from the number $65 and store the result in the ; memory location 'ANS2'. ; ANS2 = $01 ; We will use zero page addressing to refer to ANS2 ; LDA #$65 ; Load the number (#) $65 into the accumulator SEC ; Clear the C flag (used as the borrow flag in ; subtraction) to prevent borrows from a previous ; unrelated computation. SBC #$27 ; Subtract the number (#) $27 from the accumulator ; the result will be in the accumulator. STA ANS2 ; Store the result in the memory location 'ANS2' ; ; Remarks: Note that the carry or borrow flag has a inverse logic in the case ; of subtraction: You have to SEC set the carry flag to prevent a borrow. ; ; ; ; 3) Program a subroutine to turn on specific bits in on VIA 1, Port A which ; can be used to light LEDs to monitor program performance. We will ; assume that there are 8 LEDs connected to Port A. ; ; We must first initialize port A as an output port ; LDA #%11111111 ; All ones means all bits are outputs STA $A003 ; $A003 is the address of VIA1 Port A, data ; direction register. This register determines ; whether a bit is input or output. LDA #%00000000 ; STA $A001 ; $A001 is the address of VIA1 Port A I/O ; register. It is initialized to all zeros ; to mean all bits output 0 volts. ; Before we proceed with writing the subroutine we need to send the program ; to a point somewhere after the subroutine we are about to write. We will ; use a JuMP statement: ; JMP Down_Past ; Down_Past is a program position label we will ; define later. ; ; ; ; ; ============================================================================ ; It is a good idea to put these bars in to make subroutines obvious ; ============================================================================ ; ; Ok know we need to have some Specifications for this subroutine: ; ; Subroutine Name: Show ; Input Registers: .A contains a '1' in the bit position that you want to ; have turned on ; Output Registers: None ; Show ORA $A001 ; 'Show' against the margin indicates a program ; position label. ORA $A001 takes the bit pattern ; in .A and logically OR's it with the pattern of ; bits in memory location $A001, the VIA 1, Port A ; I/O register. ; page 3 ; Say $A001 contains the bits: %abcdefgh (a through h are unknown 0 or 1) ; and we or it with .A : OR %00001000 ; ------------- ; We will get: %abcd1fgh ; ; Because: 0 or 0 = 0, 1 or 0 = 1, 0 or 1 = 1, 1 or 1 = 1 ; the following is true: u or 0 = u and u or 1 = 1 ; where u is an unknown level. ; STA $A001 ; Store the new bit levels back into the I/O Port RTS ; Return from Subroutine ; ; Remarks: This subroutine can be called by setting specific bits in the .A ; register and calling the subroutine: ; LDA #%00000001 ; Set bit 0 ; JSR Show ; Show this on the VIA port ; ; Subroutines can be nested IE one subroutine can call others. Care ; should be exercised when one subroutine calls itself because there are no ; 'local' variables in assembly language (unless you simulate them) since ; the memory in the 6502 is global to all programs or subroutines. ; Subroutines can significantly compact a program and can lend to readability ; of the code if properly documented. ; ; ; Down_Past ; This is the program position label that marks where the ; JMP Down_Past goes to. ; ; ; 4) Now that we have done an output subroutine, lets do some comparisons and ; light leds to show the results. Check if ANSWER - ANS2 = 2*#$27. ; RHS = $03 ; Stores the value of the right hand side of the equation ; LDA ANSWER ; Calculate the RHS SEC SBC ANS2 STA RHS ; LDA #$27 ; To calculate 2*#$27 you use #$27+#$27 CLC ADC #$27 ; Got the LHS in the accumulator ; CMP RHS BNE Not_equal ; Don't Show any LED's ; ; The equation is true, light LED connected to bit 0 LDA #%00000001 JSR Show ; Not_Equal ; ; ; page 4 ; 5) See if ANSWER and ANS2 have any bits in common; light LED 1 if they do. ; LDA ANSWER AND ANS2 ; AND Tests to see if a bit in both arguments is ; set. If it is the resulting bit is set, otherwise ; the resulting bit is cleared. ; If two arguments have no bits in common the result ; will have no bits set or will be zero. In this case ; the AND instruction will set the zero flag. BEQ No_Bits ; The BEQ branches on result equal for comparisons ; or result zero for arithmetic and logical ; OpCodes. LDA #%00000010 JSR Show ; This turns on bit 1 if there were any bits in common ; ; There were no bits in common, the AND resulted in a Z=1, zero No_Bits ; ; ; ; 6) See if ANSWER and ANS2 have bit #1 in common; light LED 2 if they do. ; LDA ANSWER AND #%00000010 ; This picks off the value of bit 1. You can think ; of a 1 in a constant of an AND statement like a ; delta function that zeros picks off one value ; and zeros the rest of the domain. As a result ; ANDing with #%11111111 does not change a number. AND ANS2 ; We know that the .A has all zeros except possibly ; bit 1. ANDing with ANS2 will result in zero ; unless bit 1 was set in both ANSWER and ANS2 BEQ Bit1_Not_Set ; If the result is Z=1, don't show LEDs LDA #%00000100 ; otherwise Show LED 2 JSR Show ; Bit1_Not_Set ; ; ; ; 7) Do an endless loop to alternate the pattern of indicators now present ; on the LEDs with the binary representation of ANSWER. ; Endless LDX $A001 ; Grab the present bit pattern LDA ANSWER ; Grab the new bit pattern STA $A001 ; Put the new pattern on the Port STX ANSWER ; Put the old pattern into ANSWER ; LDX #$00 LDY #$00 D1 DEX ; A double indexed wait loop to waste time BNE D1 DEY BNE D1 JMP Endless ; Next time the old bit pattern becomes the new ; by the way it was stored, rotating through ; the ANSWER==>.A==>Port==>.X==>ANSWER loop. ; page 5 ; The last entry in every program must set the reset vector to point ; to the beginning of the program. If there is an interrupt routine ; then the interrupt vector must be set as well. In this case there is ; only a main program. ; .ORG $FFFC ; Set pointer to Reset Vector Location .WORD $E000 ; Store $E000 as the reset vector .END