Classic Computer Magazine Archive COMPUTE! ISSUE 40 / SEPTEMBER 1983 / PAGE 224

MACHINE LANGUAGE

Jim Butterfield, Associate Editor

Bagel Break, Part 2

Last month we outlined the logic of a simple machine language program to play "Bagels," a well-known guessing game. Let's pause and look at the various ways we can change our planned program into a real machine language program.
    You may have a tiny assembler that is built into your monitor system. This type of simple assembler is often called a nonsymbolic assembler for reasons we'll discuss in a moment. If so, you'll work out all the addresses yourself and write them in as you jot down the program coding. The type of outline you write will be similar to that in Program 2. You'll need to guess at some of the "forward" branches; at the time you write the branch instruction, you won't know what the exact destination address will be. No matter, as long as you remember to put the correct addresses in later.
    You may have purchased a full-scale assembler, in which case you'll write the program as shown in Program 1. It's still the same logic flow, but now we can give a name (or "symbolic address") to the various parts of the program. We'll let the assembler figure out where these locations are and compute the correct branch for us. This type of assembler, where we can name locations with symbolic names, or "labels," is often called a "symbolic assembler" to distinguish it from the simple assemblers mentioned previously.
    Symbolic names, or labels, seem like a convenience feature at first: not too important, but handy. In fact, they change the nature of the work in a couple of ways. First, we now have the freedom to give meaningful names to our program and work locations. The program is easier to read. Second - and this can be very powerful - we can move the logic to an entirely new part of memory with very little work; the assembler will figure everything out for us. Perhaps most important of all: if we wish to change or correct the program, we can do so without needing to type everything in again; the "source" coding will be saved on a file and may be recalled and corrected as desired.
    In whatever fashion we write our program outline, we'll still need to change it into machine language. We may use an assembler - symbolic or nonsymbolic - or we might do the job by hand. Program 3 shows the output from a typical assembly. It's full of information, but the only data that really count are the two-digit hexadecimal numbers found to the left of the printout. (The four-digit hex numbers at the extreme left are addresses, to help you know where the code is located.)
    An assembly listing is a rich source of information, especially if it's well commented. But the business end - the two-digit hex numbers - is all that is needed to do the job. Those numbers are all that we need to put into the computer. Program 4 shows a hexadecimal dump of memory with the program in place. All the pretty trimmings from the assembly listing are gone. All that we have are the instructions, ready to go to work. That's probably the way we would type them in, using the screen-editing feature of the machine language monitor to change memory until it looked like Program 4.
    But our game isn't completed yet. We need to generate the mystery numbers from BASIC, and tie all the pieces together. Next time....

Program 1:
Code As Prepared For A Full Assembler

NGUESS =$0240    ;number of guesses
EXACT  =$0241    ;exact count
MATCH  =$0242    ;other match count
INCHAR =$0243    ;input character count
SECRET =$0244    ;secret code
SCOPY  =$0248    ;copy of secret code
UGUESS =$024C    ;user's guess
       *= $033C  ;start program here
       ; start game
START  LDA #$00    ; guesses to zero
       STA NGUESS
       ; accept next guess
GUESS  INC NGUESS     ; count the guess
       LDA NGUESS     ; look at it
       CMP #10        ; over nine?
       BEQ QUIT       ; yup, quit
       JSR PLAY       ; take guess
       BNE GUESS      ; not finished? back
QUIT   RTS            ; end of game
       ; get guess & play
PLAY   ORA #$30       ;ascii numeric
       JSR $FFD2      ; .. print
       LDA #$20       ;ascii space
       JSR $FFD2      ; print it
       ; set counts to zero
       LDX #0
       STX EXACT
       STX MATCH
       STX INCHAR
       ; get 4 character guess
INLOOP JSR $FFE4      ; get char
       CMP #$41       ; less than A
       BCC INLOOP
       CMP #$47       ; over F
       BCS INLOOP     ; reject it
       JSR $FFD2      ; OK, print it
       LDX INCHAR     ; get position
       INC INCHAR     ; bump position
       STA UGUESS,X   ; store character
       LDA SECRET,X   ; copy secret char
       STA SCOPY,X    ; .. to copy area
       CPX #3         ; four chars?
       BNE INLOOP     ; nope, go back
       ; check guess for exact matches
COMPAR LDA SCOPY,X    ; test character
       CMP UGUESS,X   ; against guess
       BNE SKIP       ; nope, try next
       INC EXACT      ; yes, count it
       LDA #0         ; and wipe out..
       STA SCOPY,X    ; .. matching ..
       STA UGUESS,X   ; .. characters
