Quantcast
Channel: VBForums - Game Demos
Viewing all articles
Browse latest Browse all 56

Atari 2600 Programming Tutorial 1 - Getting started, Learning the 6502 Assembler

$
0
0



Welcome to my ultimate 2600 Atari 2600 programming tutorial with a sample example that would work not only on an Atari 2600 emulator such as Stella, but also work on a real Atari 2600 if you have the right tools to extract onto a real cartridge.

Now before you begin. You would need to learn basic 6502 assembly. Now before you walk away and be like "screw that", it's actually easier than you think. Much easier. Just looks a wee bit different than what you commonly program on. I too was turned off into learning it as well until I grew some balls and dived into it, only to find it was a lot of fun. So without further a due, lets dive in shall we. :bigyello:

History:
6502 assembly, believe it or not, was designed for the MOS6502 chip found commonly in old hardware, such as the Apple II, Commodor 64, the Amiga 500, Atari 2600, the Nintendo Entertainment System, etc. It was invented in 1975 and is still used today by hobbyist and homebrewers. At the time, the MOS6502 chip was considered to be the cheapest CPU, and as a result was widely used by computer manufacturers to cut costs. The language itself consists of 56 opcodes and 13 address modes. It also has built in registers such as A (which is an Accumulator), X, and Y. A is commonly used for arithmetic, whereas X and Y is used for counting.

What is an opcode?:
An opcode is an instruction, or to be more precise, a built in method. For example, if you want to load the value of 1 into the A register (which looks like this A = 1 in plain English), you would use the instruction LDA #1. LDA stands for Load Accumulator with a value. The # symbol means you are putting a number there. If you use LDA #$01, it would load 1 as a hexidecimal number. If you use LDA #%00000001, it would load 1 as a binary number. The accumulator (A) is only 8 bits wide. Which means you can only use values between 0 - 255 or 0 - FF or 00000000 - 11111111. This is considered loading the accumulator immediately, and uses the immediate address mode.

Another thing you can do with LDA is load the accumulator with a value from memory. For example you can do LDA $80. Assuming theres a value at that memory location, you are storing the accumulator (A) with a value from the memory address $0080. The amount of memory you can access is 64k wide or $0000 to $FFFF. Some are reserved for certain effects depending on the hardware or even software. So you can load important information such as a random number generated, or what pixel color is being stored, etc. $00-$FF is considered to be a zero page address, where as using $0100-$FFFF is considered to be an absolute address.

Wow thats a lot of information on just one opcode! Are there anymore?:
Yes there are. 55 more to be exact, but we are only gonna use commonly 10 with these tutorials. Another important opcode would be STA, which means to Store the accumulator value to a particular memory address. For example,

Code:

LDA #$01
STA $0200

This means you are loading the accumulator with the value of 1, and storing that value into the memory location $0200. Now you get to play with these two opcodes on a particular website! Because this will actually plot a white pixel onto the screen. Address $0200 to $05FF will be the entire screen. Their built in assembler has a killer debugger as well so you can see whats going on line by line.

https://skilldrick.github.io/easy6502/

This website will introduce you to more opcodes, and more address modes to those opcodes. But like I said before, you will commonly be using 10 commonly.

How the heck do I create 16 bit numbers if I'm only limited to 8 bits?:
This is when things get interesting. You would have to use 2 memory addresses next to each other in order to create bigger numbers. For example, if you want to create the number in hex #$500 and make it into a memory address where you can store a value into, you would do this:

Code:

LDA #$00      ;Store the value #$00 into the accumulator
STA $00        ;Store the accumulator's value into memory location $00
LDA #$05      ;Store the value #$05 into the accumulator
STA $01        ;Store the accumulator's value into memory location $01

LDY #00        ;Store the value #$00 into the Y register
LDA #$01      ;Load the value #$01 into the accumulator (color white)
STA ($00), Y  ;Indirectly store #$01 into the memory location $0500 we
                    ;created earlier on top!

This will plot a pixel at $0500 on screen. But whats this indirect part mean? Indirect Addressing is a little different, but it was a way to access the 16 bit world. We actually just converted a 16 bit number into a real memory address by combing two 8 bit numbers (lower and upper) and put a value there so a pixel appears on screen. With this, you have to wrap the address with parenthesis () if you are using Indirect Addressing Y. If it's X, you would wrap the whole thing. For example STA ($00, X). If you were to just use STA $00 instead of STA ($00), Y, it would do nothing because $00 is still an 8 bit zero page address location. Not the 16 bit location we just created. See for yourself on the emulator on the website.

