6502 Instruction Set
Here are the 56 mnemonics, the 56 instructions you can give the 6502 (or 6510) chip. Each of them is described in several ways: what it does, what major uses it has in ML programming, what addressing modes it can use, what flags it affects, its opcode (hex/decimal), and the number of bytes it uses up.
ADC
What it does: Adds byte in memory to the byte in the Accumulator, plus the carry flag if set. Sets the carry flag if result exceeds 255. The result is left in the Accumulator.
Major uses: Adds two numbers together. If the carry flag is set prior to an ADC, the resulting number will be one greater than the total of the two numbers being added (the carry is added to the result). Thus, one always clears the carry (CLC) before beginning any addition operation. Following an ADC, a set (up) carry flag indicates that the result exceeded one byte's capacity (was greater than 255), so you can chainadd bytes by subsequent ADCs without any further CLCs (see "Multi-Byte Addition" in Appendix D).
Other flags affected by addition include the V (overflow) flag. This flag is rarely of any interest to the programmer. It merely indicates that a result became larger than could be held within bits 0-6. In other words, the result "overflowed" into bit 7, the highest bit in a byte. Of greater importance is the fact that the Z is set if the result of an addition is zero. Also the N flag is set if bit 7 is set. This N flag is called the "negative" flag because you can manipulate bytes thinking of the seventh bit as a sign (+ or -) to accomplish "signed arithmetic" if you want to. In this mode, each byte can hold a maximum value of 127 (since the seventh bit is used to reveal the number's sign). The B branching instruction's Relative addressing mode uses this kind of arithmetic.
ADC can be used following an SED which puts the 6502 into "decimal mode." Here's an example. Note that the number 75 is decimal after you SED:
SED |
|
CLC |
|
LDA #75 |
|
ADC #$05 |
(this will result in 80) |
CLD |
(always get rid of decimal mode as soon as you've
finished) |
Attractive as it sounds, the decimal mode isn't of much real value to the programmer. LADS will let you work in decimal if you want to without requiring that you enter the 6502's mode. Just leave off the $ and LADS will handle the decimal numbers for you.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,X Absolute Absolute,X Absolute,Y Indirect,X Indirect,Y |
ADC #15 ADC 15 ADC 15,X ADC 1500 ADC 1500,X ADC 1500,Y ADC (15,X) ADC (15),Y |
$69/105 $65/101 $75/117 $6D/109 $7D/125 $79/121 $61/97 $71/113 |
2 2 2 3 3 3 2 2 |
Affected flags: N Z C V
AND
What it does: Logical ANDS the byte in memory with the byte in the Accumulator. The result is left in the Accumulator. All bits in both bytes are compared, and if both bits are 1, the result is 1. If either or both bits are 0, the result is 0.
Major uses: Most of the time, AND is used to turn bits off. Let's say that you are pulling in numbers higher than 128 (10000000 and higher) and you want to "unshift" them and print them as lowercase letters. You can then put a zero into the seventh bit of your "mask" and then AND the mask with the number being unshifted:
LDA ? |
(test number) |
AND #$7F |
(01111111) |
(If either bit is 0, the result will be 0. So the seventh bit of the test number is turned off here and all the other bits in the test number are unaffected.)
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,X Absolute Absolute,X Absolute,Y Indirect,X Indirect,Y |
AND #15 AND 15 AND 15,X AND 1500 AND 1500,X AND 1500,Y AND (15,X) AND (15),Y |
$29/41 $25/37 $35/53 $2D/45 $3D/61 $39/57 $21/33 $31/49 |
2 2 2 3 3 3 2 2 |
Affected flags: N Z
ASL
What it does: Shifts the bits in a byte to the left by 1. This byte can be in the Accumulator or in memory, depending on the addressing mode. The shift moves the seventh bit into the carry flag and shoves a 0 into the zeroth bit.
Major uses: Allows you to multiply a number by
2. Numbers bigger than 255 can be manipulated using ASL with ROL (see "Multiplication"
in Appendix D).
A secondary use is to move the lower four bits in a
byte (a four-bit unit is often called a nybble) into the higher four bits.
The lower bits are replaced by zeros, since ASL stuffs zeros into the zeroth
bit of a byte. You move the lower to the higher nybble of a byte by: ASL ASL
ASL ASL.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Accumulator Zero Page Zero Page,X Absolute Absolute,X |
ASL ASL 15 ASL 15,X ASL 1500 ASL 1500,X |
$0A/10 $06/6 $16/22 $0E/14 $1E/30 |
1 2 2 3 3 |
Affected flags: N Z C
BCC
What it does: Branches up to 127 bytes forward or 128 bytes backward from its own address if the carry flag is clear. In effect, it branches if the second item is lower than the first, as in: LDA #150: CMP #149 or LDA #22: SBC #15. These actions would clear the carry and, triggering BCC, a branch would take place.
Major uses: For testing the results of CMP or ADC or other operations which affect the carry flag. IF-THEN or ONGOTO type structures in ML can involve the BCC test. It is similar to BASIC's > instruction.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Relative |
BCC addr. |
$90/144 |
2 |
Affected flags: none of them.
BCS
What it does: Branches up to 127 bytes forward or 128 bytes backward from its own address if the carry flag is set. In effect, it branches if the second item is higher than the first, as in: LDA #150: CMP #249 or LDA #22: SBC #85. These actions would set the carry and, triggering BCS, a branch would take place.
Major uses: For testing the results of LDA or ADC or other operations which affect the carry flag. IF-THEN or ON-GOTO type structures in ML can involve the BCC test. It is similar to BASIC's < instruction.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Relative |
BCS addr. |
$130/176 |
2 |
Affected flags: none of them.
BEQ
What it does: Branches up to 127 bytes forward or 128 bytes backward from its own address if the zero flag (Z) is set. In other words, it branches if an action on two bytes results in a 0, as in: LDA #150: CMP #150 or LDA #22: SBC #22. These actions would set the zero flag, so the branch would take place.
Major uses: For testing the results of LDA or ADC or other operations which affect the carry flag. IF-THEN or ONGOTO type structures in ML can involve the BEQ test. It is similar to BASIC's = instruction.
Addressine Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Relative |
BEQ addr. |
$F0/240 |
2 |
Affected flags: none of them.
BIT
What it does: Tests the bits in the byte in memory against the bits in the byte held in the Accumulator. The bytes (memory and Accumulator) are unaffected. BIT merely sets flags. The Z flag is set as if an Accumulator AND memory had been performed. The V flag and the N flag receive copies of the sixth and seventh bits of the tested number.
Major uses: Although BIT has the advantage of not having any effect on the tested numbers, it is infrequently used because you cannot employ the Immediate addressing mode with it. Other tests (CMP and AND, for example) can be used instead.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Zero Page Absolute |
BIT 15 BIT 1500 |
$24/36 $2C/44 |
2 3 |
Affected flags: N Z V
BMI
What it does: Branches up to 127 bytes forward or 128 bytes backward from its own address if the negative (N) flag is set. In effect, it branches if the seventh bit has been set by the most recent event: LDA #150 or LDA #128 would set the seventh bit. These actions would set the N flag, signifying that a minus number is present if you are using signed arithmetic or that there is a shifted character (or a BASIC keyword) if you are thinking of a byte in terms of the ASCII code.
Major uses: Testing for BASIC keywords, shifted ASCII, or graphics symbols. Testing for + or - in signed arithmetic.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Relative |
BMI addr. |
$30/48 |
2 |
Affected flags: none of them.
BNE
What it does: Branches up to 127 bytes forward or 128 bytes backward from its own address if the zero flag is clear. In other words, it branches if the result of the most recent event is not zero, as in: LDA #150: SBC #120 or LDA #128: CMP #125. These actions would clear the Z flag, signifying that a result was not 0.
Major uses: The reverse of BEQ. BNE means Branch if Not Equal. Since a CMP subtracts one number from another to perform its comparison, a 0 result means that they are equal. Any other result will trigger a BNE (not equal). Like the other B branch instructions, it has uses in IF-THEN, ONGOTO type structures and is used as a way to exit loops (for example, BNE will branch back to the start of a loop until a 0 delimiter is encountered at the end of a text message). BNE is like BASIC's <> instruction.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Relative |
BNE addr. |
$D0/208 |
2 |
Affected flags: none of them.
BPL
What it does: Branches up to 127 bytes forward or 128 bytes backward from its own address if the N flag is clear. In effect, it branches if the seventh bit is clear in the most recent event, as in: LDA #12 or LDA #127. These actions would clear the N flag, signifying that a plus number (or zero) is present in signed arithmetic mode.
Major uses: For testing the results of LDA or ADC or other operations which affect the negative (N) flag. IF-THEN or ON-GOTO type structures in ML can involve the BCC test. It is the opposite of the BMI instruction. BPL can be used for tests of "unshifted" ASCII characters and other bytes which have the seventh bit off and so are lower than 128 (0XXXXXXX).
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Relative |
BPL addr. |
$10/16 |
2 |
Affected flags: none of them.
BRK
What it does: Causes a forced interrupt. This interrupt cannot be masked (prevented) by setting the I (interrupt) flag within the Status Register. If there is a Break Interrupt Vector (a vector is like a pointer) in the computer, it may point to a resident monitor if the computer has one. The PC and the Status Register are saved on the stack. The PC points to the location of the BRK + 2.
Major uses: Debugging an ML program can often start with a sprinkling of BRKs into suspicious locations within the code. The ML is executed, a BRK stops execution and drops you into the monitor, you examine registers or tables or variables to see if they are as they should be at this point in the execution, and then you restart execution from the breakpoint. This instruction is essentially identical to the actions and uses of the STOP command in BASIC.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
BRK |
$00/0 |
1 |
Affected flags: Break (B) flag is set.
BVC
What it does: Branches up to 127 bytes forward or 128 bytes backward from its own address if the V (overflow) flag is clear.
Major uses: None. In practice, few programmers use "signed" arithmetic where the seventh bit is devoted to indicating a positive or negative number (a set seventh bit means a negative number). The V flag has the job of notifying you when you've added, say 120 + 30, and have therefore set the seventh bit via an "overflow" (a result greater than 127). The result of your addition of two positive numbers should not be seen as a negative number, but the seventh bit is set. The V flag can be tested and will then reveal that your answer is still positive, but an overflow took place.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Relative |
BVC addr. |
$50/80 |
2 |
Affected flags: none of them.
BVS
What it does: Branches up to 127 bytes forward or 128 bytes backward from its own address if the V (overflow) flag is set).
Major uses: None. See BVC above.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Relative |
BVS addr. |
$70/112 |
2 |
Affected flags: none of them.
CLC
What it does: Clears the carry flag. (Puts a 0 into it.)
Major uses: Always used before any addition (ADC). If there are to be a series of additions (multiple-byte addition), only the first ADC is preceded by CLC since the carry feature is necessary. There might be a carry, and the result will be incorrect if it is not taken into account.
The 6502 does not offer an addition instruction without the carry feature. Thus, you must always clear it before the first ADC so a carry won't be accidentally added.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
CLC |
$18/24 |
1 |
Affected flags: Carry (C) flag is set to zero.
CLD
What it does: Clears the decimal mode flag. (Puts a 0 into it.)
Major uses: Commodore computers execute a CLD when first turned on as well as upon entry to monitor modes (PET/CBM models) and when the SYS command occurs. Apple and Atari, however, can arrive in an ML environment with the D flag in an indeterminant state. An attempt to execute ML with this flag set would cause disaster-all mathematics would be performed in "decimal mode." It is therefore suggested that owners of Apple and Atari computers CLD during the early phase, the initialization phase, of their programs. Though this is an unlikely bug, it would be a difficult one to recognize should it occur.
For further detail about the 6502's decimal mode, see SED below.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
CLD |
$D8/216 |
1 |
Affected flags: Decimal (D) flag is set to zero.
CLI
What it does: Clears the interrupt-disable flag. All interrupts will therefore be serviced (including maskable ones).
Major uses: To restore normal interrupt routine processing following a temporary suspension of interrupts for the purpose of redirecting the interrupt vector. For more detail, see SEI below.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
CLI |
$58/88 |
1 |
Affected flags: Interrupt (I) flag is set to zero.
CLV
What it does: Clears the overflow flag. (Puts a 0 into it.)
Major uses: None. (See BVC above.)
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
CLV |
$B8/184 |
1 |
Affected flags: Overflow (V) flag is set to zero.
CMP
What it does: Compares the byte in memory to the byte in the Accumulator. Three flags are affected, but the bytes in memory and in the Accumulator are undisturbed. A CMP is actually a subtraction of the byte in memory from the byte in the Accumulator. Therefore, if you LDA #15:CMP #15-the result (of the subtraction) will be zero, and BEQ would be triggered since the CMP would have set the Z flag.
Major uses: This is an important instruction in ML. It is central to IF-THEN and ON-GOTO type structures. In combination with the B branching instructions like BEQ, CMP allows the 6502 chip to make decisions, to take alternative pathways depending on comparisons. CMP throws the N, Z, or C flags up or down. Then a B instruction can branch, depending on the condition of a flag.
Often, an action will affect flags by itself, and a CMP will not be necessary. For example, LDA #15 will put a 0 into the N flag (seventh bit not set) and will put a 0 into the Z flag (the result was not 0). LDA does not affect the C flag. In any event, you could LDA #15: BPL TARGET, and the branch would take effect. However, if you LDA $20 and need to know if the byte loaded is precisely $0D, you must CMP #$OD:BEQ TARGET. So, while CMP is sometimes not absolutely necessary, it will never hurt to include it prior to branching.
Another important branch decision is based on > or < situations. In this case, you use BCC and BCS to test the C (carry) flag. And you've got to keep in mind the order of the numbers being compared. The memory byte is compared to the byte sitting in the Accumulator. The structure is: memory is less than or equal to the Accumulator (BCC is triggered because the carry flag was cleared). Or memory is more than Accumulator (BCS is triggered because the carry flag was set). Here's an example. If you want to find out if the number in the Accumulator is less than $40, just CMP #$41:BCC LESSTHAN (be sure to remember that the carry flag is cleared if a number is less than or equal; that's why we test for less than $40 by comparing with a $41):
LDA #75
CMP #$41; IS IT LESS THAN $40?
BCC LESSTHAN
One final comment about the useful BCC/BCS tests following CMP: It's easy to remember that BCC means less than or equal and BCS means more than if you notice that C is less than S in the alphabet.
The other flag affected by CMPs is the N flag. Its uses are limited since it merely reports the status of the seventh bit; BPL triggers if that bit is clear, BMI triggers if it's set. However, that seventh bit does show whether the number is greater than (or equal to) or less than 128, and you can apply this information to the ASCII code or to look for BASIC keywords or to search data bases (BPL and BMI are used by LADS' data base search routines in the Array subprogram). Nevertheless, since LDA and many other instructions affect the N flag, you can often directly BPL or BMI without any need to CMP first.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,X Absolute Absolute,X Absolute,Y Indirect,X Indirect,Y |
CMP #15 CMP 15 CMP 15,X CMP 1500 CMP 1500,X CMP 1500,Y CMP (15,X) CMP (15),Y |
$C9/201 $C5/197 $D5/213 $CD/205 $DD/221 $D9/217 $C1/193 $D1/209 |
2 2 2 3 3 3 2 2 |
Affected flags: N Z C
CPX
What it does: Compares the byte in memory to the byte in the X Register. Three flags are affected, but the bytes in memory and in the X Register are undisturbed. A CPX is actually a subtraction of the byte in memory from the byte in the X Register. Therefore, if you LDA # 15:CPX #15-the result (of the subtraction) will be zero and BEQ would be triggered since the CPX would have set the Z flag.
Major uses: X is generally used as an index, a counter within loops. Though the Y Register is often preferred as an index since it can serve for the very useful Indirect Y addressing mode (LDA (15),Y)-the X Register is nevertheless pressed into service when more than one index is necessary or when Y is busy with other tasks.
In any case, the flags, conditions, and purposes of CPX are quite similar to CMP (the equivalent comparison instruction for the Accumulator). For further information on the various possible comparisons (greater than, equal, less than, not equal), see CMP above.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Absolute |
CPX #15 CPX 15 CPX 1500 |
$E0/224 $E4/228 $EC/236 |
2 2 3 |
Affected flags: N Z C
CPY
What it does: Compares the byte in memory to the byte in the Y Register. Three flags are affected, but the bytes in memory and in the Y Register are undisturbed. A CPX is actually a subtraction of the byte in memory from the byte in the Y Register. Therefore, if you LDA #15: CPY #15-the result (of the subtraction) will be zero, and BEQ would be triggered since the CPY would have set the Z flag.
Major uses: Y is the most popular index, the most heavily used counter within loops since it can serve two purposes: It permits the very useful Indirect Y addressing mode (LDA (15),Y) and can simultaneously maintain a count of loop events.
See CMP above for a detailed discussion of the various branch comparisons which CPY can implement.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Absolute |
CPY #15 CPY 15 CPY 1500 |
$C0/192 $C4/196 $CC /204 |
2 2 3 |
Affected flags: N Z C
DEC
What it does: Reduces the value of a byte in memory by 1. The N and Z flags are affected.
Major uses: A useful alternative to SBC when you are reducing the value of a memory address. DEC is simpler and shorter than SBC, and although DEC doesn't affect the C flag, you can still decrement double-byte numbers (see "Decrement Double-Byte Numbers" in Appendix D).
The other main use for DEC is to control a memory index when the X and Y Registers are too busy to provide this service. For example, you could define, say, address $505 as a counter for a loop structure. Then: LOOP STA $8000:DEC $505:BEQ ENDJMP LOOP. This structure would continue storing A into $8000 until address $505 was decremented down to zero. This imitates DEX or DEY and allows you to set up as many nested loop structures (loops within loops) as you wish.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Zero Page Zero Page,X Absolute Absolute,X |
DEC 15 DEC 15,X DEC 1500 DEC 1500,X |
$C6/198 $D6/214 $CE/206 $DE/222 |
2 2 3 3 |
Affected flags: N Z
DEX
What it does: Reduces the X Register by 1.
Major uses: Used as a counter (an index) within loops. Normally, you LDX with some number (the number of times you want the loop executed) and then DEX:BEQ END as a way of counting events and exiting the loop at the right time.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
DEX |
$CA/202 |
1 |
Affected flags: N Z
DEY
What it does: Reduces the Y Register by 1.
Major uses: Like DEX, DEY is often used as a counter for loop structures. But DEY is the more common of the two since the Y Register can simultaneously serve two purposes within a loop by permitting the very popular Indirect Y addressing mode. A common way to print a screen message (the ASCII form of the message is at $5000 in this example, and the message ends with 0): LDY #0:LOOP LDA $5000,Y:BEQ END:STA SCREEN,Y:INY:JMP LOOP:END continue with the program.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
DEY |
$88/136 |
1 |
Affected flags: N Z
EOR
What it does: Exclusive ORs a byte in memory with the Accumulator. Each bit in memory is compared with each bit in the Accumulator, and the bits are then set (given a 1) if one of the compared bits is 1. However, bits are cleared if both are 0 or if both are 1. The bits in the byte held in the Accumulator are the only ones affected by this comparison.
Major uses: EOR doesn't have too many uses. Its main value is to toggle a bit. If a bit is clear (is a 0), it will be set (to a 1); if a bit is set, it will be cleared. For example, if you want to reverse the current state of the sixth bit in a given byte: LDA BYTE:EOR #$40:STA BYTE. This will set bit 6 in BYTE if it was 0 (and clear it if it was 1). This selective bit toggling could be used to "shift" an unshifted ASCII character via EOR #$80 (1000000). Or if the character were shifted, EOR #$80 would make it lowercase. EOR toggles.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,X Absolute Absolute,X Absolute,Y Indirect,X Indirect,Y |
EOR #15 EOR 15 EOR 15,X EOR 1500 EOR 1500,X EOR 1500,Y EOR (15,X) EOR (15),Y |
$49/73 $45/69 $55/85 $4D/77 $5D/93 $59/89 $41/65 $51/81 |
2 2 2 3 3 3 2 2 |
Affected flags: N Z
INC
What it does: Increases the value of a byte in memory by 1.
Maor uses: Used exactly as DEC (see DEC above), except it counts up instead of down. For raising address pointers or supplementing the X and Y Registers as loop indexes.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Zero Page Zero Page,X Absolute Absolute, X |
INC 15 INC 15,X INC 1500 INC 1500,X |
$E6/230 $F6/246 $EE/238 $FE/254 |
2 2 3 3 |
Affected flags: N Z
INX
What it does: Increases the X Register by 1.
Major uses: Used exactly as DEX (see DEX above), except it counts up instead of down. For loop indexing.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
INX |
$E8/232 |
1 |
Affected flags: N Z
INY
What it does: Increases the Y Register by 1.
Major uses: Used exactly as DEY (see DEY above), except it counts up instead of down. For loop indexing and working with the Indirect Y addressing mode (LDA (15),Y).
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
INY |
$C8/200 |
1 |
Affected flags: N Z
JMP
What it does: Jumps to any location in memory.
Major uses: Branching long range. It is the equivalent of BASIC's GOTO instruction. The bytes in the Program Counter are replaced with the address (the argument) following the JMP instruction and, therefore, program execution continues from this new address.
Indirect jumping-JMP (1500)-is not recommended, although some programmers find it useful. It allows you to set up a table of jump targets and bounce off them indirectly. For example, if you had placed the numbers $00 $04 in addresses $88 and $89, a JMP ($0088) instruction would send the program to whatever ML routine was located in address $0400. Unfortunately, if you should locate one of your pointers on the edge of a page (for example, $00FF or $17FF), this Indirect JMP addressing mode reveals its great weakness. There is a bug which causes the jump to travel to the wrong place-JMP ($D0FF) picks up the first byte of the pointer from $D0FF, but the second byte of the pointer will be incorrectly taken from $0000. With JMP ($17FF), the second byte of the pointer would come from what's in address $1700.
Since there is this bug, and since there are no compelling reasons to set up JMP tables, you might want to forget you ever heard of Indirect jumping.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Absolute Indirect |
JMP 1500 JMP (1500) |
$4C/76 $6C/108 |
3 3 |
Affected flags: none of them.
JSR
What it does: Jumps to a subroutine anywhere in memory. Saves the PC (Program Counter) address, plus three, of the JSR instruction by pushing it onto the stack. The next RTS in the program will then pull that address off the stack and return to the instruction following the JSR.
Major uses: As the direct equivalent of BASIC's GOSUB command, JSR is heavily used in ML programming to send control to a subroutine and then (via RTS) to return and pick up where you left off. The larger and more sophisticated a program becomes, the more often JSR will be invoked. In LADS, whenever something is printed to screen or printer, you'll often see a chain of JSRs performing necessary tasks: JSR PRNTCR: JSR PRNTSAJSR PRNTSPACEJSR PRNTNUM:JSR PRNTSPACE. This JSR chain prints a carriage return, the current assembly address, a space, a number, and another space.
Another thing you might notice in LADS and other ML programs is a PLA:PLA pair. Since JSR stuffs the correct return address onto the stack before leaving for a subroutine, you need to do something about that return address if you later decide not to RTS back to the position of the JSR in the program. This might be the case if you usually want to RTS, but in some particular cases, you don't. For those cases, you can take control of program flow by removing the return address from the stack (PLA:PLA will clean off the two-byte address) and then performing a direct JMP to wherever you want to go.
If you JMP out of a subroutine without PLA:PLA, you could easily overflow the stack and crash the program.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Absolute |
JSR 1500 |
$20/32 |
3 |
Affected flags: none of them.
LDA
What it does: Loads the Accumulator with a byte from memory. Copy might be a better word than load, since the byte in memory is unaffected by the transfer.
Major uses: The busiest place in the computer. Bytes coming in from disk, tape, or keyboard all flow through the Accumulator, as do bytes on their way to screen or peripherals. Also, because the Accumulator differs in some important ways from the X and Y Registers, the Accumulator is used by ML programmers in a different way from the other registers.
Since INY/DEY and INX/DEX make those registers useful as counters for loops (the Accumulator couldn't be conveniently employed as an index; there is no INA instruction), the Accumulator is the main temporary storage register for bytes during their manipulation in an ML program. ML programming, in fact, can be defined as essentially the rapid, organized maneuvering of single bytes in memory. And it is the Accumulator where these bytes often briefly rest before being sent elsewhere.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,X Absolute Absolute,X Absolute,Y Indirect,X Indirect,Y |
LDA #15 LDA 15 LDA 15,X LDA 1500 LDA 1500,X LDA 1500,Y LDA (15,X) LDA (15),Y |
$A9/169 $A5/165 $B5/181 $AD/173 $BD/189 $B9/185 $A1/161 $B1/177 |
2 2 2 3 3 3 2 2 |
Affected flags: N Z
LDX
What it does: Loads the X Register with a byte from memory.
Major uses: The X Register can perform many of the tasks that the Accumulator performs, but it is generally used as an index for loops. In preparation for its role as an index, LDX puts a value into the register.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,Y Absolute Absolute,Y |
LDX #15 LDX 15 LDX 15,Y LDX 1500 LDX 1500,Y |
$A2/162 $A6/166 $B6/182 $AE/174 $BE/190 |
2 2 2 3 3 |
Affected flags: N Z
LDY
What it does: Loads the Y Register with a byte from memory.
Major uses: The Y Register can perform many of the tasks that the Accumulator performs, but it is generally used as an index for loops. In preparation for its role as an index, LDY puts a value into the register.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,X Absolute Absolute,X |
LDY #15 LDY 15 LDY 15,X LDY 1500 LDY 1500,X |
$A0/160 $A4/164 $134/180 $AC/172 $BC/188 |
2 2 2 3 3 |
Affected flags: N Z
LSR
What it does: Shifts the bits in the Accumulator or in a byte in memory to the right, by one bit. A zero is stuffed into bit 7, and bit 0 is put into the carry flag.
Major uses: To divide a byte by 2. In combination
with the ROR instruction, LSR can divide a two-byte or larger number (see
Appendix D).
LSR:LSR:LSR:LSR will put the high four bits (the high
nybble) into the low nybble (with the high nybble replaced by the zeros being
stuffed into the seventh bit and then shifted to the right).
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Accumulator Zero Page Zero Page,X Absolute Absolute,X |
LSR LSR 15 LSR 15,X LSR 1500 LSR 1500A |
$4A/74 $46/70 $56/86 $4E/78 $5E/94 |
2 2 2 3 3 |
Affected flags: N Z C
NOP
What it does: Nothing. No operation.
Major uses: Debugging. When setting breakpoints with BRK, you will often discover that a breakpoint, when examined, passes the test. That is, there is nothing wrong at that place in the program. So, to allow the program to execute to the next breakpoint, you cover the BRK with a NOP. Then, when you run the program, the computer will slide over the NOP with no effect on the program. Three NOPs could cover a JSR XXXX, and you could see the effect on the program when that particular JSR is eliminated.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
NOP |
$EA/234 |
1 |
Affected flags: none of them.
ORA
What it does: Logically ORs a byte in memory with the byte in the Accumulator. The result is in the Accumulator. An OR results in a 1 if either the bit in memory or the bit in the Accumulator is 1.
Major uses: Like an AND mask which turns bits off, ORA masks can be used to turn bits on. For example, if you wanted to "shift" an ASCII character by setting the seventh bit, you could LDA CHARACTER:ORA #$80. The number $80 in binary is 10000000, so all the bits in CHARACTER which are ORed with zeros here will be left unchanged. (If a bit in CHARACTER is a 1, it stays a 1. If it is a zero, it stays 0.) But the 1 in the seventh bit of $80 will cause a 0 in the CHARACTER to turn into a 1. (If CHARACTER already has a 1 in its seventh bit, it will remain a 1.)
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,X Absolute Absolute,X Absolute,Y Indirect,X Indirect,Y |
ORA #15 ORA 15 ORA 15,X ORA 1500 ORA 1500,X ORA 1500,Y ORA (15,X) ORA (15),Y |
$09/9 $05/5 $15/21 $0D/13 $1D/29 $19/25 $01/1 $11/17 |
2 2 2 3 3 3 2 2 |
Affected flags: N Z
PHA
What it does: Pushes the Accumulator onto the stack.
Major uses: To temporarily (very temporarily) save the byte in the Accumulator. If you are within a particular subroutine and you need to save a value for a brief time, you can PHA it. But beware that you must PLA it back into the Accumulator before any RTS so that it won't misdirect the computer to the wrong RTS address. All RTS addresses are saved on the stack. Probably a safer way to temporarily save a value (a number) would be to STA TEMP or put it in some other temporary variable that you've set aside to hold things. Also, the values of A, X, and Y need to be temporarily saved, and the programmer will combine TYA and TXA with several PHAs to stuff all three registers onto the stack. But, again, matching PLAs must restore the stack as soon as possible and certainly prior to any RTS.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
PHA |
$48/72 |
1 |
Affected flags: none of them .
PHP
What it does: Pushes the "processor status" onto the top of the stack. This byte is the Status Register, the byte which holds all the flags: N Z C I D V.
Major uses: To temporarily (very temporarily) save the state of the flags. If you need to preserve the all current conditions for a minute (see description of PHA above), you may also want to preserve the Status Register as well. You must, however, restore the Status Register byte and clean up the stack by using a PLP before the next RTS.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
PHP |
$08/8 |
1 |
Affected flags: none of them.
PLA
What it does: Pulls the top byte off the stack and puts it into the Accumulator.
Major uses: To restore a number which was temporarily stored on top of the stack (with the PHA instruction). It is the opposite action of PHA (see above). Note that PLA does affect the N and Z flags. Each PHA must be matched by a corresponding PLA if the stack is to correctly maintain RTS addresses, which is the main purpose of the stack.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
PLA |
$68/104 |
1 |
Affected flags: N Z
PLP
What it does: Pulls the top byte off the stack and puts it into the Status Register (where the flags are). PLP is a mnemonic for PuLl Processor status.
Major uses: To restore the condition of the flags after the Status Register has been temporarily stored on top of the stack (with the PHP instruction). It is the opposite action of PHP (see above). PLP, of course, affects all the flags. Any PHP must be matched by a corresponding PLP if the stack is to correctly maintain RTS addresses, which is the main purpose of the stack.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
PLP |
$28/40 |
1 |
Affected flags: all of them.
ROL
What it does: Rotates the bits in the Accumulator or in a byte in memory to the left, by one bit. A rotate left (as opposed to an ASL, Arithmetic Shift Left) moves bit 7 to the carry, moves the carry into bit 0, and every other bit moves one position to its left. (ASL operates quite similarly, except it always puts a 0 into bit 0.)
Major uses: To multiply a byte by 2. ROL can be
used with ASL to multiply multiple-byte numbers since ROL pulls any carry
into bit 0. If an ASL resulted in a carry, it would be thus taken into account
in the next higher byte in a multiplebyte number. (See Appendix D.)
Notice how the act of moving columns of binary numbers
to the left has the effect of multiplying by 2:
0010 (the number 2 in binary)
0100 (the number 4)
This same effect can be observed with decimal numbers,
except the columns represent powers of 10:
0010 (the number 10 in decimal)
0100 (the number 100)
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Accumulator Zero Page Zero Page,X Absolute Absolute,X |
ROL ROL 15 ROL 15,X ROL 1500 ROL 1500,X |
$2A/42 $26/38 $36/54 $2E/46 $3E/62 |
1 2 2 3 3 |
Affected flags: N Z C
ROR
What it does: Rotates the bits in the Accumulator or in a byte in memory to the right, by one bit. A rotate right (as opposed to a LSR, Logical Shift Right) moves bit 0 into the carry, moves the carry into bit 7, and every other bit moves one position to its right. (LSR operates quite similarly, except it always puts a 0 into bit 7.)
Major uses: To divide a byte by 2. ROR can be
used with LSR to divide multiple-byte numbers since ROR puts any carry into
bit 7. If an LSR resulted in a carry, it would be thus taken into account
in the next lower byte in a multiple-byte number. (See Appendix D.)
Notice how the act of moving columns of binary numbers
to the right has the effect of dividing by 2:
1000 (the number 8 in binary)
0100 (the number 4)
This same effect can be observed with decimal numbers, except the columns
represent powers of 10:
1000 (the number 1000 in decimal)
0100 (the number 100)
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Accumulator Zero Page Zero Page,X Absolute Absolute,X |
ROR ROR 15 ROR 15,X ROR 1500 ROR 1500.X |
$6A/106 $66/102 $76/118 $6E/110 $7E/126 |
1 2 2 3 3 |
Affected flags: N Z C
RTI
What it does: Returns from an interrupt.
Major uses: None. You might want to add your own routines to your machine's normal interrupt routines (see SEI below), but you won't be generating actual interrupts of your own. Consequently, you cannot ReTurn from Interrupts you never create.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
RTI |
$40/64 |
1 |
Affected flags: all of them (Status Register is retrieved from the stack).
RTS
What it does: Returns from a subroutine jump (caused by JSR) .
Major uses: Automatically picks off the two top bytes on the stack and places them into the Program Counter. This reverses the actions taken by JSR (which put the Program Counter bytes onto the stack just before leaving for a subroutine). When RTS puts the return bytes into the Program Counter, the next event in the computer's world will be the instruction following the JSR which stuffed the return address onto the stack in the first place.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
RTS |
$60/96 |
1 |
Affected flags: none of them.
SBC
What it does: Subtracts a byte in memory from the byte in the Accumulator, and "borrows" if necessary. If a "borrow" takes place, the carry flag is cleared (set to 0). Thus, you always SEC (set the carry flag) before an SBC operation so you can tell if you need a "borrow." In other words, when an SBC operation clears the carry flag, it means that the byte in memory was larger than the byte in the Accumulator. And since memory is subtracted from the Accumulator in an SBC operation, if memory is the larger number, we must "borrow."
Major uses: Subtracts one number from another.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Immediate Zero Page Zero Page,X Absolute Absolute,X Absolute,Y Indirect,X Indirect.Y |
SBC #15 SBC 15 SBC 15,X SBC 1500 SBC 1500,X SBC 1500,Y SBC (15,X) SBC (15),Y |
$E9/233 $E5/229 $175/245 $ED/237 $FD/253 $F9/249 $E1/225 $F1/241 |
2 2 2 3 3 3 2 2 |
Affected flags: N Z C V
SEC
What it does: Sets the carry (C) flag (in the processor Status Register byte).
Major uses: This instruction is always used before any SBC operation to show if the result of the subtraction was negative (if the Accumulator contained a smaller number than the byte in memory being subtracted from it). See SBC above.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
SEC |
$38/56 |
1 |
Affected flags: C
SED
What it does: Sets the decimal (D) flag (in the processor Status Register byte).
Major uses: Setting this flag puts the 6502 into decimal arithmetic mode. This mode can be easier to use when you are inputting or outputting decimal numbers (from the user of a program or to the screen). Simple addition and subtraction can be performed in decimal mode, but most programmers ignore this feature since more complicated math requires that you remain in the normal binary state of the 6502.
Note: Commodore computers automatically clear this mode when entering ML via SYS. However, Apple and Atari computers can enter ML in an indeterminant state. Since there is a possibility that the D flag might be set (causing havoc) on entry to an ML routine, it is sometimes suggested that owners of these two computers use the CLD instruction at the start of any ML program they write. Any ML programmer must CLD following any deliberate use of the decimal mode.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
SED |
$F8/248 |
1 |
Affected flags: D
SEI
What it does: Sets the interrupt disable flag (the I flag) in the processor status byte. When this flag is up, the 6502 will not acknowledge or act upon interrupt attempts (except a few nonmaskable interrupts which can take control in spite of this flag, like a reset of the entire computer). The operating systems of most computers will regularly interrupt the activities of the chip for necessary, high-priority tasks such as updating an internal clock, displaying things on the TV, receiving signals from the keyboard, etc. These interruptions of whatever the chip is doing normally occur 60 times every second. To find out what housekeeping routines your computer interrupts the chip to accomplish, look at the pointer in $FFFE/FFFF. It gives the starting address of the maskable interrupt routines.
Major uses: You can alter a RAM pointer so that it sends these interrupts to your own ML routine, and your routine then would conclude by pointing to the normal interrupt routines. In this way, you can add something you want (a click sound for each keystroke? the time of day on the screen?) to the normal actions of your operating system. The advantage of this method over normal SYSing is that your interrupt-driven routine is essentially transparent to whatever else you are doing (in whatever language). Your customization appears to have become part of the computer's ordinary habits.
However, if you try to alter the RAM pointer while the other interrupts are active, you will point away from the normal housekeeping routines in ROM, crashing the computer. This is where SEI comes in. You disable the interrupts while you LDA STA LDA STA the new pointer. Then CLI turns the interrupt back on and nothing is disturbed.
Interrupt processing is a whole subcategory of ML programming and has been widely discussed in magazine articles. Look there if you need more detail.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
SEI |
$78/120 |
1 |
Affected flags: I
STA
What it does: Stores the byte in the Accumulator into memory.
Major uses: Can serve many purposes and is among the most used instructions. Many other instructions leave their results in the Accumulator (ADC/SBC and logical operations like ORA), after which they are stored in memory with STA.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Zero Page Zero Page,X Absolute Absolute,X Absolute,Y Indirect,X Indirect,Y |
STA 15 STA 15,X STA 1500 STA 1500,X STA 1500,Y STA (15,X) STA (15),Y |
$85/133 $95/149 $8D/141 $9D/157 $99/153 $81/129 $91/145 |
2 2 3 3 3 2 2 |
Affected flags: none of them.
STX
What it does: Stores the byte in the X Register into memory.
Major uses: Copies the byte in X into a byte in memory.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Zero Page Zero Page,Y Absolute |
STX 15 STX 15,Y STX 1500 |
$86/134 $96/150 $8E/142 |
2 2 3 |
Affected flags: none of them.
STY
What it does: Stores the byte in the Y Register into memory.
Major uses: Copies the byte in Y into a byte in memory.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Zero Page Zero Page,X Absolute |
STY 15 STY 15,X STY 1500 |
$84/132 $94/148 $8C/140 |
2 2 3 |
Affected flags: none of them.
TAX
What it does: Transfers the byte in the Accumulator to the X Register.
Major uses: Sometimes you can copy the byte in the Accumulator into the X Register as a way of briefly storing the byte until it's needed again by the Accumulator. If X is currently unused, TAX is a convenient alternative to PHA (another temporary storage method).
However, since X is often employed as a loop counter, TAX is a relatively rarely used instruction.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
TAX |
$AA/170 |
1 |
Affected flags: N Z
TAY
What it does: Transfers the byte in the Accumulator to the Y Register.
Major uses: Sometimes you can copy the byte in the Accumulator into the Y Register as a way of briefly storing the byte until it's needed again by the Accumulator. If Y is currently unused, TAY is a convenient alternative to PHA (another temporary storage method).
However, since Y is quite often employed as a loop counter, TAY is a relatively rarely used instruction.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
TAY |
$A8/168 |
1 |
Affected flags: N Z
TSX
What it does: Transfers the Stack Pointer to the X Register.
Major uses: The Stack Pointer is a byte in the 6502 chip which points to where a new value (number) can be added to the stack. The Stack Pointer would be "raised" by two, for example, when you JSR and the two bytes of the Program Counter are pushed onto the stack. The next available space on the stack thus becomes two higher than it was previously. By contrast, an RTS will pull a two-byte return address off the stack, freeing up some space, and the Stack Pointer would then be "lowered" by two.
The Stack Pointer is always added to $0100 since the stack is located between addresses $0100 and $01FF.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
TSX |
$BA/186 |
1 |
Affected flags: N Z
TXA
What it does: Transfers the byte in the X Register to the Accumulator.
Major uses: There are times, after X has been used as a counter, when you'll want to compute something using the value of the counter. And you'll therefore need to transfer the byte in X to the Accumulator. For example, if you search the screen for character $75:
CHARACTER = $75:SCREEN =
$0400
LDX #0
LOOP LDA SCREENX:CMP
#CHARACTER:BEQ MORE:INX
BEQ NOTFOUND ; (this prevents an endless loop
MORE TXA ; (you now know the character's location)
NOTFOUND BRK
In this example, we want to perform some action based on the location of the character. Perhaps we want to remember the location in a variable for later reference. This will require that we transfer the value of X to the Accumulator so it can be added to the SCREEN start address.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
TXA |
$8A/138 |
1 |
Affected flags: N Z
TXS
What it does: Transfers the byte in X Register into the Stack Pointer.
Major uses: Alters where, in the stack, the current "here's storage space" is pointed to. There are no common uses for this instruction.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
TXS |
$9A/154 |
1 |
Affected flags: none of them.
TYA
What it does: Transfers the byte in the Y Register to the Accumulator.
Major uses: See TXA.
Addressing Modes:
Name |
Format |
Opcode |
Number of Bytes Used |
Implied |
TYA |
$98/152 |
1 |
Affected flags: N Z
Return to Table of Contents | Previous Chapter | Next Chapter