.........1.........2.........3.........4.........5.........6.........7.........8
Mastering Machine Code on Your Spectrum
part 5 of 8 - from ZX Computing Jun/Jul'83
Machine code master, Toni Baker, shows you how to
incorporate machine code within your BASIC programs with an
incredible program to add visual accompaniment to your
stereo.
I'd like to cheat a bit now, if I may, by giving you a BASIC
program. (Shrieks of horror!) Well, it has got some machine
code in it, but nothing new. This is a lesson in how to
incorporate machine code into BASIC, for finding a use for
all these weird and wonderful routines that keep cropping
up. Almost the hardest task you have in programming is the
hanging around at bus stops and tedious dinner parties
waiting for that most illusive of qualities - inspiration.
The machine code routine in question was featured in part
three of this series of articles - it's a routine to change
the colours of PAPER and INK throughout the whole screen
faster than you can say 'The sixth sick sheik's sixth
sheep's sick' without falling over. The BASIC that surrounds
it is new, however. This is a program to impress your next
door neighbours and fanatics of laser shows, or a new way of
running a disco. This is visual accompaniment to your
stereo!
Sound's great!
It's not technically a sound- to- light unit, for the
program has no way of knowing whether or not your stereo is
even switched on, let alone what's playing on it. What it
is, however, is a very good optical illusion of sound and
vision being synchronised. What you do is RUN the program
and input answers to the various questions asked, put your
favourite record on, switch the lights off and close the
curtains, then just sit back while your brain dances round
in circles.
The program is featured in Figs. 1 and 2. You should enter
the machine code first (using a BASIC program to do so) and
then delete this BASIC program to input the one given. Take
a look at this now.
I'll now give you some examples on how to RUN the program.
Type RUN. (Easy so far, isn't it?) For the question 'NUMBER
OF LINES', you should input (say) 5. For 'INK', input 'INT
(4*RND)+4', and for 'PAPER' input '0'. Finally, for 'STARS?'
you should input 'Y'. This is just an example - try it out
for yourself.
What's the plot?
The program has a couple of extra features which you ought
to know about. RUN 200 enables you to define the initial INK
and the initial PAPER colours. For instance, RUN 200 and
then input 0 / 7 / 4 / '7-X' / '7-Y' / 'Y' / ('/' counts as
ENTER). RUN 400 will SAVE and VERIFY the program and the
machine code.
I won't turn the above program into machine code just yet.
Before I do, I'll give you some information on PLOT and
DRAW.
CALL PLOT_BC (Hex CD E522) requires B to hold the Y
co-ordinate, and C to hold the X co-ordinate. This will PLOT
the required point. Bit zero of P_FLAG (5C91) must be zero
for OVER 0 or one for OVER 1.
CALL DRAW_3 (Hex CDBA24) requires B to hold the absolute
value of the Y parameter, and C the absolute value of the X
parameter. If Y is greater than or equal to zero then D
should hold 01 Hex, otherwise D should hold FF Hex. If X is
greater than or equal to zero then E should hold 01 Hex,
otherwise E should hold FF Hex. The sequence of instructions
LD HL,2758 / EXX must be carried out between CALL DRAW_3 and
RET (to BASIC) otherwise the Spectrum will crash.
Transformation time
We still can't rewrite the program into machine code yet,
since we don't have a routine for INT (X*RND). It is
possible to write a simple random number subroutine which
creates random numbers between 0000 and FFFF Hex in the HL
register pair, so take a look at Fig.3 which illustrates
such a subroutine. It works using the random number seed
already used by the ROM, but does not actually call the
ROM's RND routine (since this is highly impractical). The
subroutine does, however, work in more or less the same way
as RND - it takes the value of the system variable SEED, and
multiplies it by some constant. Only the remainder modulo
65536d is taken as the new result. This is not quite RND,
but it does give fairly random results.
Figure Four, on the other hand, is another kettle of fish
altogether. This is a subroutine I've called RAND_A in order
to distinguish it from the subroutine in Fig.3. It requires
that A contains a number between 00 and A-1. Of particular
note is the subroutine MULT which is called from within
RAND__A; this is a subroutine which will multiply the number
held in the A register by the number held in the DE register
pair. The result will be formed in the AHL register triplet
(the result will always fit in three bytes). RAND_A works
just like the ROM's RND routine - it takes a value, SEED,
which is multiplied by 4B, and then the remainder is found
from a division by Hex 10001, less one. Can you see how the
program calculates this remainder? To find the random number
required, this new seed is multiplied by A and the high part
only becomes the random number.
Now we are almost ready to turn the program Patterns
entirely into machine code. Well - not quite entirely as we
still can't do VAL. Let's ignore that part for the time
being and leave VAL in BASIC. I'd like you now to study
Figs. 5 and 6, which list the revised program, now called
Patterns 2. If you now compare it with Figs. 1 and 2, see if
you can work out how the translation is achieved. Note that
the instruction CALL RAND_A is used - this is a reference to
the subroutine in Fig. 4.
You can use any addresses you like for this program. I chose
to use the following:
Label Hex Dec
RAND_A 7000 28672
MULT 7021 28705
FIND_A 7030 28720
PL_DR 703B 28731
INIT 7078 28792
MAIN 7098 28824
P_VAL 7105 28933
P_OVER 7106 28934
P_DRAW 7107 28935
LINES 7108 28936
INK 7109 28937
PAPER 710A 28938
STARS 710B 28939
ARRAY 710C 28940
It is essential, however, that P_OVER and P_DRAW be
adjacent, and also that ARRAY points to the start of a
segment of spare RAM.
- Fig.1 The program, Patterns: part one - the BASIC - - - - - - - - - - - -
10 INPUT "NUMBER OF LINES";n
20 DIM x(n+1): DIM y(n+1)
30 INPUT "INK";x$ (use the keyword INK here)
40 INPUT "PAPER";y$ (use the keyword PAPER here)
50 INPUT "STARS?";a$: LET s=a$="N" OR a$="n"
60 CLS: LET p=1
70 LET p1=p+1: IF p1>n+1 THEN LET p1=1
80 LET p2=p1+1: IF p2>n+1 THEN LET p2=1
90 PLOT x(p1),y(p1)
95 DRAW x(p2)-x(p1),y(p2)-y(p1)
100 PLOT OVER s;x(p1),y(p1)
105 DRAW OVER 1;x(p2)-x(p1),y(p2)-y(p1)
110 LET x(p1)=INT (256*RND)
120 LET y(p1)=INT (176*RND)
130 PLOT x(p),y(p)
140 DRAW x(p1)-x(p),y(p1)-y(p)
150 LET x=VAL x$: LET y=VAL y$
160 POKE 32769,x: POKE 32770,y: LET p=p1+USR 32768
170 GO TO 70
200 INPUT "INITIAL INK";x
210 INPUT "INITIAL PAPER";y
220 GO TO 10
400 SAVE "PATTERNS" LINE 430
410 SAVE "PATTERNS" CODE 32768,34
420 VERIFY "": VERIFY "" CODE: STOP
430 CLEAR 32767: LOAD "" CODE: STOP [I added the CLEAR. JG.]
- Fig.2 The program, Patterns: part two - the machine code - - - - - - - -
01???? PATTERNS LD BC,???? To be POKEd by BASIC
78 LD A,B
76 HALT
D3FE OUT (FE),A
78 LD A,B
87 ADD A,A
87 ADD A,A
87 ADD A,A
81 ADD A,C
218D5C LD HL,ATTR_P
77 LD (HL),A
210058 LD HL,ATTRS
110158 LD DE,ATTRS+1
01FF02 LD BC,02FF
77 LD (HL),A
EDB0 LDIR
C9 RET
- Fig.3 The machine code random number subroutine - - - - - - - - - - - - -
D5 RAND PUSH DE
2A765C LD HL,(SEED)
54 LD D,H
5D LD E,L
29 ADD HL,HL
29 ADD HL,HL
19 ADD HL,DE
29 ADD HL,HL
29 ADD HL,HL
29 ADD HL,HL
19 ADD HL,DE
22765C LD (SEED),HL
D1 POP DE
C9 RET
- Fig.4 The INT(A*RND) routine - - - - - - - - - - - - - - - - - - - - - -
C5 RAND_A PUSH BC
D5 PUSH DE
E5 PUSH HL
F5 PUSH AF
3E4B LD A,4B
ED5B765C LD DE,(SEED)
CD???? CALL MULT
A7 AND A
4F LD C,A
ED42 SBC HL,BC
3801 JR C,AA
2B DEC HL
22765C AA LD (SEED),HL
54 LD D,H
5D LD E,L
F1 POP AF
CD???? CALL MULT
E1 POP HL
D1 POP DE
C1 POP BC
C9 RET
0608 MULT LD B,08
210000 LD HL,0000
29 LOOP ADD HL,HL
17 RLA
3003 JR NC,BB
19 ADD HL,DE
CE00 ADC A,00
10F7 BB DJNZ LOOP
C9 RET
- Fig.5 The program, Patterns2; the BASIC - - - - - - - - - - - - - - - - -
10 INPUT "NUMBER OF LINES";n
20 POKE lines,n: LET n=USR init
30 INPUT "INK";x$
40 INPUT "PAPER";y$
50 INPUT "STARS?";a$: POKE stars,a$="N" OR a$="n"
60 POKE ink,VAL x$: POKE paper,VAL y$
70 LET n=USR main
80 GO TO 60
200 INPUT "INITIAL INK";x
210 INPUT "INITIAL PAPER";y
220 GO TO 10
400 SAVE "P2" LINE 450
410 SAVE "P2" CODE rand_a,263
420 VERIFY ""
430 VERIFY "" CODE
440 STOP
450 CLEAR rand_a-1: LOAD "" CODE [I added the CLEAR. JG.]
- Fig.6 The program, Patterns2; the machine code - - - - - - - - - - - - -
D5 FIND_A PUSH DE
11???? LD DE,ARRAY
6F LD L,A
2600 LD H,#00
29 ADD HL,HL
19 ADD HL,DE
D1 POP DE
C9 RET
C5 PL_DR PUSH BC
D5 PUSH DE
7A LD A,D
D5 PUSH DE
CD???? CALL FIND_A
4E LD C,(HL)
23 INC HL
46 LD B,(HL)
C5 PUSH BC
3A???? LD A,(P_OVER)
32915C LD (P_FLAG),A
CDE522 CALL PLOT_BC
C1 POP BC
D1 POP DE
7B LD A,E
CD???? CALL FIND_A
7E LD A,(HL)
23 INC HL
1E01 LD E,#01
91 SUB C
3004 JR NC,PD2
ED44 NEG
1EFF LD E,#FF
4F PD2 LD C,A
7E LD A,(HL)
1601 LD D,#01
90 SUB B
3004 JR NC,PD3
ED44 NEG
16FF LD D,#FF
47 PD3 LD B,A
3A???? LD A,(P_DRAW)
32915C LD (P_FLAG),A
CDBA24 CALL DRAW_3
D1 POP DE
C1 POP BC
C9 RET
210040 INIT LD HL,D_FILE
110140 LD DE,D_FILE+1
01FF17 LD BC,#17FF
3600 LD (HL),#00
EDB0 LDIR
ED4B???? LD BC,(LINES-1)
04 INC B
21???? LD HL,ARRAY
AF XOR A
77 IN2 LD (HL),A
23 INC HL
77 LD (HL),A
23 INC HL
10FA DJNZ IN2
32???? LD (P_VAL),A
C9 RET
ED4B???? MAIN LD BC,(P_VAL)
3A???? LD A,(LINES)
51 LD D,C
14 INC D
BA CP D
3002 JR NC,M2
1600 LD D,#00
5A M2 LD E,D
1C INC E
BB CP E
3002 JR NC,M3
1E00 LD E,#00
210000 M3 LD HL,#0000
22???? LD (P_OVER),HL
CD???? CALL PL_DR
3A???? LD A,(STARS)
32???? LD (P_OVER),A
3E01 LD A,#01
32???? LD (P_DRAW),A
CD???? CALL PL_DR
7A LD A,D
CD???? CALL FIND_A
3EFF LD A,#FF
CD???? CALL RAND_A
77 LD (HL),A
23 INC HL
3EB0 LD A,#B0
CD???? CALL RAND_A
77 LD (HL),A
5A LD E,D
51 LD D,C
210000 LD HL,#0000
22???? LD (P_OVER),HL
CD???? CALL PL_DR
7B LD A,E
32???? LD (P_VAL),A
76 HALT
3A???? LD A,(PAPER)
D3FE OUT (#FE),A
87 ADD A,A
87 ADD A,A
87 ADD A,A
2A???? LD HL,(INK)
B5 OR L
328F5C LD (ATTR_T),A
210058 LD HL,ATTRS
110158 LD DE,ATTRS+1
01FF02 LD BC,#02FF
77 LD (HL),A
EDB0 LDIR
215827 LD HL,#2758
D9 EXX
C9 RET
--
Another Fine Product transcribed by:
Jim Grimwood (jimg@globalnet.co.uk), Weardale, England
--