When I jumped from reading about 6502 assembly to writing a small program I started small. I explored the basic program construction, and the accumulator. While I’m learning I will be using OSS Mac/65 Assembler.
When writing an assembly program the first thing that must be done is to define the programs load address (memory location). Sounds simple enough. Buts it’s not. The address depends on many variables such as the version of DOS, if Basic cartridge is installed, if control needs to return to either once the program is done, if the program is to be run from a mini loader or if it’s to be bootable via ATR image.
I’m still figuring out the voo-doo behind load address determination, but I have learned that $3800 is safe for programs that return to DOS, and $2000 for those that don’t. As I learn more about the address decision I’ll write about it.
The structure of a 6502 assembly program is:
- Specify the load address
- Program instructions
- Specify the program end
Once the program is written it needs to be assembled by the assembler. I’m using OSS Mac/65, but there are others such as the Atari Assembler Editor, and Synapse SynAssembler. After its assembled, its ready for execution.
When writing 6502 assembler, each line has a syntax that must be followed. The syntax is:
Line Label OpCode Operand Comment
A brief explanation of each component of the syntax:
- Line – Line number. Start at whatever you want and increment as you go. MUST be followed by a space or TAB.
- Label – Used to identify sections of code, such as COLOR, START, DISPLAY. If no label is used, press TAB to skip this field, otherwise the assembler will barf.
- Opcode – The command (instruction) to execute such as LDA, STA.
- Operand – Parameter to opcode instructions which are literal values, memory locations, or memory locations and register references. Such as “#FF”, or “$3800”.
- Comment – Comments are just that, comments about the code from the author. They are not executed. They are designated by the semi-colon character. Anything after a semi-colon is ignored by the assembler.
In addition to the instruction syntax, there are a few assembler directives, some of which are required, others which aid in program development. These are assembler commands, not 6502 instructions. Here are the required ones, others will be introduced as I start using them:
- “*=” – This is the origin, or load address of the program. It tells the assembler where the program should be loaded into memory. It requires one parameter which is the load address for the program.
- “.OPT OBJ” – This is required for Mac/65 to product object code.
- “.END” – This terminates the program. It tells the assembler to exit the program.
The accumulator is a CPU register that is used for arithmetic and data manipulation.
The first 6502 instructions I explore deal with the accumulator. Specifically, load and store. I also get introduced to RTS. The definitions of the instructions are:
- LDA (LoaD Accumulator): Loads the accumulator with a value or the contents of a memory location.
- STA (STore Accumulator): Stores the contents of the accumulator to a memory location.
- RTS (ReTurn from Subroutine): Returns program execution to the next address after the JSR (Jump to SubRoutine) instruction which called the jump.
Putting It All Together
With this new knowledge I constructed a small 6502 assembly program that sets a few of my console preferences such as color, key rate, etc.
100 *= $3800
101 .OPT OBJ
106 ; Set left margin to 0
110 LDA #0
120 STA 82
126 ; Set key repeat rate
130 LDA #2
140 STA 730
145 ; Set key delay
150 LDA #14
160 STA 729
166 ; Set background color
170 LDA #$04
180 STA 710
185 ; Set text color
190 LDA #$0C
200 STA 709
206 ; No key click
210 LDA #1
220 STA 731
Breaking It Down
- 100: Specify the load address of $3800
- 101: Tell Mac/65 to product object code
- 110: Load the accumulator with decimal value 0
- 120: Store the accumulators contents (0) into memory location 82 (the right margin)
- 130: Load the accumulator with decimal value 2
- 140: Store the accumulators contents (2) into memory location 730 (the key repeat rate)
- 150: Load the accumulator with decimal value 14
- 160: Store the accumulators contents (14) into memory location 729 (the key repeat delay)
- 170: Load the accumulator with hex value 04. This could easily have been decimal value 4. I just wanted to experiment with different value types.
- 180: Store the accumulators contents (decimal 4) into memory location 710 (the background color for graphics 0 display mode)
- 190: Load the accumulator with hex value 0C
- 200: Store the accumulators contents (decimal 12) into memory location 709 (the text color for graphics 0 display mode)
- 210: Load the accumulator with decimal value 1
- 220: Store the accumulators contents (1) into memory location 731 (the key click; > 0 is off)
- 230: Return. I initially didn’t have a return and the results were unpredictable from strange errors, to system crashes.
- 240: Tell the assembler we’re done.
Edit and List
While writing or editing a program it is often useful to list the program to the screen so blocks of code can be seen together. In Mac/65, simply enter “LIST”.
To list a specific section or line number range, enter “LIST start,end” where start is the starting line number you want to see, and end is the last line number you want to see.
Save and Load
In Mac/65 you save a program using LIST and load it with ENTER.
- Save the program with “LIST #D:PREFS.M65”.
- Load the program with “ENTER #D:PREFS.M65”.
In Mac/65 you assemble the program using the ASM command.
- Assemble the program to file with “ASM ,,#D:PREFS.COM”
With Mac/65 you can turn the assembly screen listing off. Presumably that will speed up the process. As a beginner I’ll leave it on. What the listing displays (see screenshot above) is the address in memory the instruction is loaded into, the machine object code of the instruction, and the assembly line as it was entered.
If you dump the addresses in memory where the program was assembled to, the byte values should match what was in the second column of the assembly listing during the assembly process. From my program I see location 381A contains “8DDB02”, and 381D contains “60”. Using the D (Dump) command to display the memory locations 3800 to 381F, I see that they do indeed match (last 4 bytes).
To execute the newly compiled program, drop back to DOS and run the executable.
- Drop back to DOS (Mac/65 way): DOS
- Looking at the disk directory I see the source file and assembled object file, with the object file being very small.
- Run the program (DOS XL or SpartaDOS way) from the D1 command prompt: D:PREFS.COM
- After running the program:
SUCCESS! In the blink of an eye the screen color is changed, the text color is brighter, the right margin is moved from column 2 to 0, the key click is off, the key delay is quicker, and the key repeat is ultra fast, just like I like it.
Now I’ve officially gotten to the same point I was at so many years ago, well very close (just need to add some math bits). Stay with me as I dive deeper.