What is to come

Before we cover how to write messages (or text) on your screen, we will need to learn how to use the X, Y registers. This is a key component and is usually frequently in all assembly language programs.  It allows you to run loops that can write data values to sprite memory, create animation, and lots of other things.

Therefore, I have divided the following lessons into explaining how use the index registers, the transfer X/Y registers, the arithmetic operators, the jump(subroutine) commands, and  the X/Y accumulators. Understanding these mnemonics we give you some powerful tools to use as you begin evolving your grasp on assembly language.

THE INDEX REGISTERS

We will now be covering the X index register. This is an important register in the microprocessor. Keep in mind that there is also a Y register, which we will cover below in the example part. These two registers are 8 bit ones and can contain a maximum number ranging from 0 to 255 ($00 – $ff). They function similar to the accumulator, but mostly used as counters (known as “indexing”). If you think about Basic they are nearly identical to the FOR/NEXT loops when combined with branching (to be discussed later). The contents of the register is used as an index or offset to an address. If the register value is “1” then “1” is added to a specified address. They can be used to also cycle through memory locations. This is handy when you want to print a line of text or characters to Commodore 64’s screen memory (which we will review further ahead). They can also be used as temporary storage.

You can think of the index registers like a counter. It keeps track of a series of numbers that get passed into registers (X and Y). If you recall the LDA it is very similar in the sense that it is copying the value from the X register or the Y register and placing into an area that can be used for later. Once this copy has taken place, then the values can be passed into memory locations to produce results. Let’s first example an Excel graph to understand this at the machine language level and then we’ll move on to a program example. We will also be covering loops in this tutorial or otherwise the example won’t make any sense. Excuse some of the advanced leaps here, but as you may recall machine language is not easy to grasp and will take multiple iterations to get moving along at a comfortable pace. For now though we will see a loop example and write some text to the screen shortly.

LDX

LDX (Load index register X with data or from a specified address)

It copies data to the X register or copies from a memory location. The data in the memory location copied still remains intact afterward.

Example:             ldx #$03               ; Put a 3 the X register – X=3

                                ldx $30               ; Put the data found in memory location 48 in the x register

Basic:                     X=PEEK (48)

Commodore 64 Screen Memory

Before we learn more about the functionality of LDX and other instructions it is vital that we first grasp a complete picture of how your Commodore 64 system views something known as “screen memory”. Screen memory consists of all the dots you can see on your computer screen. If you peer closely you will see them. These “dots” are often referred to as “pixels”.

A raster beam scans from left to right to make up the entire screen. When the beam arrives at the right side, it is shut off and then turned on again for the next line. This process repeats until the synchronization is complete and your C64 screen appears in its complete glory! Look at the image carefully for the VICE C64 emulator and you will see the dots as they are arrayed. To give you a closer perspective, I have utilized Photoshop to enlarge the VICE C64 screen so you can see it up close and personal. Look at the letters and you should easily see the dots now (excuse any distortion – blame VICE C64 if you want to).

Hence, the screen starts at the top left corner of the screen at memory location 1024 ($0400) to the bottom right corner at memory location 2023 ($07e7). If you start at 0 and count the locations it is a total of 999. Each area contains a size of 8 x 8 = 64 (pixels) – in total. This is referenced to the MPU as 999 bytes of memory. Technically, we need to say 1000 bytes since as mentioned it counts from 0-999 (starting with “0” as 1 up to 1000 in total.

C64 Screen MemoryTo simplify this even further, let’s examine another visual example to see the screen divided into all 1000 bytes. I found this guide online at the website www.commodore.ca/manuals/128_system_guide/app-f.htm. This can also be found in the back of the owners manual called Commodore 64C Personal Computer system guide Learning to program in BASIC 2.0 in Appendix E, page 167.  Each row starts at the left hand side and counts over 40 bytes (spaces). So if you count from 1024-1063 = 40 bytes. Be sure this time to start at 1 and count up to 40. If you don’t believe me, you are free to count the graph spaces yourself. Essentially here to be clear you will count as the C64 sees it, starting at 1024, 1025, 1026, etc.

The Index Registers (Visually)

Index RegistersNow we are going to examine the Index Registers using data entered in an Excel spreadsheet. Looking at the cell columns you will see columns for decimal, hex, Memory (Pet Ascii), hex mem, Screen, Screen hex, and Display. This breaks down the decimal, hex, what it looks like in the C64’s memory, how it appears in hex memory, the screen memory locations, the screen in hex, and the output display. This is compacted from the line that shows “message text” with ‘Commodore 64’ showing in that area. The general idea here is to gauge an understanding of how text is translated to the computer’s memory up close and personal.

Understanding LDX

So let’s throw that earlier example back up on the screen again to stay consistent with our evaluation of LDX. As learned previously, LDX stands for “Load Index X with memory”). As per the other instructions, LDX also can affect various flags in memory. These are referenced as N (Negative), Z (Zero), C (Carry), I (Interrupt), D (Decimal), and V (Overflow). We studied these intensely earlier in our tutorial, but I got some suggestions to explain when they are being affected and I will be mentioning that in the code sample below for extreme clarity. Finally let’s get to work with that example. I have listed it here.

