Oldschool Gaming - reviewing new games on classic computers
The Hex Files :: Part 2 :: written by Jason Kelk :: added 18 Jan 2004

Hello all and welcome to the second part of this course for budding Commodore 64 programmers. In the previous installment we got to grips with the basics of the C64 itself and introduced a first batch of assembly language commands that, after they're converted to machine code, our C64 can understand. This time around, I plan to bring a few more in to play as well as expand on what's gone before. To begin with, LDA and LDX have both been covered independently last time but they can also work together to much greater effect - so lets get things off to a start straight away with the first little example:

		ldx #$00		; set X register to zero
		lda #$01		; put 1 in the accumulator
		sta $0400,x		; store contents of A into $0400+X
		rts

If we were to run this, a letter A would appear at the top left corner of our screen. Nothing exiting so far, huh? Well, if we were to alter the first command to read LDX #$01 and re-run it the results would be slightly different in that the A would now be one character to the right. So how does this actually work you ask. Well, the first command sets the value in the X register and the second sets the accumulator (A register) in the same way as before. But the STA command has been altered slightly so that instead of just putting the contents of A to a set place (in this case memory location 1,024) it adds the value in X to the location. So if X is 0 then the A character appears at 1,024 and if it were 40 then the A will be one line down because there are forty characters a line.

This is the basics of loops in machine code, but before we can introduce them properly we need to first look at another facet of machine code. When writing code it is necessary to leap back and forth through the program in the same way that BASIC can with GOTO's and GOSUB's. Because we have no line numbers we need some way of identifying a piece of code to jump to which is what labels do. A label is not actually a command its a word, but it's like naming a piece of your program so that you can then refer to it by that name. Classic examples are calling a loop loop or your control routine readstick (for reading the joystick) but just about any word that doesn't have an instruction in can be used. Labels do have other uses which we will cover later but for now I'll leave this definition.

Time for another example I think, this time showing the use of a label and our next two commands. This next example would, if executed, put eight A's at the top left of the screen:

		ldx #$00		; set X register to zero
		lda #$01		; put 1 in the accumulator
loop		sta $0400,x		; our very first label!
		inx			; INcrement X (as before)
		cpx #$08		; ComPare X to see if it's 8
		bne loop		; Branch if Not Equal to loop
		rts			; exit

Why have I confused you and introduced two new commands together? Well, lets cover each command in turn. First, CPX is short for ComPare X and its job is to compare things to the X register (fairly obvious, eh?) In the example above we are checking to see if X has the value of #$08 but if we wanted to put say nine A's we merely change the command to CPX #$09. But when we have done this comparison we need to then do something with the results. And this is where Branch if Not Equal, or BNE comes in.

The basic flow of this loop goes like thus. We put a zero in X and a one in A (for character 1, which is the A we would see on screen). Then we hit the main loop which puts the contents of A into location $0400 + X, which is $0400 since X is zero. Then we add one to X and compare it to eight to see if it's reached the end, if not we branch back to loop and put another character down at $0400 + X (which is now $0401 since X is 1). This continues until X does reach eight. When this happens the BNE is ignored (after all, it is equal now) and we fall through to the end.

Some of you may be a bit confused by this logic, thinking that since we stop when X reaches eight then surely the eighth character wouldn't appear on screen because the loop would stop, but it makes more sense when you remember that we are counting from zero and not one.

So far we have been examining routines purely in theory but I'm sure we are getting to the point where all of you want to start seeing results from your code. From here onwards, we'll be using the C64Asm cross assembler, although the source is fully compatible with the native Turbo Assembler for now. To start you all off I'll just give you the basics of starting it up and we will enter the previous example as source code and show it working.

Because we are now moving into the "real" world of programming the listing is slightly different. First, open a copy of Notepad (or your text editor of choice) and enter the following variation on the code we've seen thus far:

		* = $0900
		ldx #$00
		lda #$01
loop		sta $0400,x
		inx
		cpx #$08
		bne loop
		rts

The only difference is the * = $0900 at the top; this is a command to tell the assembler where we want our code to go (in this case $0900 in memory, which is 2304 in decimal). Now we want to see our code going, so it's time to assemble it. First, save the file out as "test.txt" and then you'll need to navigate into the same directory in DOS and type c64asm test.txt program.prg and you should see the following appear:

	Assembling TEST.TXT
	PROGRAM.PRG created from $9000 to $090c

Now that's a happy bunny, it can be fed to a passing emulator or moved to a real C64 and tested; to try it in WinVICE simply drag the PRG file over to the emulator's window and drop it, then type SYS2304 and voila - your very first machine code program!

Well, that's the second part over with but before you carry on to the next installment I'll leave you with a little challenge. Can you figure out how to change our example to put eleven characters on the screen in the listing above and change them from "A" to "C"? Why not play with the code and see what you can come up with! If you have any questions about this article or machine code in general, contact me and I'll order an economy size tub of rice pudding and come round to yours.

The source code for the routines above can be downloaded here for easier reference.

Content copyright © 2004-2014 Oldschool Gaming     Designed and hosted by Enisoc Design