Vocademy

Programming the 6502

Extra Study Material (continued)

The 6502 is one of the simplest microprocessors ever available. It has only three working registers and a simple instruction set. This is why modernized versions are still in production today. Next time you see a heart defibrillator in action, you may see a life saved by a 6502[1]. Many consider the 6502 to be the inspiration for modern RISC (Reduced Instruction Set Computing) processors such as the ARM, which is widely used in smartphones and internet tablets.

The following information is not intended to be a lesson in 6502 programming. Instead, it is an example to demonstrate the inner workings of microprocessors in general.

The programmers model Programmers visualize the world of the microprocessor as a box with smaller boxes inside to store binary numbers. These inside boxes represent the working registers. This model is connected to a memory subsystem through wires called the address bus and the data bus. The memory subsystem is visualized as a stack of memory locations. Think of it like a very tall stack of shoe boxes. Each memory location is identified by a binary number and can hold eight bits (one byte) of data. The microprocessor is able to specify any memory location by turning the voltage of any of the wires of the address bus on or off as needed. The programmer sees these voltages as logical 1s and logical 0s. Once a memory location is specified, the data bus connects to that location and can either see what is stored there or change the data stored there.

6502 Programmers Model

The 6502 has three working registers, the accumulator (A) and the X and Y registers. It also has a 16-bit address bus and an 8-bit data bus. It can specify a 16-bit address, then either copy eight bits at that address to an internal register or copy eight bits from an internal register to that address. Once a byte is in the accumulator, operations such as add, subtract, AND, OR, and Exclusive OR can be performed on it.

Little-endian addressing

The most common microprocessor instructions move data to and from memory. Therefore, part of an instruction must be the location (address) of the data on which the instruction works. A typical instruction consists of a single byte that is the instruction itself, called the operation code or op-code, followed by two bytes that make up the 16-bit address where the data to operate on is stored.

The 6502 uses a 16-bit number to refer to a memory address, but each memory location can only store eight bits. Therefore, it takes two memory locations to store an address. When the 6502 needs to read an address from memory, it must read two bytes in succession.

The 6502 stores addresses in a format called "little-endian"[2]. This means that the first byte of a 16-bit address is the least-significant byte, and the second is the most-significant byte. For example, the address specified by the binary number 0100000000000100 would be stored in memory as the following two bytes:

Byte 1 00000100
Byte 2 01000000
   
0100000000000100 in little endian addressing. Notice that the bytes are stored least-significant byte first, the reverse of what may seen natural.

Sample Instructions

One of the fundamental operations that a microprocessor does is move information from a location in memory to a working register in the computer. In the 6502, the main working register is called the accumulator (also called the A register). The simplest way to do this operation is a two-byte instruction. The first byte, the op-code, tells the microprocessor to copy data from somewhere in memory to the accumulator. The second byte is the data to be copied. This is called immediate addressing (the data immediately follows the op-code in memory).

The 6502 op-code to do this is 10101001. So, if the 6502 lands at a memory location looking for an instruction and finds 10101001, it will move to the next byte in memory, take whatever number is there, and copy it to the accumulator. For example, the following is the two-byte instruction to copy the binary equivalent of the decimal number 12 from memory to the accumulator:

10101001
00001100
 
Instruction to copy the binary equivalent of the decimal number 12 to the accumulator.

The following illustration explains this instruction. The first column is the data in memory. The second column is the same number expressed as a hexadecimal number[3]. The third column is a brief explanation. 

10101001 A9   Op-code (copy next byte to the accumulator)
00001100 0C   Data (Decimal 12)
     
Instruction to copy the decimal number 12 (with explanation in
parenthesis).

The 6502 has eight different ways to specify the memory address that contains data to process. These different ways to specify addresses are called addressing modes. The immediate mode was just demonstrated. Another addressing mode is called "absolute." This is when the two bytes following an op-code specify the address of the data on which to operate.

Assume that memory location 35,789 has the data that needs to be copied to the accumulator. The 16-bit binary representation of 35,789 is 1000101111001101. This is first divided into two bytes, 10001011 and 11001101. These two bytes are put in memory (little endian format) immediately following the op-code. This makes up the three-byte instruction to load the accumulator with the data at an absolute location in memory.

The following example will copy the byte of data stored at memory location 35,789 to the accumulator:

10101101 A9    Op-code (copy data from absolute location in memory)
11001101 CD     Address of data (1000101111001101, 8BCD or 35,789)
10001011 BB
     
Instruction to copy the byte of data stored at location 35,789 to the accumulator.

A more versatile addressing mode is called "absolute, indexed." This is where the X register contains a number used as an offset pointer to an address. After the 16-bit number is derived from the two bytes following the op-code, the content of the X register is added to that number. For example, if the X register contains the number 3 and an instruction points to hexadecimal A000[4], indexed by X, the actual address will be A003. This is like giving directions and saying, "Go to 1234 Elm Street, then go three houses further down the street. You end up at 1237 Elm Street.

This addressing mode can use the same instruction over and over in a loop. Each time the program loops, the X register is incremented so that the working address steps sequentially in memory.

The op-code is the only obvious difference when using the absolute, indexed address mode. The op-code to load the accumulator using absolute addressing is AD. The op-code to load the accumulator using absolute, indexed addressing is BD. The following example shows the same instruction as above but with absolute, indexed addressing.

10111101 BD    Op-code (copy data from absolute location indexed by X)
11001101 CD    Base address of data (1000101111001101, 8BCD or 35,789) before indexing
10001011 BB
     
Instruction to copy the byte of data stored at location 35,789 to the accumulator.

Yet another mode of addressing is indirect addressing. This is where the two bytes following the op-code point to a location in memory where two more bytes point to yet another location in memory. The second address is where the actual data is stored. The pointer can be changed without changing the programming by using this method. Therefore, data can be moved without rewriting the program to point to different addresses each time. All that needs to be changed is the pointer.

This is as far as we will go into addressing modes. It is just enough to show some sample programs to explain how microprocessors work.

—————————
1http://www.westerndesigncenter.com/wdc/
2''Little-endian'' is a reference to Gulliver's Travels.
3Programmers use hexadecimal numbers as a shorthand for binary numbers
4A000 is a hexadecimal number that represents 1010000000000000.
Vocademy