Example:             ldx #$03               ; Put a 3 the X register – X=3

                                lda  #$30               ; Put the data found in memory location 48 in the accumulator

                                sta  $33c               ; Put the value $30 in memory location $33c (828)

register

Basic:                     X=PEEK (48)

Status FlagsAs we study the first instruction it is read as “Load the X register with the immediate value of three in the accumulator’s memory and increase the program counter by two bytes”. Therefore if we now examine the status registers (using the Debugger). Go ahead and enter the code into CBM Prg Studio. Next go to the Debugger menu and choose Debug Program. After this the familiar Debugger window will appear. It has loaded the bytes into the screen. Now to get the results of the processor registers, press the execute button (green arrow). When it finishes you will see the status flags affected at the top. I have listed them here for scrutiny.

Inspecting the flags

In close surveillance here you will see the registers and flags affected by the simple instruction LDX #$03. PC (Program counter) started at $1000 and cleared to 0000 since the execution ended.  The X (XR) register was changed to 3. YR (Y Register) will be defined soon, but not changed here. SP (stack pointer) is not used yet, so it remains idle at 0.  SR (status register) confirms the condition of the flags.

Now  as we audit the processor status registers and their flags we see the values of 00110100. Peering above these values you will see the NV-BDIZC – N)egative,V(Overflow),(D)ecimal, (I)nterrupt,(Z)ero, and (C)arry flags.  Looking at them from left to right we learn that the Negative flag was not changed since we didn’t encounter any negative values. The Overflow flag was unaffected since we are not doing extreme arithmetic yet. The center (-) flag is ignored. The Break flag flipped on since we encountered a break (BRK) instruction at the end. The Decimal flag has not been altered because we are using integers only and have not set the flag (possibly to be reviewed later when we work with arithmetic). The Interrupt flag was set here since “1” states that we have not turned off any interrupts (to be studied much later when we get to rasters (my favorite). The Zero flag was not set since our number is greater than 0. Finally the Carry flag was not touched because we are not doing any math yet.

Status FlagsNow let’s move onto the next instruction for lda #$30. This read as “Load the Accumulator with the immediate value of 48 ($30 – hex) in memory. Now enter the new instruction for lda #$30 after the first instruction of ldx #$03.  As usual debug the program and activate the Debugger (clicking Debug – Debug Program). When the Debugger window occupies your screen execute the code with the green arrow again.  Since we have some different results again, I have appended the screenshot above for reference.

This time the analysis reads as PC (Program Counter) is 0000 since the memory location reset itself after completion of the code scan. The AC (Accumulator) now contains $30 (48) since we used LDA #$30 to “Load the 48 into memory”. The XR (X Register) displays $03 again. YR (Y Register) is skipped once more. The SP is at $34. Next reviewing the registers NV-BDIZC we discover that all flags  remain the same as before.

Finally we have arrived at the last instruction for sta $33c which reads “Store the accumulator with the absolute value of $33c found in memory”. Technically speaking, this is staring at memory location $33c (828) to see the value that was placed there earlier by the lda (Load) command, which we know is $30 (48). In Basic terms it reads as POKE 828, 48.

Following our specific pattern here again (going from left to right) the status registers are exactly a replicate since we haven’t changed any of the flags with the newly added lines.

Hopefully this sheds some light on how the accumulator is working in conjunction with the flags as each instruction is reviewed by the computer (known as a compilation). As you begin to sink your skills in writing and reading machine code, you will soon become a guru at understanding how the computer thinks. This is key to overcoming serious tangles that can occur when writing massive lines of code and is a must for any assembly language developer that wants to become an expert in given time.

Writing a simple loop

Now we are going to combine more instructions and learn some new commands so we can continue to expand our view of machine language programming. It is going to get intense, but enjoy the ride because the rewards are coming.

So far in this session we have learned about the LDX and how to pass values to read them to memory. Now I’m going to be introducing a new instruction called INX. As per the norm, let’s review the table again to get familiar with the concepts, addressing mode, cycles, etc.

INX

INX

Audibly this instruction is read as “Increment the X Register”. It only reserves 1 byte of memory and uses up two cycles. Don’t underestimate this instruction for its limitations however, it is quite powerful and widely used throughout a machine language project. The purpose of this register works in connection with LDX that we learned about earlier. It is time for another simple program example to digest this in small increments to prevent “overload” as I was advised.

Example:

                * = $1000

ldx #$00               ; Put a 0 the X register – X=0

inx                          ; Increment the x register by 1 value

Now to keep in check with how the Commodore 64 system reads this at the lower level, it is necessary to enter it into CBM Prg Studio and run it in Debug mode again.  After this is done we will be monitoring the registers and status flags again. To keep everyone on board, a screenshot has been embedded into this paragraph segment once more. The only real significant difference this time around is that the AC (Accumulator) has been set to $00, the XR (X Register) and has been set to $01 for the first part. Beyond this, the SP (Status processor) is showing $fe and SR (status register) reflects $34. However, our status flags mirror the same comparison as before.

Hopefully it has dawned on you that the AC was set to “00” because of the LDX #$00 and the XR was set to $01 because of the increment of the X Register. Did you miss that? Here’s what is going on at an elementary level. Since we started the program off by “Loading the X Register with the immediate value of 00” (zero), the next instruction that reads “Increment the X Register”, has added a one to the zero. Mathematically speaking it is taking 0 + 1 = 1. That is basically it. The INX increases the value found in the X register by one each time.

Okay brace yourself because we are expanding the program even larger now. It is the only way to improve your skills. It’s called “getting your feet wet”. Now that we got some simplicity out of the way, it is time to start creating the program that will create a loop. A loop is essentially called such because it will repeat previous instructions until it gets a result or crashes.

Creating the program loop

The first instruction will remain the same as before. So we are going to erase the program and add LDX #$00. This is important because we want to start the loop at zero so we can count up. The central idea behind this program will be to write a message on the Commodore 64 screen that says “Commodore 64”. If you recall the earlier Excel chart, this was included to demonstrate the various parts that make up the characters that spell “Commodore 64”. If you had to analyze them individual by bytes it would look like this instead.

C             O             M            M            O             D             O             R             E              6              4

I spaced it out in hopes of planting an understanding that each of these is counted separately. If you start with the “C” that would be 0. So essentially the LDX #$00 is actually pointing to the first “C”. Then if you add the INX it would in essence point at the “O”. Okay finally let’s learn a new command. Actually you saw this much earlier in the tutorial, but now we are going to put into practice when this routine is complete.

Sample program:

                * = $1000

ldx #$00               ; Put a 0 the X register – X=0

loop

                                lda message,x                   ; Increment the x register by 1 value

Okay this is going to require some forethought since we haven’t finished the program and are breaking this down in sections. So on the next line of our program we are presented with a single word that says “loop”. This is actually called a “label” or a pointer. What it does is occupy a byte in memory that we can refer back to at that specific address. Since we started the program counter at $1000 (* = $1000), the Commodore 64 system begins to assign each instruction in memory. You could also think of it like when the computer reads the instruction ldx #$00 it reserves two bytes in memory. Then we it gets to the next line that says “loop”, it makes room for just one byte of memory.  So the label of $1000 is actually pointing to memory location $1002. If you were in Basic, you would use A=PEEK(4098) , which is the same.

Our New LDA instruction

Okay finally we can evaluate the instruction lda message,x. It reads as “Load the accumulator with message at X Register in memory”. Currently we haven’t defined any area in memory yet for “message”. Eventually it will be using a pointer (just like our loop label) and grabbing bytes in that area. For now though, I felt it necessary to break it down. So it reads the memory location that is occupied by “message” and then it appends the X register to it. What this is actually doing is the start of a Basic FOR/NEXT loop.  As we add more code to our example, it will unravel more for you. At least that is the plan. Time for a new line.

Example:

                * = $1000

ldx #$00               ; Put a 0 the X register – X=0

loop

                                lda message,x                   ; Increment the x register by 1 value

                                sta $0400,x                          ; Store X into memory location $0400

As we continue to progress, we now arrive at the new instruction that shows sta $0400,x. If you recall our earlier example when STA (Store Accumulator in Memory) was used in Part 3, you may remember that this command will store the contents of the value previously in the accumulator in the parameter listed after STA. This time the sta $0400, x reads as “Store $0400 into the X Register”. It is actually pretty identical to the earlier lda message,x in some aspect. While the earlier instruction reads a series of bytes occupied by the memory space holder pointing to “message”, the sta $0400,x will take the bytes that were loaded from the message area and transfer them into memory starting at $0400. So in Basic this would look like POKE 1024 + x, message. Normally in Basic we would utilize a READ command to grab a stack of bytes (data as it is referred to). In machine language however, we are pulling these from memory locations where they will be stored soon.

Our train of a program is ready to add a new boxcar. Let’s watch the program blossom further.

Example:

                * = $1000

ldx #$00               ; Put a 0 the X register – X=0

loop

                                lda message,x                   ; Increment the x register by 1 value

                                sta $0400,x                          ; Store X into memory location $0400

                                inx                                          ; Increment the X Register by 1

Okay since we reviewed how INX works in our sample program, I feel safe enough to introduce the next instruction. Just recall that INX increases the X register by one that was previously placed in the accumulator. The next instruction is presented below.

Example:

                * = $1000

ldx #$00               ; Put a 0 the X register – X=0

loop

                                lda message,x                   ; Increment the x register by 1 value

                                sta $0400,x                          ; Store X into memory location $0400

                                inx                                          ; Increment the X Register by 1

                                cpx #$c                                 ; Compare the X Register with the immediate value

It is time once again to present a new chart so we can discuss the importance behind our new instruction. Normally I could list the entire program and then return to breaking down its parts later, but I am trying to be primitive in my approach to your learning style.

CPX

CPX

Our new instruction this time reads as “Compare the X Register”. The purpose of a CPX is to assess the value (or number) that is accumulator contained in the X Register in memory. It is used to mark a condition based on the value that exists currently there. Let’s add the new instruction for CPX #$c. This is actually checking in X Register to see if the value of $0c is contained there. So it reads completely as “Compare the X Register with the immediate value of $c (12). Let’s get the new lines.

Example:

                * = $1000

ldx #$00               ; Put a 0 the X register – X=0

loop

                                lda message,x                   ; Increment the x register by 1 value

                                sta $0400,x                          ; Store X into memory location $0400

                                inx                                          ; Increment the X Register by 1

                                cpx #$c                                 ; Compare the X Register with the immediate value

                                bne  loop                             ; If branch isn’t equal, go to loop

We have arrived at the instruction that states bne loop. In machine language terms it is actually saying “Branch not equal loop”. Let me stretch that out more for more revelation. We rewrite it to pitch “Branch to loop if not equal to zero”. Ahh, it is making more sense now… I hope. So the program is nearly finished. Okay onto the next statement and when its done I will explain it in whole.

Example:

                * = $1000

ldx #$00               ; Put a 0 the X register – X=0

loop

                                lda message,x                   ; Increment the x register by 1 value

                                sta $0400,x                          ; Store X into memory location $0400

                                inx                                          ; Increment the X Register by 1

                                cpx #$c                                 ; Compare the X Register with the immediate value

                                bne  loop                             ; If branch isn’t equal, go to loop

                                rts                                           ; Return from subroutine

Alright we finally got an easy one. Let me jog your memory when I read how it is perceived to the Commodore 64 system. It states “Return from Subroutine”. What it is actually doing is signaling to your computer that this program routine has finished its task. You will use an RTS whenever you want to end a program or exit from a routine. This is strikingly identical to the Basic command GOSUB. Like an RTS, whenever Basic trips over a RETURN this it knows that subroutine is done and it is time to return back to the line under the previous GOSUB.

The Complete Program

Finally we see the whole picture fading into view. So now I will list the entire program and entrance the last segmented piece to get this loop underway!

Example:

                * = $1000

ldx #$00               ; Put a 0 the X register – X=0

loop

                                lda message,x                   ; Increment the x register by 1 value

                                sta $0400,x                          ; Store X into memory location $0400

                                inx                                          ; Increment the X Register by 1

                                cpx #$c                                 ; Compare the X Register with the immediate value

                                bne  loop                             ; If branch isn’t equal, go to loop

                                rts                                           ; Return from subroutine

message text “Commodore 64”

Recall earlier when we reviewed the lda message, x. The last part of this program shows message text “Commodore 64”. Keep it fresh in your mind that the earlier “loop” label occupied a byte in memory where a pointer resides. So the word “message text “Commodore 64” is doing something close in comparison. There are more bytes that exist here because of the quotes surrounding the “Commodore 64”. So the message serves as a place holder for a memory location that triggered off of the start of the program loop at $1000 (4096). The ‘text’ just tells this label that the next parameter following this will be in a text form. Finally we see the message that says “Commodore 64”. If you remember the graph that was given earlier, the system will count each individual letter starting with the ‘C’, ‘O’, ‘M’ and so on until it reads the final quote and that word is complete.