17 Machine-Code in BASIC

Machine-code subroutines written using the mnemonic assembler can be incorporated into BASIC programs, and several examples are given in the following sections.

17.1 Replace Subroutine

The following machine-code routine, 'Replace’, can be used to perform a character-by-character substitution on a string. It assumes the existence of three strings called R, S, and T. The routine looks up each character of R to see if it occurs in string S and, if so, it is replaced with the character in the corresponding position in string T,

For example, if:

$S="TMP"; $T="SNF"

then the sequence:

$R="COMPUTER" LINK RR0

will change $R to "CONFUSER".

10 REM Replace
20 DIM LL(4),R(20),S(20),T(20)
40 FOR N=l TO 2; DIM P(-1)
50[
60:LL0 LDX @0
70:LL1 LDY @0; LDA R,X
80 CMP @#D; BNE LL3; RTS finished
90:LL2 INY
100:LL3 LDA S,Y
110 CMP @#D; BEQ LL4
120 CMP R,X; BNE LL2
130 LDA T,Y; STA R,X replace char
140:LL4 INX; JMP LL1 next char
150]
160 NEXT N
200 END

The routine has many uses, including code-conversion, encryption and decryption, and character rearrangement.

17.1.1 Converting Arabic to Roman Numerals

To illustrate one application of the Replace routine, the following program converts any number from Arabic to Roman numerals:

10 REM Roman Numerals
20 DIM LL(4),Q(50)
30 DIM R(20),S(20),T(20)
40 FOR N=l TO 2; DIM P(-1)
50[
60:LL0 LDX @0
70:LL1 LDY @0; LDA R,X
80 CMP @#D; BNE LL3; RTS finished
90:LL2 INY
100:LL3 LDA S,Y
110 CMP @#D; BEQ LL4
120 CMP R,X; BNE LL2
130 LDA T,Y; STA R,X replace char
140:LL4 INX; JMP LL1 next char
150]
160 NEXT N
200 $S="IVXLCDM"; $T="XLCDM??"
210 $Q=""; $Q+5="I"; $Q+10="ii"
220 $Q+15="iii"; $Q+20="iv"; $9+25="V" 
230 $Q+30="vi"; $Q+35="vii"
240 Sq+40="viii"; $Q+45="ix"
250 DO $R="";D=10000
255 INPUT A
260 DO LINK LL0
270 $R+LEN(R)=$(Q+A/D*5)
280 A=A%D; D=D/10; UNTIL D=O
290 PRINT $R; UNTIL 0
Description of Program:
Allocate labels and strings 
40-160 Assemble Replace routine.
200	Set up strings of Roman digits
210-240 Set up strings of numerals for 0 to 9.
255	Input number for conversion
260	Multiply the Roman string R by ten by performing a character substitution.
270	Append string for Roman representation for A/D to end of R.
280	Look at next digit of Arabic number.
290	Print Roman string, and carry on.
Variables:
A – Number for conversion
D – Divisor for powers of ten.
LL(0..4) – Labels for assembler routine.
LL0 – Entry point for Replace routine.
N – Counter for two-pass assembly.
P – Location counter.
Q – $(Q+5*x) is string for Roman numeral X.
$R – String containing Roman representation of A.
$S – Source string for replacement.
$T – Target string for replacement.
Program size: 579 bytes.

17.2 Harpsichord

The following program simulates a harpsichord; it uses the central section of the ATOM's keyboard as a harpsichord keyboard, with the keys assigned as follows:

_|_   E R _ Y U I _ P @  
  A S D F G H J K L ; [ ]

where the S key corresponds to middle C. The space bar gives a 'rest', and no other key on the keyboard has any effect.

The tune is displayed on a musical stave as it is played, with the black notes designated as sharps. Pressing RETURN will then play the music back, again displaying it as it is played.

The program uses the Index routine, described in Section 16.3, to look up the key pressed, and a version of the Bleep routine in Section 15.4.1.

