# Learning 6502 assembly

This page by Dan Polansky guides the reader through first steps of learning 6502 assembly (6502 is an 8-bit processor originally manufactured by MOS Technology). The approach is this: first point the reader to good online sources describing the assembly language, then provide exercises.
We will use Easy 6502 website, which contains a nice introduction together with an online 6502 emulator written in JavaScript. In that environment, one can manipulate a screen of 32 x 32 pixels and 16 colors, starting at $200, one byte per pixel. Furthermore, pseudorandom 8-bit numbers can be obtained from address $fe. One can also get the ASCII code of the last key pressed from $ff. This environment is good to start practicing, although it does not offer ASCII output, which is inconvenient for, say, numerical exercises.
If you never programmed in assembly, the Easy 6502 web site is a good start as a read. The processor is also described in Wikibooks. You may either read Easy 6502 right now, or you can start with exercises and only consult the guide on an as needed basis.
The following exercises are meant for Easy 6502 online emulator. The sequence of exercises is significant, where the latter ones incrementally build on the earlier ones. To learn most from this page, you have to do the exercises yourself rather than merely reading the solutions.
Motivation: Get a feel for assembly programming with a simple processor that was much in use in many home computers (Apple II, Commodore 64, Atari 8-bit, etc.) and appreciate the convenience of high-level languages, C included, and cherish the ingenuity and talent of all those 6502 programmers who created the 8-bit games on very limited machines.
License: All code snippets here are released into the public domain.

## Cheat sheet

Here is a quick cheat sheet. Exercises follow in the next sections.
Instructions:
* LDA, STA, LDX, STX, LDY, STY
* TAX, TAY, TXA, TYA, TXS, TSX
* CMP, CPX, CPY
* BEQ, BNE, BCC, BCS, BPL, BMI, BVC, BVS
* JMP, JSR, RTS
* PLA, PHA
* ADC, SBC, INC, INX, INY, DEC, DEX, DEY
* CLC, SEC, CLD, SED
* ASL, LSR, AND, ORA, EOR, BIT, ROL, ROR
* Etc.
Addressing modes:
* LDA #$80 ; Acc := $80; called immediate
* LDA $80 ; Acc := Peek($80)
* LDA $8000 ; Acc := Peek($8000)
* LDA ($80), Y ; Acc := Peek(Deek($80)+Y) ; only for zero page
* LDA ($80, X) ; Acc := Peek(Deek($80+X)) ; only for zero page
Numerical literals (exemplified in use with LDA immediate):
* LDA #170 ;decimal
* LDA #$AA ;hexadecimal
* LDA #%10101010 ;binary
Flags of the status register:
* N: Negative
* V: Overflow
* -: ignored
* B: Break
* D: Decimal: use BCD
* I: Interrupt
* Z: Zero
* C: Carry
Links:
* 6502 Instruction Set, masswerk.at
* 6502 Family CPU Reference by Michael Steil, pagetable.com
* NMOS 6502 Opcodes by John Pickens et al., 6502.org
* 6502 Assembly, wikibooks.org -- contains some suspect material, e.g. "INC $F001,Y", which does not exist

## Limitations of the CPU

To get a better idea about the character of 6502 programming, let us look at its limitations compared e.g. to Motorola 68000 ("68k"):
* There are only 3 main registers: A, X and Y. By contrast, 68k has 8 data registers and 8 address registers. As a consequence, 6502 programming needs to use memory location for loop indices and other temporary needs much more often.
* All three main registers are 8-bit. Thus, even such a simple thing as making an x coordinage loop from 0 to 319 (typical for some 8-bit computers using the CPU) cannot be handled by incrementing a single register with no additional work. By contrast, 68k has 32-bit data and address registers. Even 16-bit registers would make a huge difference.
* Some operations are only possible with the accumulator, not with the index registers X and Y. If one wants to use these operations on, say, X, one can use TXA, then operate, and then TAX, thereby losing the value that was in A.
* 6502 has no integer multiplication and division instructions, only addition and subtraction. 68k has multiplication.

## Small block of pixels without a loop