You also noticed there's another new opcode you see here such as LDY. And it pretty much does the same thing as LDA only it loads the Y register with a value. And you can guess there's also a LDX. But did you know there's also a STX $(memory location) and a STY $(memory location)? You guessed it! STX stores the value of X into a given memory location and STY stores the value of Y into a given memory location. Way to go! You just learned LDA, LDX, LDY, STA, STX, and STY. Now for some arithmetic functions!

Seriously, how do I do math stuff!
There are a very limited number of math functions in the 6502 assembly unfortunately, as you can only add, subtract, increment, decrement, and, and or. If you want multiplication, division, square root, sin, cos, etc., they would need to be manually programmed. And theres plently of code online that shows you how.

ADC is a commonly used opcode for addition, and stands for add with carry. Carry is one of the flags of the 6502 processor and is only set if the accumulator is over 255. For example, if you do this on this website:

Code:

LDA #$01
ADC #$02

The accumulator will now be 3. But if you do this:

Code:

LDA #$FF
ADC #$02

The accumulator would be 1, yet the carry flag is set. Because it exceeded 255 and started back at the beginning.

SBC does the same thing only it subtracts instead of adds.

INX increments X by one.

INY increments Y by one.

DEX decrements X by one.

DEY decrements Y by one.

TAX transfers the value of A into X. Like X = A

TAY transfers the value of A into Y. Like Y = A

TXA transfers the value of X into A. Like A = X

TYA transfers the value of Y into A. Like A = Y

Now that you understand that, its time to learn sub routines!

How do I make subs?:
A sub label is needed to make a sub, and marks a program counter location that can be jumped into any time. For example. Lets take a look at our funky indirect addressing example again, only this time were gonna make a loop!:

Code:

LDY #00        ;Store the value #$00 into the Y register

MyLoop:
LDA #$00
STA $00
LDA #$05
STA $01

LDA #$01
STA ($00), Y
INY
JMP MyLoop

Now run the code on the website. Whoa!!! Did you see that?!! You flooded a good part of the screen from $0500 to $05FF over and over again. You notice there is a JMP command there that jumps to any sub routine label you desire. This comes in handy for placing multiple subs into a loop like so:

Code:


LDX #$00
LDY #$00
JMP MyLoop

MySub1:
;Do stuff here
INX

MySub2:
;Do stuff here
INY

MyLoop:
JMP MySub1
JMP MySub2
JMP MyLoop

Pretty cool isn't it? :bigyello:

Ok, but what about IF statements ;)?:
Now you are gonna learn about a couple compare commands and branch commands. Compare commands compare if the value matches a specific register, and branch commands act on it whether they are equal, not equal, less than, or greater than. Think of the compare command as the IF, and the branch command as the act, which is a jump to a particular sub routine.

CMP compares the value to the accumulator. For example, CMP #$05. You can also compare memory address values, such as CMP $0200.

CPX compares the value to the X register. Pretty much nearly the same as above with the X register.

CPY compares the value to the Y register. Pretty much nearly the same as above with the Y register.

BEQ (Sub Label) jumps to a particular sub if the previous compare statement is equal to the value from the compare statement.

Code:

LDX #$00
MySub:
INX
CPX #05
BEQ MyOtherSub
JMP MySub

MyOtherSub:
TXA

BNE (Sub Label) jumps to a particular sub if the previous compare statement is NOT equal to the value from the compare statement.

Code:

LDX #$00
MySub:
INX
CPX #05
BNE MySub

MyOtherSub:
TXA

Now things are bout to get weird. Cause there are signed and unsigned numbers in 6502 believe it or not, but the combination of certain opcodes will test if they are less than, greater than, less than or equal to, and greater than or equal to. Assuming you have two subs HERE and THERE, here is how to do these using other branch opcodes:

Code:

For unsigned numbers
--------------------------
Operator < :       
BCC THERE

Operator = :       
BEQ THERE

Operator > :       
BEQ HERE
BCS THERE

Operator <= :       
BCC THERE
BEQ THERE

Operator >= :       
BCS THERE


For signed numbers
--------------------------
Operator < :       
BMI THERE

Operator = :       
BEQ THERE

Operator > :       
BEQ HERE
BPL THERE

Operator <= :       
BMI THERE
BEQ THERE

Operator >= :       
BPL THERE

Thats it for the basics!!! You are just nearly a step away from making Atari 2600 games! The next examples in later tutorials will be the actual demos well be making, which is why this is located in the Demos page!

For more information on all 56 opcodes: http://www.6502.org/tutorials/6502opcodes.html
Really cool 6502 demos here, including real games!: http://www.6502asm.com/

Exercise: Write a program that allows you to plot the X and Y position of a pixel anywhere on screen!

Next tutorial will be your first colored background on the Atari 2600 with a demo ;)

Viewing all articles
Browse latest Browse all 56

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>