1 REM Harpsichord
10 DIM S(23),T(26),F(0)
15 DIM WW(2),RR(2),Z(128)
20 DIM P(-1)
30 PRINT $21
100[\generate NOTE
110:WW0 STA F; LDA @0
120:WW2 LDX F
130:WW1 DEX; NOP; NOP; BNE WW1
140 EOR @4; STA #B002
150 DEY; BNE WW2; RTS
160\READ KEY & LOOK UP IN T
165:RR1 STX F; RTS
170:RR0 JSR #FFE3
180 LDX @25
190:RR2 CMP T,X; BEQ RR1
210 DEX; BPL RR2; BMI RR0
220]
230 PRINT $6
380 X=#8000
390 D=256*#22
393 S!20=#01016572
395 S!16=#018898AB
400 S!12=#01CBE401
410 S!8=#5A606B79
420 S!4=#8090A1B5
430 S!0=#C0D7F2FF
450 $T="ASDFGHJKL;[]?ER?YUI?P@? ?"
460 T?24=#1B; REM ESCAPE
470 CLEAR 0
480 DO K=32
500 FOR M=0 TO 127; LINK RR0
505 IF ?F<>25 GOTO 520
508 IF M<>0 Q=m
510 K=128; GOTO 540
520 Z?M=?F
530 GOSUB d
540 NEXT M
780 K=32
800 FOR M=0 TO Q-1; WAIT; WAIT
810 ?F=Z?M; GOSUB d
820 NEXT M
825 UNTIL 0
830dREM DRAW TUNE
840 IF K<31 GOTO e
850 CLEAR 0
860 FOR N=34 TO 10 STEP -6
870 MOVE 0,N; DRAW 63,N
880 NEXT N
890 K=0
900eIF ?F=23 GOTO s
910 IF ?F>11 K?(X+32*(27-?F))=35; K=K+1
920 K?(X+32*(15-?F%12))=15
930 K=K+1
960 A=S?(?F); Y=D/A
970 LINK WWO
980 RETURN
990sFOR N=0 TO 500;NEXT N
995 K=K+1; RETURN
Description of Program:
100-150 Assemble bleep routine
160-210 Assemble index routine
393-430 Set up note values
450-460 Set up keyboard table
480-825 Main program loop
500-540 Play up to 128 notes, storing and displaying them.
800-820 Play back tune
830	d: Draw note on staves and play note
840-880 If first note of screen, draw staves
900-920 Plot note on screen
960-970 Play note
990-995 Wait for a rest
Variables:
A – Note frequency
D – Duration count
?F – Key Index
K – Column count on screen
M – Counter
N – Counter
P – Location counter
Q – Number of notes entered
RR(0..2) – Labels in index routine
RR0 – Entry point to read routine
S?0..S?23 – Vector of note periods
T?0..T?26 – Vector of keys corresponding to vector S
WW(0..2) – Labels in note routine
WW0 – Entry point to note routine
X – Screen address
Y – Number of cycles of note to be generated
Z(0..128) – Array to store tune.
Program size: 1049 bytes Extra storage: 205 bytes Machine code: 41 bytes
Total size: 1295 bytes

17.3 Bulls and Cows or Mastermind

Bulls and Cows is a game of logical deduction which has become very popular in the plastic peg version marketed as 'Mastermind'. In this version of the game the human player and the computer each think of a 'code', consisting of a string of four digits, and they then take turns in trying to guess the other player's code. A player is given the following information about his guess:

The number of Bulls – i.e. digits correct and in the right position. The number of Cows – i.e. digits correct but in the wrong position.

Note that each digit can only contribute to one Bull or one Cow. The human player specifies the computer's score as two digits, Bulls followed by Cows. For example, if the code string were '1234' the score for guesses of '0004’, '4000', and '4231' would be '10’, '01', and '22' respectively.
The following program plays Bulls and Cows, and it uses a combination of BASIC statements to perform the main input and output operations, and assembler routines to speed up sections of the program that are executed very frequently; without them the program would take several minutes to make each guess.