SKIP   DEX
       BPL COMPAR
       ; check for out-of-place matches
       LDY #$00       ; first secret char
RETRY  LDX #$00       ; first guessed char
CHECK  LDA SCOPY,Y    ; is character wiped?
       BEQ PASS       ; yes, ignore next bit
       CMP UGUESS,X   ; compare it to guess
       BNE PASS       ; nope, move on
       INC MATCH      ; yup, count it
       LDA #$00       ; and wipe out..
       STA SCOPY,Y    ; .. matching ..
       STA UGUESS,X   ; .. characters
PASS   INX            ; next guessed character
       CPX #4         ; tried them all?
       BCC CHECK      ; no, try next one
       INY            ; next secret character
       CPY #4         ; tried them all?
       BCC RETRY      ; no, keep going
       ; print results
       LDX #0         ; start at 'exact'
PLOOP  LDA #$20       ; print a space
       JSR $FFD2
       LDA EXACT,X    ; get the number
       ORA #$30       ; to ascii numeric
       JSR $FFD2      ; and print
       INX            ; move to 'match'
       CPX #$02       ; too far?
       BCC PLOOP      ; nope, keep printing
       LDA #$0D       ; print 'return'
       JSR $FFD2
       LDA EXACT      ; four exact?
       CMP #4         ; if so, set z flag
       RTS



Program 2:
Code As Prepared For
A Tiny Assembler

(033C) LDA #$00
       STA $0240
(0341) INC $0240
       LDA $0240
       CMP #10
       BEQ $0350
       JSR $0351
       BNE $0341
(0350) RTS
(0351) ORA #$30
       JSR $FFD2
       LDA #$20
       JSR $FFD2
       LDX #$00
       STX $0241
       STX $0242
       STX $0243
(0366) JSR $FFE4
       CMP #$41
       BCC $0366
       CMP #$47
       BCS $0366
       JSR $FFD2
       LDX $0243
       INC $0243
       STA $024C,X
       LDA $0244,X
       STA $0248,X
       CPX #$03
       BNE $0366
(0387) LDA $0248,X
       CMP $024C,X
       BNE $0394
       INC $0241
       LDA #$00
       STA $0248,X
       STA $024C,X
(039A) DEX
       BPL $0381
       LDY #$00
(039F) LDX #$00
(03A1) LDA $0248,Y
       BEQ $03B0
       CMP $024C,X
       BNE $03B0
       INC $0242
       LDA #$00
       STA $0248,Y
       STA $024C,X
(03B6) INX
       CPX #$04
       BCC $039B
       INY
       CPY #$04
       BCC $0399
       LDX #$00
(03C2) LDA #$20
       JSR $FFD2
       LDA $0241,X
       ORA #$30
       JSR $FFD2
       INX
       CPX #$02
       BCC $03BC
       LDA #$0D
       JSR $FFD2
       LDA $0241
       CMP #$04
       RTS



Program 3: Code As Assembled By A Full Assembler

             NGUESS =$0240    ;number of guesses
             EXACT  =$0241    ;exact count
             MATCH  =$0242    ;other match count
             INCHAR =$0243    ;input char count
             SECRET =$0244    ;secret code
             SCOPY  =$0248    ;copy secret code
             UGUESS =$024C    ;user's guess
                    *= $033C  ;start program here
                                    ; start game
033C A9 00    START  LDA #$00       ; guesses, zero
033E 8D 40 02        STA NGUESS
                                    ;accept next guess
0341 EE 40 02 GUESS  INC NGUESS     ; count guess
0344 AD 40 02        LDA NGUESS     ; get it
0347 C9 0A           CMP #10        ; over nine?
0349 F0 05           BEQ QUIT       ; yup, quit
034B 20 51 03        JSR PLAY       ; take guess
034E D0 Fl           BNE GUESS      ; not finished?
0350 60       QUIT   RTS            ; end of game
                                    ;get guess & play
0351 09 30    PLAY   ORA #$30       ;ascii numeric
0353 20 D2 FF        JSR $FFD2      ; .. print
0356 A9 20           LDA #$20       ;ascii space
0358 20 D2 FF        JSR $FFD2      ; print it
                                    ;set counts to zero
035B A2 00           LDX #0
035D 8E 41 02        STX EXACT
0360 8E 42 02        STX MATCH
0363 8E 43 02        STX INCHAR     ; get 4 character
                                      guess
