Beginning ML #2
by Craig Taylor (duck@pembvax1.pembroke.edu)

  Last time we introduced the definition of what exactly Machine Language / 
Assembly Language is along with an example of clearing the screen in Machine
Language.

  Now, in this issue let's print my name (and later your name). Looking at the
code from last time the following assembly source jumps to mind:

------------ 
print_1.asm:

          lda #147         ; clr/screen code
          jsr $ffd2        ; print
          lda #'C'         ; code for ascii "C"
          jsr $ffd2        ; print
          lda #'r'    
          jsr $ffd2
          lda #'a'
          jsr $ffd2
          lda #'i'
          jsr $ffd2
          lda #'g'
          jsr $ffd2
          lda #32          ; code for space 
          jsr $ffd2
          lda #'T'         ; print my last name....
          jsr $ffd2
             .
               .            (ad naseum...)    
                 .        
          rts
----------

  Now, for short strings like "HI!" that might be fine but if your name is 
something like "Seymour Johnson the third" it can get a little bit ridiculous
in terms of the amount of memory and the amount of typing (eegh! - typing!) 
involved. There's an easier way.
  
  It's called indexed addressing. What is this you say? Let's first take a 
look at the above program using indexed addressing and then explain it.

------------ 
print_2.asm

          ldy #$00
   loop   lda string,y
          jsr $ffd2
          iny
          cpy #numchars
          bne loop
          rts

 string   .byte 147
          .ascii "Craig Taylor"

 numchars = *-string

------------

  Hmm, looks a little bit confusing 'eh?

  What we're doing is using the register y to act as a pointer to grab the 
y'th character in what is at memory location STRING. If y is 0 then we'll get
string+0 which happens to be a 147.

  The .byte and .ascii directives are not real instructions the computer
understands. What happens is that your assembler sees that you want data
put at those locations so it convert 147 and "Craig Taylor" to numbers
and puts them at the proper locations, relieving you the burden of doing it.

   The numchars = *-string looks confusing at first... obviously, numchars
stands for the number of characters we need to print out but how is it being
figured?  Most assemblers keep the current location in memory it's assembling
to in something called a program counter of PC.  Most assemblers also will let
you have the value at assembly time by referencing it using the "*" symbol.
"string" is already a symbol that has been set an address in memory and after
assembling the .byte and .ascii instruction "*" will be equal to the next 
address that the assembler would put any instructions at, had we had any.
Now, *-string basically is saying to the compiler, look, take the current 
program counter (where it's assembling to) and subtract it from where the 
symbol string starts at (which it just assembled a while back). This should
be then, our number of characters we have.

WALK-THROUGH:

  Register Y is initially set to zero in the first instruction, as we want to
begin with the first character. The first character is at string+0, not 
string+1. This may seem a little bit odd at first, but try thinking of it this
way:

     Take, for example, 3 diskettes. Put them in a row and call the one on the
     left "string" (or some other name). Then point at "string+1", "string+2"..
     Notice there's no "string+3" even tho' there's 3 diskettes?  This may 
     seem a little bit strange at first, but after thinking about it a while
     you'll begin to understand. In machine / assembly language, you typically
     count starting from zero, in the real world, typically from one.

  The lda string,y instruction is telling the computer to reference string as 
if it was an array, get the byte at location string + y, or for you basic
programmers thinking of string as an array of bytes (with no bounds checking)
string[y]. Thus, the accumulator is equal to the yth byte starting from
the location string is defined to be.

  We then call the routine Commodore so graciously provided for us that prints
out the contents of the accumulator. Now, some routines, as we'll see in other
editions, are not so nice and may change the value of the accumulator, the 
x and y registers. However, Commodore was extra nice and the routine at $ffd2 is
guaranteed not to change any of the registers.
 
  The routine then "iny".  What is this? It "INcrements the Y register". INX 
will "INcrement the X register".  The X and Y register can not have any math
performed on them other than increment and decrement operations (ie: adding
one and subtracting one).   The only register that allows addition or
subtraction is the accumulator. However, in this case we just want y to point
to the next character, the next byte so "INY" serves us fine.
  
  We then "ComPare Y" register to the number of characters in the string. Notice
the # sign. If we hadn't have had that there, it would've tried to look at 
whatever memory location numchars was defined for. Numchars was set up to hold
the number of characters in the string, not be a pointer for a memory location.

  Now that we've compared it, we "Branch if the last comparison was Not Equal"
back to where loop is at (in this case, where we load a with character again).

  If it was equal we fall through to the RTS where we return from our little
program.

  Basically, we've got something like the following flowchart:
                  _______
                 / START \
                 \_______/
                    |
                   \|/
                +-----------------+
                | Set Index (Y)   |
                | first character | 
                +-----------------+
                    |
                   \|/
                +-------------------+
                | Get the character | /
                | pointed to by     |<------------------+
                | the index(Y)      | \                 |
                +-------------------+                   |
                    |                                   |
                   \|/                                  |
                +-------------+                         |
                | Print it    |                         |
                +-------------+                         |
                    |                                   |
                   \|/                                  |
                +------------------------+              |
                | Increment the Index(Y) |              |
                +------------------------+              |
                    |                                   |
                   \|/                                  |
                    /\                                  |
                   /= \                                 |
                  /# of\                                |
                 /chars?\                               |
                /to print\___no,not =_____------------->+
                \???     /
                 \      /
                  \    /
                   \  /
                    \/
                     |
                    \|/
                    _____
                   / END \
                   \_____/

  Indexed addressing is used *very* often in assembly language.  Try playing 
with the second program and experiment with it until you understand fully what
is going on.  Next time we'll look at how to access some of the diskette 
routines and to display a file on disk.