Assignment: fill a small block of pixels, say, 3 pixels, with colors 0 through 2.
Solution:
What we have learned: we can use LDA and STA to manipulate memory. There is the immediate addressing mode indicated using the hash character (#) and the other addressing mode. The string character ($) indicates the value is hexadecimal; it is decimal without it.

## Block of pixels using a loop

Assignment: fill a 256-long block of pixels (spanning mutliple lines on the 32x32 screen) with color 1.
Solution:
What we have learned:
* The increment instruction affects the zeor flag.

## Fill screen with vertical stripes

Assignment: fill the 32x32 screen with vertical color stripes. Which colors are to be used is left unspecified.
Hint: we may build on the ideas from previous exercises. We can no longer do with using Y as index register alone since we need to cover 32x32 = 4 * 256 bytes.
Solution:
What we have learned:
* We can use the indirect addressing indexed with Y for the purpose. The base address needs to be stored at zero page ($0-$FF). We picked $80 arbitrarily. We note that 6502 uses little endian addressing: the lower byte is stored at $80 and the upper byte in $81 rather than the other way around.
* There is TYA (A := Y) and similar for X and the other way around.

## Fill screen with horizontal stripes

Assignment: Fill screen with horizontal stripes.
Solution:
What we have learned: We need to use additional memory to store values given how few registers we have.

## Fill screen with random color pixels

Assignment: fill the 32x32 screen with random color pixels. This is a minor variation on filling the screen with a fixed color.
Hint: obtain a random byte from address $fe.

## Plot a secondary diagonal

Assignment: plot a secondary diagonal using color 1. That is, start at upper righthand corner and end at lower lefthand corner. (Plotting the main diagonal is a bit easier and is left out.)
Solution:
What we have learned: we cannot do addition on Y, only on A. The carry bit set by ADC is not erased by TAY.

## Random pixels in a rectangle

Assignment: bombard a rectangle (e.g. 20 x 25 pixels) starting at the top left corner with random pixels. Thus, pseudorandomly generate pixel x and y coordinates in the appropriate ranges and plot pixel with color 1 at that location, doing so repeatedly. Have the rectangle width and height parametrized.
Solution:
What we have learned:
* How to compare 8-bit numbers for less than or less than or equal using unsigned 8-bit integer semantics.
* How to multiply by a power of 2 (here, 32, the screen width) via ASL and using carry bit to reflect the operation in the upper byte.
Links:
* Tutorials: Compare Instructions, 6502.org

## Keyboard controlled pixels

Assignment: read key events and when a key is pressed, place random color to pixel that is offset from the screen beginning by the ASCII code of the key pressed. Read the ASCII code of the last key (or key combination, e.g. "a" with shift) from $ff. When no key is being pressed, keep setting random color to pixel with offset zero.
Solution:
What we have learned: How to read key events and erase last key pressed. How the keys map to codes, visually; thus, e.g. "a" is $61, and other lowercase letters alphabetically follow.

## Keyboard-controlled moving dot

Assignment: implement a keyboard-controlled moving dot representing a person, represented as a single pixel of color 1 (white). Use color 5 (green) to first fill the screen as a background. Mark the screen boundary using color 8 (brown). As the player moves around, leave empty space (color 0, black) behind. Do not allow the player to enter the screen boundary filled with brown. Use keys A, S, D, and W to control the player.
Note: This was inspired by the snake game at Easy 6502. Like in the snake, one has to figure out how to receive keyboard events. However, it is simpler than the snake, not requiring keeping track of the locations of the snake body.
Solution:
What we have learned:
* Far jumps are not possible using relative branch instructions Bxx; one has to use e.g. JMP.
* To subtract the value V using SBC #V, one has to make sure the carry flag is set (via SEC) rather than cleared (via CLC).

## Plot concentric colored squares

Assignment: plot concentric square outlines in different colors, 16 of them so they completely fill the screen. Create a generic plot pixel routine for the purpose, passing the color and the x and y coordinates in registers.
Solution:
What we have learned: we created a subroutine that uses registers for argument passing (not stack) and stores the registers on stack.

## Fill the screen without BNE and BEQ

Assigment: fill the screen with a fixed color without using BNE and BEQ branch instructions. Hint: you can use BPL and BMI. Purpose: get acquainted with BPL and BMI.
A solution:

## Fill the screen with a checkered pattern

Assignment 1: fill the screen with two alternating colors 0 and 1 such that the alternation is both horizontal and vertical. Thus, create a checkered pattern where the squares have the size of 1 pixel.
A solution:
Assignment 2 (a variation of assignment 1): let these be two pseudorandomly chosen colors rather than 0 and 1, that is, colors obtained from the pseudorandom source at $FE.
A solution:
Assignment 3: Implement assignment 2 with the difference that the square size is 2 instead of 1. Left as an exercise for the reader without solution (very easy modification of the solution for assignment 2).
Assignment 4: Implement assignment 2 with the difference that the square size is 4 instead of 1. Also very easy.
Assignment 5: Implement assignment 2 with the difference that the square size is 5 instead of 1 and some of the squares are truncated. Since 5 does not divide 32 (the screen size), this one is more difficult. Left without solution so far.
Assignment 6: Implement assignment 2 with the difference that the square size is picked as a pseudorandom number between 1 and 16. Depending on the square size, some of the squares may be truncated. This one is more difficult. Left without solution so far.

## Swap two bytes using only accumulator

Assignment: swap two bytes located e.g. at $80 and $81 using only the accumulator; do not use X and Y and do not use stack.
A solution:

## Visualize bit patterns on screen

Assignment: write a routine to visualize the content of a byte on the screen as an 8-pixel pattern corresponding to the bit pattern in the byte, using two colors 0 and non-0 (black and some non-black color). Thus, treat the byte as if it was part of the screen buffer of the high-resolution mode on Atari 800 XL and some other 8-bit computers. Figure out a test (not necessarily a complete one) for the byte visualization routine, e.g. by showing the value of #%10101010 that is successively shifted to the right.
Point: practice detection of the state of individual bits within bytes. Moreover, practice design of tests covering at least part of the input space. Furthermore, using this routine, we can visualize the results of various assembly operations on screen.
A solution:
A variation: modify the above solution to allow plotting on any part of the screen rather than just the top quarter. Expand the test to make full use of the screen.
A solution:
A variation: use the above solution's VISUALIZEBYTE routine to plot all byte values from 0 to 127, thereby filling the screen with them. Use different colors for different 8 pixel wide columns. This demonstrates correct function of VISUALIZEBYTE for half of the input space.
A solution:

## Scrolling the screen

Assignment: implement a routine for scrolling the screen to the right by one pixel, leaving the leftmost pixels just scrolled away black. Test it by filling the screen with pseudorandom pixels and scrolling the content by 32 pixels, thereby removing it from the screen.
A solution:

## Fibonacci sequence

Assignment: calculate Fibonacci sequence using 16-bit integer arithmetic. (Variations of the assignment follow below.)
A solution:
What we have learned: the carry flag's interaction with ADC makes 16-bit addition trivial.
A variation: modify the above to be 32-bit and to put the Fibonacci numbers on screen as bit patterns, one number per line. For the putting on screen, you can use routine VISUALIZEBYTE from a previous exercise.
A solution:
What we have learned: the carry flag's interaction with ADC makes addition trivial for any fixed number of bytes representing an integer.
A variation: modify the above to have the number of bytes used to represent an integer parametrized, to up to 255 bytes. Do not visualize the result. Slightly more challenging.
A solution:
What we have learned:
* Short memory copy.
* Addition of many-byte integers.
* Decrement of a 16-bit integer.

## Floating-point arithmetic

Implementing floating-point arithmetic on 6502 is not for beginners. If one is interested in a solution, can peruse e.g. 6502.org linked below.
Links:
* Source Code Repository, 6502.org

## Online assemblers

One can asseble the 6502 assembly source code using online assemblers:
* Easy 6502, skilldrick.github.io
* virtual 6502 Assembler, masswerk.at
The Masswerk assembler is too sensitive in that it does not compile "LDA ($80), Y" because of the space after the comma. Moreover, it assembles "LDA ($80),X", which is invalid, into "LDA $80,X". Easy 6502 seems better in those two regards.

## 6502 source code listings

Some 6502 source code listings, from which one can learn (copyrighted!):
* Source Code Repository, 6502.org
* jmechner/Prince-of-Persia-Apple-II, github.com
* Arcade Games: Source Code Collection | Michael R. Cook -- not all items listed are in 6502
* 6502disassembly.com by Andy McFadden