0366 20 E4 FF INLOOP JSR $FFE4      ; get char
0369 C9 41           CMP #$41       ; less than A
036B 90 F9           BCC INLOOP
036D C9 47           CMP #$47       ; over F
036F B0 F5           BCS INLOOP     ; reject it
0371 20 D2 FF        JSR $FFD2      ; OK, print it
0374 AE 43 02        LDX INCHAR     ; get position
0377 EE 43 02        INC INCHAR     ; bump position
037A 9D 4C 02        STA UGUESS,X   ; store
                                      character
037D BD 44 02        LDA SECRET,X   ; copy secret
                                      ch
0380 9D 48 02        STA SCOPY,X    ; .. to copy
area
0383 E0 03           CPX #3         ; four chars?
0385 D0 DF           BNE INLOOP     ; nope, go back
                                    ; check guess for
                                      exact matches
0387 BD 48 02 COMPAR LDA SCOPY,X    ; test
                                      character
038A DD 4C 02        CMP UGUESS,X   ; against guess
038D D0 0B           BNE SKIP       ; nope, try
                                      next
038F EE 41 02        INC EXACT      ; yes, count it
0392 A9 00           LDA #0         ; and wipe
                                      out..
0394 9D 48 02        STA SCOPY,X    ; .. matching
                                      ..
0397 9D 4C 02        STA UGUESS,X   ; .. characters
039A CA       SKIP   DEX
039B 10 EA           BPL COMPAR
                                    ; check for matches
039D A0 00           LDY #$00       ; first secret
039F A2 00    RETRY  LDX #$00       ; first guessed
03A1 B9 48 02 CHECK  LDA SCOPY,Y    ; char wiped?
03A4 F0 10           BEQ PASS       ; yes, ignor
03A6 DD 4C 02        CMP UGUESS,X   ; compare
03A9 D0 0B           BNE PASS       ; nope, move on
03AB EE 42 02        INC MATCH      ; yup, count it
03AE A9 00           LDA #$00       ; and wipe
                                      out..
03B0 99 48 02        STA SCOPY,Y    ; .. matching
                                      ..
03B3 9D 4C 02        STA UGUESS,X   ; .. characters
03B6 E8       PASS   INX            ; next guess
03B7 E0 04           CPX #4         ; tried all?
03B9 90 E6           BCC CHECK      ; no, try next
03BB C8              INY            ; next char
03BC C0 04           CPY #4         ; tried all?
03BE 90 DF           BCC RETRY      ; no, keep on
                                    ; print results
03C0 A2 00           LDX #0         ; first numbr
03C2 A9 20    PLOOP  LDA #$20       ; print space
03C4 20 D2 FF        JSR $FFD2
03C7 BD 41 02        LDA EXACT,X    ; get number
03CA 09 30           ORA #$30       ; to ascii num.
03CC 20 D2 FF        JSR $FFD2      ; and print
03CF E8              INX            ; move on
03D0 E0 02           CPX #$02       ; too far?
03D2 90 EE           BCC PLOOP      ; nope, loop
03D4 A9 0D           LDA #$0D       ; print return
03D6 20 D2 FF        JSR $FFD2
03D9 AD 41 02        LDA EXACT      ; four exact?
03DB C9 04           CMP #4         ;  z flag
03DD 60              RTS



Program 4:
Hexadecimal Dump Of Memory

C*
     PC  IRQ  SR AC XR YR SP
.;  B780 E455 2C 34 3A 9D F8
.
.:  033C A9 00 8D 40 02 EE 40 02
.:  0344 AD 40 02 C9 0A F0 05 20
.:  034C 51 03 D0 F1 60 09 30 20
.:  0354 D2 FF A9 20 20 D2 FF A2
.:  035C 00 8E 41 02 8E 42 02 8E
.:  0364 43 02 20 E4 FF C9 41 90
.:  036C F9 C9 47 B0 F5 20 D2 FF
.:  0374 AE 43 02 EE 43 02 9D 4C
.:  037C 02 BD 44 02 9D 48 02 E0
.:  0384 03 D0 DF BD 48 02 DD 4C
.:  038C 02 D0 0B EE 41 02 A9 00
.:  0394 9D 48 02 9D 4C 02 CA 10
.:  039C EA A0 00 A2 00 B9 48 02
.:  03A4 F0 10 DD 4C 02 D0 0B EE
.:  03AC 42 02 A9 00 99 48 02 9D
.:  03B4 4C 02 E8 E0 04 90 E6 C8
.:  03BC C0 04 90 DF A2 00 A9 20
.:  03C4 20 D2 FF BD 41 02 09 30
.:  03CC 20 D2 FF E8 E0 02 90 EE
.:  03D4 A9 0D 20 D2 FF AD 41 02
.:  03DC C9 04 60
.