10 REM Bulls & Cows
20 DIM M(3),N(3),C(0),B(0),L(9)
23 DIM GG(10),RR(10)
25 DIM LL(10)
50 GOSUB z; REM Assemble code
60 GOSUB z; REM Pass Two
10OO REM MASTERMIND *****
1005 Y=1; Z=1
1007 @=2
1010 GOSUB c
1015 G=!M ;REM MY NUMBER
1020 GOSUB c; Q=!m
1030 I=0
1040 DO I=I+1
1050 PRINT "(" I ")" '
1100 IF Y GOSUB a
1150 IF Z GOSUB b
1350 UNTIL Y=0 AND Z=0
1400 PRINT "END"; END
1999***********************************
2000 REM Find Possible Guess
2010fGOSUB c; F=!M
2160wLINK LL7
2165 IF !M=F PRINT "YOU CHEATED"; END
2170 X=1
2180v!N=GG(X)
2190 LINK LL2
2200 IF !C&#FFF<>RR(X) THEN GOTO w
2210 IF X<I THEN X=X+1; GOTO v
2220 Q=!m; RETURN
3999***********************************
4000 REM Choose Random Number
4005cJ=ABSRND
4007 REM Unpack Number
4010uFOR K=0 TO 3
4020 M?K=J%10
4030 J=J/10
4040 NEXT
4050 RETURN
4999***********************************
5000 REM Print Guess
5010gFOR K=0 TO 3
5020 P. $(H&15+#30)
5030 H=H/256; NEXT
5040 RETURN
5999********%**************************
6000 REM Your Turn
6040aPRINT "YOUR GUESS"
6045 INPUT J
6050 GOSUB u
6060 !N=G
6065 LINK LL2
6070 P.?B" BULLS, "?C" COWS"'
6075 IF!C<>#400 RETURN
6080 IF Z PRINT"...AND YOU WIN"'
6083 IF Z:1 PRINT" ABOUT TIME T00!"'
6085 Y=0
6090 RETURN
6999***********************************
7000 REM My Turn
7090bPRINT "MY GUESS:
7100 H=Q; GOSUB g
7110 PRINT ’
7120 INPUT "REPLY" V
7140 RR(I)=(V/10)*256+V%10
7150 GG(I)=Q
7225 IF V<>40 GOSUB f; RETURN
7230 IF Y PRINT"...SO I WIN!"'
7235 Z=0
7240 RETURN
7999***********************************
9000zREM Find Bulls/Cows
9035 PRINT $#15 ;REM Turn off screen
9045 DIM P(-1)
9050[
9055\ find bulls 6 cows for m:n
9060:LL2 LDA @0; LDX #13 ZERO L,B,C
9065:LL3 STA C,X; DEX; BPL LL3
9100 LDY @3
9105:LL0
9120 LDA M,Y
9130 CMP N,Y is bull?
9140 BNE LL4 no bull
9150 INC B count bull
9160 BPL LL1 no cows	i
9165:LL4
9170 TAX not a bull
9180 INC L,X
9190 BEQ LL6
9200 BPL LL5 not a cow
9210:LL6 INC C
9220:LL5 LDX N,Y; DEC L,X
9225 BMI LL1; INC C
9260:LL1 DEY; BPL LLO again
9350 RTS
9360\ increment M
9370:LL7 SED; SEC; LDY @3
9380:LL9 LDA M,Y; ADC @#90
9390 BCS LL8; AND @#0F
9400:LL8 STA M,Y; DEY
9410 BPL LL9; RTS
9500]
9900 PRINT $#6 ;REM Turn Screen on
9910 RETURN
Description of Program:
20-25 Declare arrays and vectors
50-60 Assemble machine code
1010 Computer chooses code
1020 Choose number for first guess
1040-1350 Main program loop
1050	Print turn number
110G	If you have not finished – have a turn
1150	If I have not finished – my turn
1350	Carry on until we have both finished
1999	Lines to make listing more readable.
2000-3999 f: Find a guess which is compatible with all your replies to my previous guesses.
4000-4999 c: Choose a random number
4007-4050 u: Unpack J into byte vector M, one digit per byte.
5000-5040 g: Print guess in K as four digits.
6000-6090 a: Human's guess at machine's number; print score.
7000-7240 b: Machine's guess at human's code.
9000-991O z: Subroutine to assemble machine-code routines
9055-9350 Find score between numbers in byte vectors M and N; return in ?B and ?C.
9360-9500 Increment number in vector M, in decimal, one digit per byte.
Variables:
?B – Number of Bulls between vectors M and N
?C – Number of Cows between vectors M and N
GG(1..10) – List of human's guesses
H – Computer's number
I – Turn number
J – Human's guess as 4-digit decimal number
K – Counter
L – Vector to count occurrences of digits in numbers
LL(0..10) – Labels in assembler routines
LL2 – Entry point to routine to find score between 2 codes
LL7 – Entry point to routine to increment M
!M, !N – Code numbers to be compared
P – Location counter
Q – Computer's guess, compatible with human's previous replies.
RR(1..10) – List of human's replies to guesses GG(1..10)
Y – Zero if human has finished
Z – Zero if computer has finished.
Program size: 1982 bytes
Additional storage: 152 bytes
Machine-code: 223 bytes
Total storage: 2357 bytes
Sample run:
>RUN
( 1)
YOUR GUESS?1122
0 BULLS, 0 COWS
MY GUESS: 6338
REPLY?10
( 2)
YOUR GUESS?3344
0 BULLS, 0 COWS
MY GUESS: 6400
REPLY?20
( 3)
YOUR GUESS?5566
0 BULLS, 0 COWS
MY GUESS: 6411
REPLY?10
( 4)
YOUR GUESS?7788
1 BULLS, 1 COWS
MY GUESS: 6502
REPLY?40
...SO I WIN!
( 5)
YOUR GUESS?

Next chapter