Commodore 64 Assembler Workshop
Commodore 64 Assembler Workshop
Assembler
Workshop
Commodore 64
Assembler
Workshop
Bruce Smith
O h i v a Publishing Limited
SHIVA PUBLISHING LIMITED
64 Welsh Row, Nantwich, Cheshire CW5 5ES, England
ISBN 1 85014004 9
Introduction 1
1 Opening the Tool Box 3
Writing Machine Code 4
Debugging 5
2 Commodore Command 7
CHRGET 7
The Wedge Operating System 9
The New Commands 15
Using the WOS 17
3 ASCII to Binary Conversions 20
ASCII Hex to Binary Conversion 20
Four ASCII Digits to Hex 26
Convert Decimal ASCII String to Binary 30
4 Binary to Hex ASCII 38
Print Accumulator 38
Print a Hexadecimal Address 41
Binary Signed Number to Signed ASCII Decimal
String 42
5 String Manipulation 53
Comparing Strings 53
Strings Unite 58
CopyCat 64
Insertion 71
6 Printing Print! 78
7 A Bubble of Sorts 84
8 Software Stack 91
Binary Ins and Outs 98
Come In 100
9 Move, Fill and Dump 104
Move it! 104
Fill 111
A Memory Dump 113
10 Hi-res Graphics 120
A BASIC Move 121
Selecting Hi-res 123
A Clear View 124
2
1 Opening the Tool Box
The routines included in this book are designed to make your life
that much easier when writing machine code. Quite often, after
mastering the delights of the Commodore 64's microprocessor,
programmers become frustrated because the techniques involved
in, say, converting between ASCII characters and their equivalent
binary values are not known. Nor are they readily available in a
published form, so the painful process of sitting down armed with
pencil and paper and working out the conversion through trial and
error begins.
This is just one example of the type of assembler program you
will find within these pages. Wherever possible, they are supplied
in a form that will make them relocatable, the only addresses
requiring alteration being those specified by JSR or JMP.
Each listing is in the form of a BASIC loader program, using a
loop to READ and POKE decimal machine code data into
memory. This will allow those of you who have not yet splashed out
your hard earned cash on a suitable assembler program to get
underway. For those lucky ones among you who do have an as-
sembler, each data statement has been followed by a REM line
containing the standard mnemonic representation of the instruc-
tion (see Appendix 1 for a summary). This can be entered directly
and assembled as required.
Although the programs are typeset they have been spooled
direct as ASCII files and loaded into my word processor so all
should run as they are.
BASIC is used freely to demonstrate the machine code's oper-
ation-rather than repeating sections of assembler code, BASIC is
often used to shorten the overall listing, and it is left to you to add
further sections of assembler from other programs within the book
or from your own resources. For example, many programs require
you to input a decimal address. In the demonstrations, this is
indicated by means of a one-line INPUT statement. In Chapter 3,
however, there is a routine for inputting a string of five ASCII
3
decimal characters and converting It mto a two-byte binary
number. This can be inserted into the assembler text of the pro-
gram, to go some way to making it a full machine code program
available for use as a completely self-contained section of machine
code.
You have an idea that you wish to convert into machine code-so
what's the best way to go about it? Firstly, make some brief notes
about its operation. Will it use the screen? If so, what mode? Will it
require the user to input values from the keyboard? If so, what keys
do you use? What will the screen presentation look like? Will you
want to use sound? ... and so on. Once you have decided on the
effects you want, put them down in flowchart form. This need not
be the normal flowchart convention of boxes and diamonds-I find
it just as easy to write each operation I want the program to
perform in a list and then join the flow of these up afterwards.
Quite often, the next step is to write the program in BASIC! This
may sound crazy, but it allows you to examine various aspects of
the program's operation in more detail. An obvious example ofthis
is obtaining the correct screen layout-you might find after run-
ning the routine that the layout does not look particularly good.
Finding this out at an early stage will save you a lot of time later,
avoiding the need to rewrite the screen layout portion of your
machine code-rewriting BASIC is much easier! If you write the
BASIC tester as a series of subroutines, it will greatly simplify the
process of conversion to machine code. Consider the main loop of
such a BASIC tester, which takes the form:
4
JSR $C2 REM SET UP VARIABLES
JSR $C3 REM SET UP SCREEN
REM LOOP
JSR $C4 REM INPUT VALUES
JSR $C5 REM CONVERT AS NEEDED
JSR $C6 REM DISPLAY VALUES
JSR $:;7 REM DO UPDATE
BNE LOOP
DEBUGGING
CLC
LOA $FB
AOC #1
BCC OVER
INC $FC
OVER
RTS
5
is not much good if you don't save the result of the addition
with:
STA $FB
LDA #$
BRK
LDX #$FF
DATA 169,6,162.5,96
LDA #$6
LDX #$6
XXX
If none of these errors is the cause of the problem, then I'm afraid
you must put your thinking cap on. Well-commented assembler
will make debugging very much easier.
6
2 Commodore Command
CHRGET
Table 2.1
10
GETBYfE
FROM
COMMAND
TABLE
Yes
11
67fd DATA 169,fd REM LDA #$fdfd
68fd DATA 133,127 REM STA $7F
69fd DATA 169 , 193 REM LDA #$Cl
7fdfd DATA 133,128 REM STA $8fd
71fd DATA 23fd,122 REM INC $7A
72fd DATA 2fd8,2 REM BNE $fd2
73fd DATA 23fd, 133 REM INC $7B
74fd DATA 16fd,fd REM LDY #$fdfd
75fd DATA 162,fd REM LDX #$fdfd
76fd DATA 177 , 127 REM LDA ($7F) , Y
77fd DATA 24fd,36 REM BEQ $24
78fd DATA 2fd9, 122 REM CMP ($7A), Y
79fd DATA 2fd8,4 REM BNE $fd4
8fdfd DATA 2fdfd REM INY
81fd DATA 56 REM SEC
82fd DATA 176 , 244 REM BCS $F4
83fd DATA 177,127 REM LDA ($7F) , Y
84fd DATA 24fd,4 REM BEQ $fd4
8Sfd DATA 2fdfd REM INY
86fd DATA 56 REM SEC
87fd DATA 176 , 248 REM BCS $F8
88fd DATA 2fdfd REM INY
89fd DATA 152 REM TYA
9fdfd DATA 24 REM CLC
91fd DATA Ifdl , 127 REM ADC $7F
92fd DATA 133,127 REM STA $7F
93fd DATA 169,fd REM LDA #$fdfd
94fd DATA Ifdl,128 REM ADC $8fd
95fd DATA 133,128 REM STA $8fd
96fd DATA 16fd,fd REM LDY #$fdfd
97fd DATA 232 REM INX
98fd DATA 232 REM INX
99fd DATA 56 REM SEC
Ifdfdfd DATA 176,216 REM BCS $D8
Ifdlfd DATA 189,8fd,192 REM LDA $Cfd5fd,x
Ifd2fd DATA 133,128 REM STA $8fd
Ifd3fd DATA 232 REM INX
Ifd4fd DATA 189,8fd,192 REM LDA $Cfd5fd,x
Ifdsfd DATA 133,129 REM STA $81
Ifd6fd DATA Ifd8, 128, fd REM JMP ($fdfd8fd)
12
165 REM ILLEGAL
17 DATA 162,11 REM LOX #$B
18 DATA 18,,3 REM JMP ($3)
19
11 REM ** SET UP COMMAND TABLE **
111 TABLE=4948
112 FOR LOOP= TO 1
113 READ BYTE
114 POKE TABLE+LOOP,BYTE
115 NEXT LOOP
116
117 REM ** ASCII COMMAND DATA **
118 DATA 67,76,83, REM CLS
119 DATA 76,79,87, REM LOW
12 DATA 85,8, REM UP
+
l"c"I"l"I"s"I_I"l" 1"0"1 "w"I_I"u"I"p"II_1
The Command Table
49232
~
EXEcunON I_
ADDRESS OF:
~~~
C411J5 C41"A C41
CLS lOW UP
JMP $C218
The address $C218 is the address of the start of the WOS inter-
preter at line 210. Finally, line 200 does an indirect jump through
the IMAN vector at $0302 to perform a warm BASIC start. The
CHRGET subroutine, complete with wedge jump, now looks like
this:
Table 2.2
14
byte within the command table is located (lines 740 to 7(0), and
compared to the byte within the program, immediately after the @
(line 780). If the comparison fails, the branch to line 830 is per-
formed, locating the zero and therefore the next command in the
command table. When a comparison is successful (the command is
identified) and the terminating zero located by line 770, the branch
to line 1010 is performed. Lines 1010 to 1060 locate the execution
address of the command from the address table located at $C050.
The X register is used as an offset into this, being incremented by
two each time a command table comparison fails (lines 970 and
980). The two address bytes are loaded to form a zero page vector
and the machine code is executed via an indirect jump.
On completion of the routine, its terminating RTS returns
control to line 460, and the next byte after the command is sought
out. When a zero is found, the branch of line 490 is performed and
the CHRGET routine is completed, control being returned to the
BASIC Interpreter.
15
14 POKE MC+LOOP,BYTE
141ta NEXT LOOP
142~
143 REM ** COMMAND M/C **
144 REM CLS
1450 DATA 169,147 REM LDA 11$93
146 DATA 76,210,255 REM JMP $FFD2
147 REM LOW
148 DATA 169,14 REM LDA #$E
149 DATA 76,21,255 REM JMF $FFD2
15 REM UP
151 DATA 169,142 REM LDA #$8D
152 DATA 76,21,255 REM JMP $FFD2
153
154 REM ** SET UP ADDRESS TABLE **
155 ADDR=49232
156 FOR LOOP= TO 5
157 READ BYTE
158 POKE ADDR+LOOP,BYTE
159 NEXT LOOP
16
161 REM ** ADDRESS DATA **
162 DATA ,196 REM CLS $C4
163 DATA 5,196 REM LOW $C405
164 DATA 1,196 REM UP $C4A
SYS 49666
The screen will clear, and the following message be printed across
the top of the screen:
Line-by-Iine
17
line 330 increment low byte of address
line 340 branch back to line 300 if high byte does not need
to be updated
line 350 else increment high byte of address
line 360 set Carry flag and do a forced branch back to
line 300
line 380 print 'READY' prompt
line 390 clear accumulator
line 400 set Carry flag and force a branch to line 500 to
update and return
line 420 get '@' into accumulator
line 430 set Carry flag and force a branch to line 570
line 445 entry point for PROGRAM-MODE
line 450 locate and execute command or print appropriate
error message
line 460 clear indexing register
line 470 get byte -from program
line 480 is it a 0 and therefore end of line?
line 490 yes, branch to line 500
line 500 no, is it the command delimiter ':'?
line 510 yes, branch to line 570
line 520 no, increment low byte of address
line 530 if not zero, branch back to line 470 to redo loop
line 540 increment high byte of address
line 550 set Carry flag and force a branch back to line 470.
line 570 is it a command delimiter ':'?
line 580 if greater than or equal to ':' then branch to line 650
line 590 is it a space?
line 600 yes, so branch to line 650
line 610 set Carry flag
line 620 subtract ASCII base code
line 630 set C&rry flag
line 640 subtract token and ASCII set bits
line 650 return to BASIC Interpreter
line 660 jump to CHRGET
line 665 entry for FIND-EXECUTE subroutine
line 670 seed address of command table ($Cl00) into vector
at $7F
line 710 increment low byte of command address
line 720 branch over if no carry into high byte
18
line 73~ else increment high byte of address
line 74~ back together, initialize Y register
line 75~ and X register
line 76~ get byte from the command table
line 77~ if zero byte, then command is identified, branch to
line 1010
line 78~ is it the same as the byte pointed to in the command
table?
line 79~ no, branch to line 830
line 8~~ increment index
line 82~ set Carry flag and force a branch back to line 760
line 83~ command not identified-seek out zero byte. Get
byte from command table
line 84~ if zero, branch to line 880
line 85~ increment index
line 86~ set Carry flag and force a branch to line 830
line 88~ increment index
line 89~ transfer into accumulator
line 9~~ clear Carry flag
line 9l~ add to low byte of vector address
line 92~ save result
line 93~ clear accumulator
line 94~ add carry to high byte of vectored address
line 95~ and save the result
line 96~ initialize index
line 97~ add two to X to move onto next address in the
line 98~ ., command address table
line 99~ set Carry flag and force a branch to line 760
line l~l~ get low byte of command execution address
line l~2~ save it in a vector
line l~3~ increment index
line l~4~ get high byte of command execution address
line l~5~ save it in vector
line l~6~ jump to vectored address to execute machine code
of identified command
line l~65 entry for ILLEGAL-unrecognized WOS command
line l~7~ get error code into X register
line l~8~ and jump to error handling routine
19
3 ASCII to Binary
Conversions
Table 3.1
$3 11
1 1 $31 ll1
2 1 $32 1l1
3 11 $33 1111
4 1 $34 111
20
Table 3.1 (contd.)
5 (lj(lj(lj(lj(lj 1(lj1 $35 (lj(ljll(lj1(lj1
6 (lj(lj(lj(lj(lj11(lj $36 (lj(ljll(ljll(lj
7 (lj(lj(lj(lj(ljll1 $37 (lj(ljll(ljll1
8 (lj(lj(lj(lj1(lj(lj(lj $38 (lj(lj111(lj(lj(lj
9 (lj(lj(lj(lj1(lj(lj1 $39 (lj(lj1ll(lj(lj1
A (lj(lj(lj(lj1(lj1(lj $41 (lj1(lj(lj(lj(lj(lj1
B (lj(lj(lj(lj 1(lj1 1 $42 (lj1(lj(lj(lj(lj1(lj
C (lj(lj(lj(lj11(lj(lj $43 (lj1(lj(lj(lj(lj11
D (lj(lj(lj(lj ll(lj1 $44 (lj1(lj(lj(lj1(lj(lj
E (lj(lj(lj(ljll1(lj $45 (lj1(lj(lj(lj 1(lj1
F (lj(lj(lj(ljllll $46 (lj1(lj(lj1l(lj
(lj(lj(lj(lj1(lj(lj
+ (lj(lj(lj(lj1(lj(lj1
Program 2
21
11.0 REM ** M/C DATA **
12.0 DATA 2.01,48 REM CMP #$3.0
13.0 DATA 144,15 REM BCC $F
14.0 DATA 2.01,58 REM CMP #$3A
15.0 DATA 144,8 REM BCC $.08
16.0 DATA 233,7 REM SBC #$.07
17.0 DATA 144,7 REM BCC $.07
18.0 DATA 2.01,64 REM CMP #$4.0
19.0 DATA 176,2 REM BCS $.02
2.0.0 REM ZERO-NINE
21.0 DATA 41,15 REM AND #$F
22.0 REM RETURN
23.0 DATA 96 REM RTS
24.0 REM ILLEGAL
25.0 DATA 56 REM SEC
26.0 DATA 96 REM RTS
27.0
28.0
29.0 REM ** TESTING ROUTINE **
3.0.0 TEST=49184
31.0 FOR LOOP= TO 14
32.0 READ BYTE
33.0 POKE TEST+LOOP,BYTE
34.0 NEXT LOOP
35.0
36.0 REM ** M/C TEST DATA **
37.0 REM TEST
38.0 DATA 32,228,255 REM JSR $FFE4
39.0 DATA 24.0,251 REM BEQ $FB
4.0.0 DATA 32,.0,192 REM JSR $C
41.0 DATA 144,2 REM BCC $.02
42.0 DATA 169,255 REM LDA #$FF
43.0 REM OVER
44.0 DATA 133,251 REM STA $FB
45.0 DATA 96 REM RTS
46.0
47.0 PRINT CHR$(147)
48.0 PRINT"HIT A HEX CHARACTER KEY, AND ITS
BINARY"
49.0 PRINT"EQUIVALENT VALUE WILL BE PRINTED"
22
Yes
Yes
No
SUBTRACT7TO
MOVE TO
A-F
Yes
SET CARRY
TO DENOTE
ERROR
MASK HIGH
NIBBLE
5
51 SYS TEST
52
53 PRINT "RESULT = "PEEK(251)
$46 (ASC"F")
CMP #$3.0 $46 1
BCC ILLEGAL
CMP 1I$3A $46 1
BCe ZERO-NINE
SBC #7 $3F 1
BCC ILLEGAL
CMP 11$4.0 $3F .0
BCS RETURN
AND $.0F $.0F .0
RTS
Note that this routine indicates an error by returning with the Carry
flag set. so any calls to the conversion routine should always check
for this on return. The short test routine does this. and loads the
accumulator with $FF to signal the fact.
Using two calls to this routine would allow two-byte hex values to
be input and converted into a full eight-byte value. On completion
of the first call. the accumulator's contents would need to be shifted
into the high nibble.
24
The coding might look like this:
REM WAIT
JSR GETIN REM GET FIRST CHARACTER
BEQ WAITl
JSR ASCII-BINARY REM CONVERT TO BINARY
BCS REPORT-ERROR REM NON-HEX IF C=l
ASL A REM MOVE INTO HIGHER
NIBBLE
ASL A
ASL A
ASL A
STA HIGH-NIBBLE REM SAVE RESULT
REM WAIT2
JSR GETIN REM GET SECOND CHARACTER
BEQ WAIT2
JSR ASCII-BINARY REM CONVERT TO BINARY
BCS REPORT-ERROR REM NON-HEX IF C=l
ORA HIGH-NIBBLE REM ADD HIGH NIBBLE
REM ALL BINARY NOW IN
ACCUMULATOR
Using this routine and entering, say, $FE will return 11111110 in
the accumulator.
Line-by-Iine
Program 3
The machine code begins by clearing three bytes of zero page RAM
pointed to by the contents of the X register (lines 100 to 140). The
ASCII characters are accessed one by one from a buffer which may
be resident anywhere in memory (line 1(0), though in this case it is
the four bytes at the start of the cassette buffer. Conversion and
error-detection are performed (lines 170 and 180) and the four
returned bits shifted into the high four bits of the accumulator. The
buffer index, which keeps track of the character position in the
buffer, is saved in the third of the three bytes cleared.
The loop between lines 250 and 300 is responsible for moving the
four bits through the two zero page bytes which hold the final
result. In fact, with the accumulator, the whole process of the loop
is to perform the operation of a 24-hit "hift rpaister. Figure 3.2
28
Accumulator
ASLA
Carry n---1111111 1- 0
~----.-.---------------,
ROL0. X
Carry
ROL I. X
carryD
Figure 3.3 A 24-bit shift register, showing passage of the bits in the
number$F~
Line-by-line
30
that in addition to obtaining the characters for insertion into the
string buffer, the number of characters for conversion is required,
this being placed in the first byte of the buffer.
Pmgram4
31
340 REM CONVERT-CHARACTER
350 DATA 172,52,3 REM LDY $334
360 DATA 185,60,3 REM LDA $33C,Y
370 REM CHECK-LEGALITY
380 DATA 201,58 REM CMP 1I$3A
390 DATA 16,90 REM BPL $5A
400 DATA 201,48 REM CMP 11$30
410 DATA 48,86 REM BMI $56
420 DATA 72 REM PHA
430 DATA 14,53,3 REM ASL $335
440 DATA 46,54,3 REM ROL $336
450 DATA 173,53,3 REM LDA $335
460 DATA 172,53,3 REM LDY $336
470 DATA 14,53,3 REM ASL $335
480 DATA 46,54,3 REM ROL $336
490 DATA 14,53,3 REM ASL $335
500 DATA 46,54,3 REM ROL $336
510 DATA 24 REM CLC
520 DATA 109,53,3 REM ADC $335
530 DATA 141,53,3 REM STA $335
540 DATA 152 REM TYA
550 DATA 109,54,3 REM ADC $336
560 DATA 141,54,3 REM STA $336
570 DATA 56 REM SEC
580 DATA 104 REM PLA
590 DATA 233,48 REM SBC 11$30
600 DATA 24 REM CLC
610 DATA 109,53,3 REM ADC $335
620 DATA 141,53,3 REM STA $335
630 DATA 144,3 REM BCC $03
640 DATA 238,54,3 REM INC $336
650 REM NO-CARRY
660 DATA 238,52,3 REM INC $334
670 DATA 202 REM DEX
680 DATA 208,181 REM BNE $B5
690 DATA 173,55,3 REM LDA $337
700 DATA 16,17 REM BPL $11
710 DATA 56 REM SEC
720 DATA 169,0 REM LDA 110
730 DATA 237,53,3 REM SBC $335
32
GET
FIRST
CHARACTER
SET
ERROR END
FLAG
CONVERT
TO
BINARY
ROTATE
SHIff
REGISTER~
No
33
74 DATA 141,53,3 REM STA $335
75 DATA 169, REM LDA #
76 DATA 237,54,3 REM SBC $336
77 DATA 141,54,3 REM STA $336
78 REM NO-COMPLEMENT
79 DATA 24 REM CLC
8 DATA 144,1 REM BCC $1
81 REM ERROR
82 DATA 56 REM SEC
83 REM FINISH
84 DATA 96 REM RTS
85
86 REM ** SET UP SCREEN AND GET NUMBER **
87 PRINT CHR$(147)
88 INPUT"NUMBER FOR CONVERSION";A$
89 FOR LOOP=l TO LEN(A$)
9 TEMP$=MID$(A$,LOOP,1)
91 B=ASC(TEMP$)
92 POKE 828+LOOP,B
93 NEXT LOOP
94 POKE 828,LEN(A$)
95
96 SYS CODE
97
98 PRINT"THE TWO BYTES ARE AS FOLLOWS"
99 PRINT"LOW BYTE ";PEEK(821)
1 PRINT"HIGH BYTE ";PEEK(822)
The machine code begins by obtaining the character count from the
X register. An error is signalled if this count is zero, otherwise the
34
program progresses, clearing the sign flag (used to signal positive or
negative values) and result destination bytes at 'current' (lines 130
to 160). Location $70 is used to hold the string index, pointing to
the next character for conversion. This byte is initially loaded with
1 so that it skips over the count byte in the buffer.
The first byte of the string is tested for a '+' or '-' sign, the
former being an optional item in the string, and the sign flag is set
accordingly (lines 190 to 230). The CONVERT-CHARACTER
loop starts by testing the character about to be manipulated to
ensure it is a decimal value, i.e. 0 to 9 inclusive. Converting the byte
into binary form is achieved by multiplying the byte by 10. This
multiplication is readily available using four arithmetic shifts and
an addition: 2 * 2 * 2 + 2 = 10.
Because we are dealing with a two-byte result, the arithmetic
shift must be performed on the two bytes, allowing bits to be
transferred from one byte to the other. This is performed by using
an ASL followed by a ROL. As figure 3.5 illustrates, this acts
exactly like a 16-bit ASL. The first pass through this character-
conversion loop has little effect, as it is operating on characters
already converted, of which there are none first time round!
Lines 570 to 620 carry out the conversion of ASCII to binary and
store the result. This is performed, as we know from earlier
examples, by masking off the high nibble. Another technique for
doing this is simply to subtract the ASCII code for '0': $30.
-0
Once all the characters have been processed, the sign flag at $334
(820) is checked for a negative value. If this is indicated (lines 690
and 700), the value of current is subtra~ted from zero, thereby
converting the absolute value into a signed negative byte (lines 710
to 770). The Carry flag is used to indicate any error condit~ons-if
it is set an error occurred, and the string index at $334 points to the
illegal character.
35
Line-by-Iine
36
line 46 save high byte
line 47 multiply by two again (now *4)
line 49 and again (now *8)
line 5l clear Carry flag
line 52 add low byte *2
line 53 and save result
line 54 transfer high byte *2
line 55 and add to *8 high byte
line 56 save it. Now *10
line 57 set Carry flag
line 58 restore ASCII code from stack
line 59 convert ASCII to binary
line 6 clear Carry flag
line 61 add it to low byte current
line 62 save result
line 63 branch if NO-CARRY
line 64 else increment high byte
line 65 entry for NO-CARRY
line 66 move index on to next byte
line 67 decrement length counter
line 68 branch to CONVERT-CHARACTER if not finished
line 69 completed so get sign flag
line 7 if clear branch to NO-COMPLEMENT
line 7l else set Carry flag
line 72 clear accumulator
line 73 and obtain two's complement
line 74 save low byte result
line 75 clear accumulator
line 76 subtract high byte from 0
line 77 and save result
line 78 entry for NO-COMPLEMENT
line 79 clear Carry flag
line 8 and force branch to FINISH
line 81 entry for ERROR
line 82 set Carry flag to denote error
line 83 entry for FINISH
line 84 return to BASIC
37
4 Binary to Hex ASCII
PRINT ACCUMULATOR
ProgramS
The hexprint routine is embedded between lines 110 and 230. The
accumulator's contents are first pushed on to the hardware stack.
This procedure is necessary as it will have to be restored before the
second pass, which calculates the ASCII code for the second char-
acter. The first pass through the routine sets about moving the
upper nibble of the accumulator byte into the lower nibble (lines
120 and 130). The FIRST subroutine ensures that the high nibble is
cleared by logically ANDing it with $0F. This is, of course, surplus
to requirement on the first pass, but is needed on the second pass to
isolate the low nibble. Comparing the accumulator's contents with
10 will ascertain whether the value is in the range 0 to 9 or A to F. If
the Carry flag is clear, it falls in the lower range (0 to 9) and simply
setting bits 4 and 5, by adding $30, will give the required ASCII
code. A further 7 must be added to skip non-hex ASCII codes to
arrive at the ASCII codes for A to F ($41 to $46). You may have
39
noticed that line 200 does not add 7 but in fact adds one less, 6. ThIs
is because. for this section of coding to be executed, the carry must
have been set, and the 6510 addition opcode references the Carry
flag in addition. Therefore, the addition performed is: accumulator
+ 6 + 1.
The JMP of line 230 will return the program back to line 150.
Remember, FIRST was called with a JSR, so the RTS from com-
pletion of the CHROUT call returns control here. The accumu-
lator is restored and the process repeated for the second ASCII
digit.
A short test routine is established in lines 250 to 340. This
requests you to hit a key, the value of which is placed in a free zero
page byte. The 'hand-POKEd' routine at 828 is called by line 360,
and puts the key's value into the accumulator before performing a
jump to the main routine.
The following example illustrates the program's operation,
assuming the accumulator holds the value 01001111, $4F:
$4F
LSR A $27 1
LSR A $13 1
LSR A $9 1
LSR A $4 1
JSR FIRST
AND #$F $4 1
CMP #$A $4
BCC OVER
OVER
ADC #$3 $34 (ASC"4")
JMP CHROUT
PLA $4F
AND #$F $F
CMP #$A
Line-by-line
Program 6
Zero paged indexed addressing is used to access the two bytes, the
crucial location being given in the X, register, which acts as the
index for the high byte, LDA $01,X (Iine130), and the low byte,
LDA $OO,X (line 150). The all-important address in this instance is
$FB (line 130), so the bytes accessed by ADDRESS-PRINT are
$FB ($FB+0) and $FC ($FB+1). Using this method, various
addresses can be housed within zero page and anyone reached
simply by seeding the X register with the location value.
Project
42
SHIITHIGH
NIBBLE INTO
LOWER
NIBBLE
CONVERT
FIRST
DIGIT
Yes
ADD6TO
CONVERT TO
A-F
CONVERT
DIGIT TO
ASCII
END
43
Program 7
CALCULATE
ABSOLUTE
VALUE
No
CONCATENATE
CHARACTER
TO STRING
No
No
45
399.1 DATA 173 , 54,3 REM LDA $336
49.19.1 DATA 233 , 19.1 REM SBC #$A
419.1 DATA 168 REM TAY
429.1 DATA 173,55,3 REM LDA $337
439.1 DATA 233,9.1 REM SBC #$9.19.1
449.1 DATA 144,6 REM BCC $9.16
459.1 DATA 149.1,54,3 REM STY $336
469.1 DATA 141,55 , 3 REM STA $337
479.1 REM LESS-THAN
489.1 DATA 29.12 REM DEX
499.1 DATA 29.18,221 REM BNE $DD
59.19.1 DATA 46,52,3 REM ROL $334
519.1 DATA 46,53,3 REM ROL $335
529.1 REM ADD-ASCII
539.1 DATA 24 REM CLC
549.1 DATA 173,54,3 REM LDA $336
559.1 DATA 19.15,48 REM ADC #$39.1
569.1 DATA 32,116,192 REM JSR $C74
579.1 DATA 173,52 , 3 REM LDA $334
589.1 DATA 13,53,3 REM ORA $335
599.1 DATA 29.18 , 187 REM BNE $BB
69.19.1 REM FINISHED
619.1 DATA 173 , 56 , 3 REM LDA $338
629.1 DATA 16,5 REM BPL $9.15
639.1 DATA 169,45 REM LDA #$2D
649.1 DATA 32,116 , 192 REM JSR $C74
659.1 REM POSITIVE
669.1 DATA 96 REM RTS
670 REM SUBROUTINE TO FORM ASCII CHARACTER
STRING IN $FB
689.1 :: REM CONCATENATE
699.1 DATA 72 REM PHA
79.19.1 DATA 169.1,9.1 REM LDY #$9.19.1
719.1 DATA 185,251,9.1 REM LDA $FB,Y
729.1 DATA 168 REM TAY
739.1 DATA 249.1,11 REM BEQ $B
749.1 REM SHUFFLE-ALONG
759.1 DATA 185,251,9.1 REM LDA $FB,Y
769.1 DATA 29.19.1 REM INY
779.1 DATA 153,251,9.1 REM STA $FB,Y
46
78 DATA 136,136 REM DEY : DEY
79 DATA 28,245 REM BNE $F5
8 REM ZERO-FINISH
81 DATA 14 REM PLA
82 DATA 16,1 REM LDY #$1
83 DATA 153,251, REM STA $FB,Y
84 DATA 136 REM DEY
85 DATA 182,251 REM LDX $FB,Y
86 DATA 232 REM INX
87 DATA 15,251 REM STX $FB,Y
88 DATA 96 REM RTS
890 REM STRING PRINTING ROUTINE
9 REM STRING-PRINT
91 DATA 166,251 REM LDX $FB
92 DATA 16,1 REM LDY #$1
93 REM PRINT-LOOP
94 DATA 185,251, REM LDA $FB,Y
95 DATA 32,21,255 REM JSR $FFD2
96 DATA 2 REM INY
97 DATA 22 REM DEX
98 DATA 28,246 REM BNE $F6
99 DATA 96 REM RTS
1
11 REM ** GET IN A HEX NUMBER **
12 PRINT CHR$(147) : PRINT
13 PRINT"INPUT A HEX NUMBER :$";
14 GOSUB 2
15 POKE 82,LOW : REM LOW BYTE HEX
NUMBER
16 GOSUB 20
17 POKE 821,HIGH REM HIGH BYTE HEX
NUMBER
18
19 SYS CODE : REM CALL CONVERSION
ll
111 PRINT"ITS DECIMAL EQUIVALENT IS :";
112 SYS OUTPUT
113 END
114
1999 REM ** HEX INPUT CONTROL **
47
2000 GOSUB 2500
2010 F=NUM : PRINT Z$;
2020 GOSUB 2500
2030 S=NUM PRINT Z$;
2040 HIGH=F*16+S
2050 GOSUB 2500
2060 F=NUM : PRINT Z$;
2070 GOSUB 2500
2080 S=NUM : PRINT Z$
2090 LOW=Fd6+S
2100 RETURN
2200
2499 REM ** GET HEX ROUTINE **
2500 GET Z$
2510 IF Z$="" THEN GO TO 2500
2520 IF Z$>"F" THEN GOTO 2500
2530 IF Z$="A" THEN NUM=10: RETURN
2540 IF Z$="B" THEN NUM=ll: RETURN
2550 IF Z$="C" THEN NUM=12: RETURN
2560 IF Z$="D" THEN NUM=13: RETURN
2570 IF Z$="E" THEN NUM=14: RETURN
2580 IF Z$="F" THEN NUM=15: RETURN
2590 NUM=VAL(Z$): RETURN
Functional bytes:
Table 4.1
1 1
2 FF 2
3 FF 4
4 FF 8
5 FF 1
6 FF 2
7 FF 4
8 FF 8
9 FF 1
1 FF 1
11 FF 1
12 FF 1
13 FF 1
14 FF 1
15 FF 1
16 FF 1
49
All that is now required is for this character to be added to the
string buffer. This concatenation is completed by the code of lines
690 to 880. This began by obtaining the buffer index, which con-
tains the current number of characters already concatenated. This
is stored in the first byte of the buffer, $FB in this instance. It is then
moved across into the accumulator. Next, lines 750to 790 move any
characters present in the buffer up memory one byte, thereby
opening up a gap of one byte into which the newly formed char-
acter can be placed (lines 810 to 870). The buffer index is also
incremented and restored at this point, before an RTS is made
back to the main body of the program.
End of program operation is tested for by logically ~Ring the
contents of the high and low bytes of the address. If the result is
zero, all bits have been rotated and dealt with, in which case the
sign flag byte is tested to ascertain whether a minus sign need be
placed at the start ofthe ASCII string (lines 600 to 660).
Line-by-line
52
110 INPUT"WHICH DIRECTION
5 String Manipulation
COMPARING STRINGS
1 A$="MOVE LEFT"
11 INPUT"WHICH DIRECTION?"; B$
12 IF A$=B$ THEN PRINT "CORRECT!"
5~
21.0 IF LEN(A$) > LEN(B$) THEN PRINT "FIRST"
Program 8 gives the assembler and BASIC listing for the string
comparison routine, which puts all the functions described above
at your disposal whenever the program is used. The Status register
holds these answers in the Zero and Carry flags. The Zero flag is
used to signal equality: if it is set (Z= 1), the two strings compared
were identical; if it is cleared (Z=0) they were dissimilar.
The Carry flag returns information as to which of the two strings
was the longer: if it is set (C= 1), they were identical in length or the
first string was the larger. The actual indication required here is
evaluated in conjunction with the Zero flag. If Z=0 and C= 1, then
a longer string rather than an equal-length string is indicated, but if
the Carry flag is returned clear (C=0), then the second string was
longer than the first.
ProgramS
COMPARE
WITH BYTE
IN STRING 2
INCREMENT
POINTERS
No
SET STRING
FLAGS
Bytes reserved:
Once run, the BASIC text of lines 380 to 520 calls for two strings to
be input. These are stored in memory from $C500 and $C600. Note
that the routine cannot handle strings greater than 256 characters in
length (though it could of course be expanded to do so). The length
56
of each string is also required by the routine, so this is ascertained
and stored in the appropriate zero page bytes at $334 and $335 (line
560).
To allow the string buffers to be fully relocatable, the string
addresses are held in two zero page vectors (lines 540 and 550).
String comparison proper starts by evaluating the length bytes to
find out if they are the same length. If they are not equal, then the
strings cannot be identical. However, as the routine returns infor-
mation about the lengths of the strings it is still completed-in this
case the program compares bytes through the length of the smaller
of the two strings.
Byte comparison is performed by lines 170 to 190, using post-
indexed indirect addressing. On the first non-equal characters the
main loop is exited to FINISH. Assu.ming the entire comparison
works, and the X register, which holds the working string length,
has been decremented to zero, the length bytes (lines 250 and 260)
are compared to condition the Zero and Carry flags before the
routine completes.
The short test routine returns the Zero and Carry flag values and
prints them out. indicating the following results:
Returned z C Result
Line-by-Iine
STRINGS UNITE
l A$="REM"
ll B$="ARK"
12 C$=A$+B$
assigns the string 'REMARK' to the string C$. If line 120 were
rewritten as:
12 C$=B$+A$
A$=A$+B$
58
Program 9
60
GET TOTAL
STRING
LENGTH
CALCULATE
TRUNCATION
INDEX
PLACE AT
END OF
STRING 1
ADJUST
INDEXES
& COUNTERS
SIGNAL
ANY END
OVERFLOW
61
86 REM *** PRINT OUT FINAL STRING ***
87 PRINT "FINAL STRING IS :";
88 LOOP=
89 REM ** REPEAT **
9 BYTE=PEEK(F+LOOP)
91 PRINT CHR$(BYTE);
92 LOOP=LOOP+l
93 IF BYTE=13 THEN END
94 GOTO 9
Project
62
Line-by-Iine
COPYCAT
100 A$="CONCATENATE"
110 B$=MID$(A$,0,3)
120 PRINT B$
Running this will output the string 'CON'. What the code has done
is to take the three characters from the first character in the Main$.
Program 10 produces the same type of operation from machine
code.
Program 10
GET INDEX
AND COUNT
LOCATE
BYTE IN
STRING
PLACE IN
SUBSTRING
UPDATE
INDEXES
No
PLACE <RETURN>
IN
SUBSTRING
68
Index Length Substring
o 3 CON
3 3 CAT
4 3 ATE
String
Index
Line-by-line
69
line 360 denote an error by
line 370 setting the error flag
line 380 entry for GREATER-EQUAL
line 390 get length into accumultor
line 400 compare with maximum length
line 410 branch if count is
line 420 greater or equal to maximum length
line 430 put maximum length in accumulator
line 440 store in bytes to copy
line 450 and also in error flag
line 460 entry for COPY-SUBSTRING
line 470 get the index position
line 480 branch to ERROR if zero
line 490 clear accumulator
line 500 and substring length
line 510 entry for LOOP
line 520 get main string index into Y register
line 530 get character from main string
line 540 get substring index
line 550 copy character into substring
line 560 increment main string index
line 570 increment substring index
line 580 decrement bytes to move counter
line 590 branch to LOOP if still bytes to be copied
line 600 decrement final substring count
line 610 get error flag into accumulator
line 620 branch to ERROR if not zero
line 630 FINISH entry
line 640 clear Carry flag as nQ error
line 650 branch to OUT
line 655 entry for ERROR
line 660 set Carry flag to indicate error
line 670 entry for OUT
line 680 place RETURN in accumlator
line 690 get substring index into Y
line 700 increment Y
line 710 place RETURN at end of substring
line 720 return to BASIC.
70
INSERTION
This final routine provides the facility for inserting a string within
the body of another string, allowing textual material-for
example, in word processing applications-to be manipulated. If
the main string held 'ELIZABETH OKAY', this routine could be
called to insert the string 'RULES', so that the final string would
read 'ELIZABETH RULES OKAY'. As with the COPY routine,
the position of the insertion is pointed to by an index byte, and the
Carry flag is set if an error is detected-that is, if an index of0 or a
null substring is specified.
The maximum length of the final string is 256 characters. If the
insertion of the substring would cause this length to be exceeded,
the substring is truncated to the length given by (256 minus length
of main string) and only these characters are inserted.
As always, a BASIC primer demonstrates the routine's use. The
string buffers are held at $C5OO and $C600 and in this instance they
are accessed directly, although there is no reason why vectored
addresses could not be used.
Program 11
71
22 DATA 24 REM CLC
23 DATA 165.252 REM LOA $FC
24 DATA 11.251 REM AOC $FB
25 DATA 176.6 REM BCS $6
26 DATA 21.255 REM CMP I1$FF
27 DATA 24 .18 REM BEQ $12
28 DATA 144.16 REM BCC $1
29 REM CUT-OFF
3 DATA 169.255 REM LDA #$FF
31 DATA 56 REM SEC
32 DATA 229.251 REM SBC $FB
33 DATA 24 . 14 REM BEQ $68
34 DATA 144.12 REM BCC $66
35 DATA 133.252 REM STA $FC
36 DATA 169,255 REM LDA #.$FF
37 DATA 141,53.3 REM STA $335
38 REM CALC-LENGTH
39 DATA 165,251 REM LOA $FB
4 DATA 197.253 REM CMP $FO
41 DATA 176,2 REM BCS $14
42 DATA 166.251 REM LDX $FB
43 DATA 232 REM INX
44 DATA 134.253 REM STX $FD
45 DATA 169.255 REM LDA #$FF
46 DATA 141.53.3 REM STA $335
47 DATA 24 REM CLC
48 DATA 165,251 REM LDA $FB
49 DATA 11 . 252 REM ADC $FC
5 DATA 133 . 251 REM STA $FB
51 DATA 76.19.192 REM JMP $C6D
52 :: REM NO-PROBLEMS
53 DATA 56 REM SEC
54 DATA 165,251 REM LDA $FB
55 DATA 229.253 REM SBC $FD
56 DATA 17 REM TAX
57 DATA 232 REM INX
58 DATA 165 . 251 REM LDA $FB
59 DATA 133.254 REM STA $FE
6 DATA 24 REM CLC
61 DATA 11.252 REM ADC $FB
72
62 DATA 133 , 251 REM STA $FB
63 DATA 141 , 52,3 REM STA $334
64 REM MAKE-SPACE
65 DATA 164 , 254 REM LDY $FE
66 DATA 185 ,,197 REM LOA $C5 , Y
67 DATA 172 , 52,3 REM LOY $334
68 DATA 153,,197 REM STA $C5,Y
69 DATA 26 , 52.3 REM DEC $334
7 DATA 198,254 REM DEC $FE
71 DATA 22 REM OEX
72 DATA 28 , 237 REM BNE $EO
73 REM INSERT-SUBSTRING
74 DATA 169, REM LOA #$
75 DATA 133 , 254 REM STA $FE
76 DATA 166 , 252 REM LOX $FC
77 REM TRANSFER
78 DATA 164 , 254 REM LOY $FE
79 DATA 185,,198 REM LDA $C6 , Y
8 DATA 164 , 253 REM LDY $FE
81 DATA 153 , , 197 REM STA $C5 , Y
82 DATA 23 , 253 REM INC $FD
83 DATA 23,254 REM INC $FE
84 DATA 22 REM DEX
85 DATA 28 , 239 REM BNE $EF
86 DATA 173 , 53 , 3 REM LOA $335
87 DATA 28,3 REM BNE $3
88 REM GOOD
89 DATA 24 REM CLC
9 DATA 144 , 1 REM BCC $1
91 REM ERROR
92 DATA 56 REM SEC
93 REM FINISH
94 DATA 96 REM RTS
95
96 REM ** GET MAIN STRING AND STORE AT
$C5 **
97 PRINT CHR$(147)
98 INPUT"MAIN STRING";B$
99 FOR LOOP=l TO LEN(B$)
l TEMP$=MID$(B$,LOOP , 1)
73
ll B=ASC(TEMP$)
12 POKE MAIN+LOOP-l,B
13 NEXT LOOP
14
15 REM ** GET SUBSTRING AND STORE AT $C600**
16 INPUT"SUB STRING";C$
17 FOR LOOP=l TO LEN(C$)
18 TEMP$=MID$(C$,LOOP,1)
19 B=ASC(TEMP$)
ll POKE SUB+LOOP-l,B
lll NEXT LOOP
112
113 REM ** GET INSERTION INDEX **
114 INPUT"INSERTION INDEX"; X
115
116 REM ** POKE VALUES INTO ZERO PAGE **
117 POKE 251,LEN(B$)
118 POKE 252,LEN(C$)
119 POKE 253, X
12
121 SYS CODE
122
123 REM ** READ FINAL STRING **
124 COUNT=LEN(B$)+LEN(C$)-l
125 FOR LOOP= TO COUNT
126 Z=PEEK(MAIN+LOOP)
127 PRINT CHR$(Z);
128 NEXT LOOP
Line-by-line
77
6 Printing Print!
Program 12
JUMP TO END
RTSADDRESS
21 PRINT CHR$(147)
22 INPUT "INPUT STRING :";A$
23 FOR LOOP=l TO LEN(A$)
24 TEMP$=MID$(A$,LOOP,1)
25 B=ASC(TEMP$)
26 POKE STRING+LOOP-l,B
27 NEXT LOOP
28 PRINT:PRINT
29 PRINT"YOUR STRING WAS AS FOLLOWS .".
3 SYS CODE
Program 13
The final program in this chapter shows the way I find easiest to
store arid print character strings, stowing them directly wjthin the
machine code. The two main advantages of this method are that
the string is inserted directly at the point it is needed, avoiding the
need to calculate indexes into look-up tables, and that because it
manipulates its own address it is fully relocatable.
Program 14
81
28.0 FOR LOOP=.0 TO 38
29.0 READ BYTE
3.0.0 POKE DEMO+LOOP,BYTE
31.0 NEXT LOOP
32.0
33.0 REM ** DEMO M/C DATA **
34.0 DATA 169,147 REM LDA #$93
35.0 DATA 32,21.0,255 :. REM JSR $FFD2
36.0 DATA 32,.0,192 : REM JSR $C.0.0.0
37.0 REM ** NOW STORE ASCII CODES FOR PRINTING **
38.0 DATA 13 : REM CARRIAGE-RETURN
39.0 DATA 83,84,82,73,78,71,83,32
: REM STRINGS<SPACE>
4.0.0 DATA 87,73,84,72,73,78,32
: REM WITHIN<SPACE>
41.0 DATA 77,65,67,72,73,78,69,32
: REM MACHINE<SPACE>
42.0 DATA 67,79,68,69,33
REM CODE!
43.0 DATA 234 REM NOP
44.0 DATA 96 REM RTS
45.0
46.0 SYS DEMO
Line-by-Iine
Program 15
84
15.0 POKE TABLE+(TEMP-l) ,HOLD
16.0 TEMP=TEMP-l
17.0 IF TEMP<>.0 THEN GOTO 12.0
18.0 NEXT
19.0
2.0.0 REM ** DATA FOR SORTING **
21.0 DATA 1,255,67,89,12.0
22.0 DATA 6,2.0.0,85,45,199
23.0 DATA .0,123,77,98,231
24.0 DATA 9,234,99,98,1.0.0
25.0
26.0 REM ** PRINT SORTED DATA **
27.0 FOR LOOP=.0 TO 19
28.0 PRINT PEEK(TABLE+LOOP)
29.0 NEXT LOOP
The data bytes for sorting are held within the four data lines from
210 to 240 and these are read into a memory array called TABLE.
The sorting procedure is perfonned through lines 90 to 180. line 120
checking to see if a swap is required. If a swap is unnecessary.
OOTO 180 is executed and the swap routine bypassed. If it is
required. however, the OOTO statement is not encounted. and the
swap is performed in lines 130 to 160. The byte currently being
pointed to is PEEKed into the variable HOLD (line 130) and the
next byte is PEEKed and then POKEd into the location immedi-
ately before it (line 140). The swap is completed by POKEing the
value of HOLD into the now 'vacant' location. The variable TEMP
is used to keep track of the number of passes through the loop.
27 27 0A
CA 0A I 27
0A I 4C 4C
4C I CA 50
F0 50 I CA
50 I F0 F0
a) b) c)
The next pass through the data list produces the ordered list of
Figure 7.1c in which just two swaps occurred, as follows:
All the data elements are now in their final order, so the next pass
through the list will have no effect. We can signal this by using an
exchange flag to indicate whether the last pass produced any swaps,
the sort routine exiting when the flag is cleared. This detail is
included in the BASIC loader listed below as Program 16.
Program 16
SET
EXCHANGE
FLAG
GET
EXCHANGE
FLAG
L. .______-----------'
Figure 7.2 Bubble sort flowchart
87
16~ DATA 177,253 REM LDA ($FD), Y
17~ DATA 2~9,251 REM CMP ($FB), Y
18~ DATA 176,13 REM BCS $~D
19~ DATA 72 REM PHA
2~~ DATA 177,251 REM LDA ($FB), Y
21~ DATA 145,253 REM STA ($FD), Y
22~ DATA 1~4 REM PLA
23~ DATA 145,251 REM STA ($FB) ,Y
24~ DATA 169,1 REM LDA #$~1
25~ DATA 141,53,3 REM STA $335
26~ REM SECOND-FIRST
27~ DATA 2~~ REM INY
28~ DATA 2~2 REM DEX
29~ DATA 2~8,233 REM BNE $E9
3~~ DATA 173,53,3 REM LDA $335
31~ DATA 24~,5 REM BEQ $~5
32~ DATA 2~6,52,3 REM DEC $334
33~ DATA 2~8,215 REM BNE $D7
335 REM FINISH
34~ DATA 96 REM RTS
35~
36~ REM ** SET UP VECTORS **
37~ REM $FB=$C5~~, $FD=$C5~1
38~ POKE 251,~ POKE 252,197
39~ POKE 253,1 : POKE 253,197
4~~
41~ REM ** SET UP SCREEN AND ARRAY **
42~ PRINT CHR$(147)
43~ PRINT "**** MACHINE CODE BUBBLE SORT ****"
44~ PRINT:PRINT
45~ INPUT"NUMBER OF ELEMENTS IN ARRAY ";N
46~ POKE 82~,N REM LENGTH OF ARRAY
AT $334
47~ FOR LOOP=~ TO N-1
48~ PRINT"INPUT ELEMENT ";LOOP+1;
49~ INPUT A
5~~ POKE TABLE+LOOP,A
51~ NEXT LOOP
52~
53~ REM ** CALL CODE THEN PRINT SORTED TABLE **
88
540 SYS CODE
550 PRINT"SORTED VALUES ARE AS FOLLOWS"
560 FOR LOOP=0 TO N-l
570 PRINT PEEK(TABLE+LOOP)
580 NEXT LOOP
After POKEing the machine code data into memory at $C~, two
zero page vectors are created to hold the address of the TABLE
and TABLE+1 (lines 370 to 390). The program then requests (in
BASIC!) the number of elements in the array, which should be a
series of integer values less than 256. These are then POKEd into
memory (lines 450 to 510). The machine code begins by decrement-
ing the length of array byte by one .(line 100), because the last
element in the array will have no element beyond it to swap with.
The swap flag is then cleared (line 130) and the main loop entered
using the X register to count the iterations.
The LOOP begins by loading the data byte into the accumulator
(line 160) and comparing it with the one immediately preceding it.
If the byte+ 1 is greater than the byte, the Carry flag will be set and
no swap required, in which case the branch to SECOND-FIRST is
executed (line 180).
If a swap is required, the second byte is saved, pushing it on to
the hardware stack. The first byte is then transferred to the second
byte's position (lines 200 and 210) and the accumulator is restored
from the stack and transferred to the position of the first byte (lines
220 to 230). To denote that a swap has occured, the swap flag is set
(lines 240 and 250). The index and counters are then adjusted (lines
270 and 280) and the loop continues until all the array elements
have been compared. Upon completion of a full pass through the
array, the swap flag is checked. If it is clear. no exchanges took
place during the last pass, so the data list is now ordered and the
sort finished (line 300 and 310). If the flag is set. the length of array
byte is decremented and the procedure repeated once more (lines
320 and 330). On return from the SYS call. the now ordered list is
printed out to the screen.
Line-by-line
Projects
Rewrite the BASIC sections of the program to make it a complete
machine code routine.
Adapt the sorting routine to handle 16-bit numbers.
90
8 Software Stack
bit 0 pseudo-register 1
bit 1 pseudo-register 2
bit 2 pseudo-register 3
91
bit 3 Y register
bit 4 X register
bit 5 accumulator
bit 6 Status register
bit 7 Program Counter
The rule here is that if the bit is set, the related register is pushed.
Thus the instructions:
JSR USER-STACK
.BYTE $FF
would push all registers on to the user stack, the embedded byte
being $FF or 11111111. Alternatively, the coding:
JSR USER-STACK
.BYTE $lE
Program 17
92
170 DATA 72 REM PHA
180 DATA 136 REM DEY
190 DATA 208,249 REM BNE $F9
200 DATA 254,5,1 REM INC $UI5, X
210 DATA 189,5,1 REM LDA $105,X
220 DATA 133,139 REM STA $8B
230 DATA 208,3 REM BNE $03
240 DATA 254 , 6,1 REM INC $UI6 , X
250 REM PC-LOW
260 DATA 189,6,1 REM LDA $UI6 , X
270 DATA 133,140 REM STA $8C
280 DATA 169,135 REM LDA #$87
290 DATA 133,141 REM STA $8D
300 DATA 177,139 REM LDA ($8B), Y
310 DATA 133 , 142 REM STA $8E
320 DATA 169,8 REM LDA #$08
330 DATA 133,143 REM STA $8F
340 DATA 136 REM DEY
350 DATA 198 , 252 REM DEC $FC
360 REM ROTATE-BYTE
370 DATA 38,142 REM ROL $8E
380 DATA 144,16 REM BCC $10
390 DATA 189,6,1 REM LDA $106 , X
400 DATA 145,251 REM STA ($FB), Y
410 DATA 136 REM DEY
420 DATA 36,141 REM BIT $8D
430 DATA 16 , 6 REM BPL $06
440 DATA 189 , 5,1 REM LDA $105,X
450 DATA 145 , 251 REM STA ($FB), Y
460 DATA 136 REM DEY
470 REM BIT-CLEAR
480 DATA 202 REM DEX
490 DATA 38 , 141 REM ROL $8D
500 DATA 144,1 REM BCC $01
510 DATA 202 REM DEX
520 REM OVER
530 DATA 198,143 REM DEC $8F
540 DATA 208,226 REM BNE $E2
550 DATA 56 REM SEC
560 DATA 152 REM TYA
93
570 DATA 101,251 REM ADC $FB
580 DATA 133,251 REM STA $FB
590 DATA 144,2 REM BCC $02
600 DATA 230,252 REM INC $FC
610 REM CLEAR-STACK
620 DATA 162,0 REM LOX #0
630 REM REPEAT
640 DATA 104 REM PLA
650 DATA 149,139 REM STA $8B,X
660 DATA 232 REM INX
670 DATA 224,6 REM CPX #$06
680 DATA 208,248 REM BNE $F8
690 DATA 104,168 REM PLA TAY
700 DATA 104,170 REM PLA : TAX
710 DATA 104 REM PLA
720 DATA 40 REM PLP
730 DATA 96 REM RTS
740 REM TEST-ROUTINE
750 DATA 169,240 REM LOA #$F0
760 DATA 162,15 REM LOX #$0F
770 DATA 160,255 REM LOY #$FF
780 DATA 32,0,192 REM JSR $C000
790 DATA 255 REM EMBEDDED-BYTE
800 DATA 96 REM RTS
810
820 REM ** SET UP ZERO PAGE AND FREE RAM **
830 PRINT CHR$(147)
840 POKE 251,12 POKE 252,197
850 FOR N=139 TO 144 POKE N,N NEXT
860 FOR N=50432 TO 50440 : POKE N,0 NEXT
870
880 SYS 49258 : REM SYS TEST-ROUTINE
890
900 REM ** READ RESULTS **
910 FOR LOOP=50432 TO 50443
920 READ NAME$
930 PRINT NAME$;
940 PRINT PEEK(LOOP)
950 NEXT LOOP
960
94
970 DATA "ZERO PAGE ","ZERO PAGE+1"
980 DATA "ZERO PAGE+2","ZERO PAGE+3"
990 DATA "ZERO PAGE+4", "ZERO PAGE+5"
1000 DATA fly REGISTER ","X REGISTER"
1010 DATA "ACCUMULATOR", "STATUS "
1020 DATA "PC LOW ","PC HIGH "
The problem to solve next is that of where to place the user stack.
This will depend on your own requirements, so to make the whole
thing flexible, a vectored address in the bytes at $FB and $FC
contains the stack address. In the program listed above, this is
$C512 (line 840). The vectored address is, in fact, the address + 12.
This is because the stack is pushed in reverse (decreasing) order.
When executed, the coding first pushes all the processor
registers on to the hardware stack and moves the stack pointer
across into the X register (lines 90 to 140). Next, the six zero page
pseudo-registers are pushed there (lines 150 to 190). The return
address from the subroutine call is then incremented on the stack,
using the contents of the X register (stack pointer) to access it (lines
200 to 240). The two bytes that form the RTS address are copied
into pseudo-register 1 (now safely on the hardware stack) to form a
vector though which the embedded data byte can be loaded into
the accumulator and then saved for use in zero page (lines 250 to
310).
In line 280, a pre-defined byte was loaded into the accumulator
and saved in zero page. This byte holds a bit code that will inform
the program as to whether the register being pulled from the
hardware stack for transfer to the software stack is one or two bytes
long. The byte value, $87, is 10000111 in binary and the set bits
correspond to the two-byte registers, the Program Counter and the
three pseudo-registers. By rotating this byte left after each pull
operation and using the BIT operation, the Negative flag can be
tested to see if a further pull is needed. All this and the copy
hardware stack/push software stack is handled by lines 320 to 550.
Finally, the registers and pseudo-registers are restored to their
original values (lines 620 to 730). The test routine between lines 750
and 800 shows the way the program is used. When run, the test
procedure produces the following output on the screen:
As can be seen, the zero page bytes contain the values POKEd into
them by the FOR ... NEXT loop of line 830 while the accumulator
and Index registers display their seeded values (lines 750 to 770).
The Program Counter holds 192 * 256 + 115, or $C073, which was
the point in the program where its contents where pushed at line
780.
This program could be extended to provide a routine to perform
a pull user stack, to copy the contents of a software stack into the
processor and pseudo-registers.
Line-by-Iine
96
line 36.0 entry for ROTATE-BYTE
line 37.0 move next coded bit into Carry flag
line 38.0 if bit clear skip it, branch to BIT-CLEAR
line 39.0 otherwise get byte from stack
line 4.0.0 save it on user stack
line 41.0 decrement index
line 42.0 is it a two byte register?
line 43.0 no, so branch to BIT-CLEAR
line 44.0 yes, so get the second byte from the stack
line 45.0 and save it on the user stack
line 46.0 decrement index
line 47.0 entry for BIT-CLEAR
line 48.0 decrement hardware stack index
line 49.0 move bit of register code into Carry flag
line 5.0.0 if clear, branch to OVER
line 51.0 else decrement hardware stack index
line 52.0 entry for OVER
line 53.0 decrement bit counter
line 54.0 and repeat until all done
line 55.0 set Carry flag
line 56.0 move user stack pointer into accumulator
line 57.0 add to low byte of address
line 58.0 and save
line 59.0 branch to CLEAR-STACK if carry is clear
line 6.0.0 else increment high byte of address
line 61.0 entry for CLEAR-STACK
line 62.0 initialize X register
line 63.0 entry for REPEAT
line 64.0 pull byte from stack
line 65.0 and restore zero page
line 66.0 increment index
line 67.0 all bytes restored?
line 68.0 no, branch to REPEAT
line 69.0 yes, restore all registers
line 73.0 back to calling routine
line 74.0 entry for TEST-ROUTINE
line 75.0 seed registers
line 78.0 call user stack routine
line 79.0 embedded byte
line 8.0.0 back to BASIC
97
BINARY INS AND OUTS
Program 18
Line-by-Iine
accumu1ator=48+carry
0.-1 87 1 86 1 85 1 84 1 83 1 82 1 81 I 881.- 8
87,,\
I 861 85 1 84 1 83 1 82 I 81 1 8S 1 8 I
1 +ASq"W')=ASq"l").
o + ASq"0") = ASq"0")
99
line l3 restore accumulator
line l4 shift bit 7 into carry
line l5 save shifted accumulator on stack
line l6 get ASCII code for 0
line l7 add carry
line l8 print either 0 or 1
line 19 decrement bit counter
line 2 do NEXT-BIT until complete
line 2l pull stack to balance push
line 22 back to BASIC
COME IN
1 87 1 86 1 85 1 84 1 83 1 82 1 81 1 8D 1
I 86 1 85 1 84 1 83 1 82 I 81 I 8D I c I
L~~
Figure 8.2 Input a number directly into the accumulator
100
Program 19
Line-by-Iine
103
9 Move, Fill and Dump
MOVE IT!
The ability to move blocks of memory around within the bounds of
the memory map is a necessity. When manipulating hi-resolution
graphics, for example, large blocks of memory need to be moved
around quickly and smoothlY.,The program could also be used to
relocate sections of machine code rather than rewriting the assemb-
ler that created them-assuming, of course, that your code has
been designed to make it portable.
At first sight, it may seem that the simplest method of moving a
block of memory is to take the first byte to be moved and store it at
the destination address, take the second byte and place it at the
destination address + 1, and so forth. There would be no problem
here if the destination address was outside the source address, but
consider what would happen if the destination address was within
the bounds to be searched by the source address-that is, the two
regions overlapped, Figure 9.1 illustrates the problem using this
straightforward method to move a block of five bytes forward by
just a single byte, relocating the five bytes from $C500 to $C501.
Using the obvious method, the first character, 'S', is moved from
$C500 to $C501 thereby overwriting the 'A'. The program then
takes the next character at location START + 1 ($C501), the'S' that
has just been written there, and places it at START+2 ($C502)
START $C500 S S S S S S
$C501 A S S S
$C502 R R S
$C503 A A S
$C504 H H S
$C505 S
1st 2nd 3rd 4th 5th
Figure 9.1 The overwriting move sequence
104
overwriting the 'R'. As you can see, the end result is SSSSS-the
whole block is full of 'S's-not the required effect!
To avoid this problem, the MOVE routine acts 'intellegently'
and if it calculates that an overwrite would occur, performs the
movement of bytes in the reverse order, starting at the highest
address and moving down the memory map as Figure 9.2 shows.
START $C500 S S S
$C501 A A S
$C502 R R A
$C503 A R
$C504 H A
$C505 H
1st 2nd 3rd 4th 5th
Figure 9.2 The correct move sequence
Program 20
106
61 REM TRANSFER
62 DATA 136 REM DEY
63 DATA 177,253 REM LOA ($FD) ,Y
64 DATA 145,251 REM STA ($FB) , Y
65 DATA 192, REM CPY It$
66 DATA 28,247 REM BNE $F7
67 REM RIGHT-COMPLETE-PAGES
68 DATA 174,53,3 REM LOX $335
69 DATA 24,221 REM BEQ $00
7 REM UPDATE
71 DATA 198,254 REM DEC $FE
72 DATA 198,252 REM DEC $FC
73' :: REM PAGE
74 DATA 136 ," REM DEY
75 DATA 177,253 REM LOA ($FD) ,Y
76 DATA 145,251 REM STA ($FB) ,Y
77 DATA 192, REM CPY It$
78 DATA 28,247 REM BNE $F7
79 DATA 22 REM DEX
8 DATA 28,24 REM BNE $F
81 DATA 96 REM RTS
82
83 REM ** SET UP VARIABLES **
84 PRINT CHR$(147)
85 PRINT" *** MEMORY MOVER V1.1 ***"
86 INPUT"START ADDRESS ";S
87 INPUT"DESTINATION ";0
88 INPUT"LENGTH IN BYTES ";L
89
9 Sl=INT(S!256) S2=S-(Sh256)
91 D1=INT(D!256) D2=D-(Dh256)
92 L1=INT(L!256) L2=L-(Lh256)
93
94 POKE 251,02 POKE 252,01
95 POKE 253,S2 POKE 254,Sl
96 POKE 82,L2 POKE 821,L1
97
98 REM ** SET UP DEMO **
99 FOR N= TO 15
1 POKE 828+N,N
107
1.01.0 POKE 9.0.0+N,.0
1.02.0 NEXT N
1.03.0
1.04.0 SYS CODE
1.05.0
1.06.0 REM ** PRINT THE RESULTS! **
1.07.0 FOR N=.0 TO 15
1.08.0 PRINT PEEK(828+N);" II.
,
1.09.0 PRINT PEEK(9.0.0+~)
11.0.0 NEXT N
Bytes reserved:
When run. the BASIC test requests three inputs: the START
address of the memory block to be moved, its DESTINATION
address and its LENGTH in bytes. All values should be entered as
decimal values. Thus. to move a 1K block of memory from 49152 to
56f11/1/J. the values to input are:
START ADDRESS 49152
DESTINATION 56.0.0.0
LENGTH IN BYTES 1.024
Line-by-line
110
line 7991 decrement page counter
line 89191 if not zero, branch to UPDATE
line 8191 return to BASIC
FILL
Program 21
111
28~DATA 2~~ REM INY
29~ DATA 2~2 REM DEX
3~~ DATA 2~8,25~ REM BNE $FA
31~ REM FINISH
32~ DATA 96 REM RTS
33~
34~ REM ** GET DETAILS **
35~ PRINT CHR$(147)
36~ INPUT"FILL DATA :";F
37~ INPUT"START ADDRESS :";S
38~ INPUT"NUMBER OF BYTES :";L
39~
4~~ Sl=INT(S/256) S2=S-(Sh256)
41~ L1=INT(L/256) L2=L-(Lh256)
42~
43~ POKE 251,L2 POKE 252,L1
44~ POKE 253,S2 POKE 254,Sl
45~ POKE 255,F
46~
47~ SYS CODE
Bytes reserved:
When executed, the machine code expects to find the fill value, the
start address and the amount of memory to be filled, in five zero
page bytes of memory from $FB. Input of each of these is handled
by a few lines of BASIC from line 360. To clear a 1K block of RAM
from $C500with zero, the following information should be entered
in response to the 64's prompt:
FILL DATA ~
START ADDRESS 49152
NUMBER OF BYTES 1~24
112
Line-by-Iine
A MEMORY DUMP
A hex and ASCII dump of memory can be extremely useful, not
only within machine code programs, but also when used from a
BASIC program. Most often it provides information about the way
a program is manipulating numeric and string variables and tables.
Figure 9.3 shows the type of dump produced by the routine:
twenty-four lines of eight bytes each. The example shows some text
stored in memory. Each line starts with the current address, fol-
lowed by the eight bytes stored in memory from that point. The far
right of the listing provides the ASCII equivalents of each byte.
Any non-ASCII character (that is, one greater than $7F) or control
code (those less than $20) is represented by a full stop.
113
Cl08 54 68 69 73 20 69 73 20 This is
CllO 61 20 73 69 60 70 6C 65 a simple
C1l8 20 65 78 61 60 70 6C 65 example
C120 20 6F 66 20 68 6F 77 20 of how
C128 74 68 65 20 80 64 75 60 the .dum
C130 70 20 72 6F 75 74 69 6E p routin
C138 65 20 66 6F 72 20 74 68 e for th
C140 65 20 43 6F 60 60 6F 64 e Commod
C148 6F 72 65 20 36 34 20 80 are 64 .
C150 77 6F 72 6B 73 2E 00 54 works T
C158 68 65 20 64 75 60 70 20 he dump
C160 63 61 6E 20 62 65 20 64 can be d
C168 69 76 69 64 65 64 20 69 ivided i
C170 6E 74 6F 20 74 68 72 65 nto thre
C178 65 20 80 73 65 63 74 69 e .secti
C180 6F 6E 73 2E 20 54 68 65 ons. The
C188 20 66 69 72 73 74 20 63 first c
C190 6F 6C 75 60 6E 20 6C 69 olumn 1 i
C198 73 74 73 20 74 68 65 20 sts the
C1AO 80 73 74 61 72 74 20 61 .start a
C1A8 64 64 72 65 73 73 20 6F ddress a
C1BO 66 20 74 68 65 20 62 6C f the bl
C1B8 6F 63 6B 2E 20 54 68 65 ock. The
C1CO 20 73 65 63 6F 6E 64 20 second
C1C8 80 63 6F 6C 75 60 6E 20 .column
Cl00 69 73 20 69 6E 20 66 61 is in fa
Cl08 63 74 20 74 68 65 20 68 ct the h
ClEO 65 78 61 64 65 63 69 60 exadecim
C1E8 61 6C 20 80 76 61 6C 75 .301 .valu
C1FO 65 73 20 6F 66 20 65 69 es of ei
C1F8 67 68 74 20 62 79 74 65 ght byte
C200 73 20 66 72 6F 60 20 74 s from t
C208 68 69 73 20 80 61 64 64 his add
C210 72 65 73 73 2E 20 46 69 ress. Fi
C218 6E 61 6C 6C 79 20 74 68 nally th
C220 65 20 6C 61 73 74 20 63 e last c
C228 6F 6C 75 60 6E 20 80 64 olumn .d
C230 65 70 69 63 74 73 20 74 epicts t
C238 68 65 20 41 53 43 49 49 he ASCII
C240 20 76 61 6C 75 65 73 20 values
C248 6F 66 20 74 68 65 73 65 of these
C250 20 80 62 79 74 65 73 2E .bytes.
C258 20 75 6E 6C 65 73 73 20 unless
C260 74 68 65 20 62 79 74 65 the byte
C268 20 69 73 20 6E 6F 6E 20 is non-
C270 41 53 43 49 49 20 80 77 ASCII .w
C278 68 69 63 68 20 69 73 20 hich is
C280 74 68 65 6E 20 64 69 73 then dis
C288 70 6C 61 79 65 64 20 61 played a
C290 73 20 61 2G 66 75 6C 6C s a full
C298 20 73 74 6F 70 21 00 00 stop ~ ..
. .- . - -..
C2AO 00 4C 00 C9 A9 FF 85 22 L "
C2A8 08 60 00 00 00 00 00 00
114
As it stands, the routine requires three zero page data bytes, two
for the start address and one for the number of eight byte lines to be
dumped. The routine also employs the ADDRESS-PRINT and
HEXPRINT routines discussed earlier.
Program 22
115
34.0 DATA 32.21.0.255 REM JSR $FFD2
35.0 DATA 2.0.0 REM INY
36.0 DATA 2.02 REM DEX
37.0 DATA 16 . 237 REM BPL $ED
38.0 DATA 169 . 13 REM LDA 1I$.0D
39.0 DATA 32.21.0 . 255 REM JSR $FFD2
4.0.0 DATA 24 REM CLC
41.0 DATA 165.251 REM LOA $FB
42.0 DATA 1.05 . 8 REM ADC 11$.08
43.0 DATA 133 . 251 REM STA $FB
44.0 DATA 144.2 REM BCC $.02'
45.0 DATA 23.0.252 REM INC $FC
46.0 REM NO-CARRY
47.0 DATA 198.254 REM DEC $FE
48.0 DATA 2.08.191 REM BNE $BF
49.0 DATA 96 REM RTS
5.0.0 REM SPACE
51.0 DATA 169 . 32 REM LDA 11$2.0
52.0 DATA 76 . 21.0 . 255 REM JMP $FFD2
53.0 REM ADDRESS-PRINT
54.0 DATA 162 . 251 REM LDX II$FB
55.0 DATA 181.1 REM LDA 1 . X
56.0 DATA 32 . 9.0 . 192 REM JSR $C.05A
57.0 DATA 181 . .0 REM LDA .0 . X
58.0 DATA 32.9.0 . 192 REM JSR $C.05A
59.0 DATA 32.66 . 192 REM JSR $C.042
6.0.0 DATA 32.66 . 192 REM JSR $C.042
61.0 DATA 96 REM RTS
62.0 REM HEXPRINT
63.0 DATA 72 REM PHA
64.0 DATA 74.74 REM LSR A : LSR A
65.0 DATA 74.74 REM LSR A : LSR A
66.0 DATA 32 . 99 . 192 REM JSR $C.063
67.0 DATA 1.04 REM PLA
68.0 REM FIRST
69.0 DATA 41.15 REM AND 1I$.0F
7.0.0 DATA 2.01.1.0 REM CMP 1I$.0A
71.0 DATA 144.2 REM BCC $.02
72.0 DATA 1.05 . 6 REM ADC 11$.06
73.0 :: REM OVER
116
74~ DATA 1~5,48 REM ADC #$3~
75~ DATA 76,2l~,255 REM JMP $FFD2
76~
77~ REM ** INPUT DETAILS FOR DUMP **
78~ PRINT CHR$(147)
79~ INPUT"DUMP START ADDRESS ";A
8~~ HIGH=INT(A/256)
8l~ LOW=A-(HIGH*256)
82~ POKE 25l,LOW : POKE 252,HIGH
83~ INPUT"NUMBER OF LINES (2~/SCREEN) ";8
84~ POKE 254,B
85~ SYS CODE
Line-by-Iine
119
10 HI-res Graphics
1. Move start of BASIC user area and set position for hi-res
screen.
2. Clear screen memory.
3. Select screen colour and clear to that colour.
4. Reselect normal character mode.
120
A BASIC MOVE
Program 23
Line-by-Iine
122
SELECTING HI-RES
Table 10.1
You can see from the table that the screen memory may be moved
around in 2K block steps. An 'x' in each of the other bits denotes
that these bits may be in either state. However, remember that
these bits are controlling other aspects of the VIC's function, so
that any reprogramming of bits 3,2 and 1 must preserve the other
bits. This is best done with the logical OR function. Looking at
Table 10.1 we can see that bit 3 must be set to point the Memory
Control register at location 8192. In BASIC this would simplify to:
LOA #$08
ORA $0018
STA $0018
Now that the hi-res screen has been defined, it can be switched in
by setting bit 5 of the VIC Control register at $D011 (53265).
123
Again, the other bits in the register must be preserved, so the byte
must be ORed with 32 (OO1~ binary). In BASIC this is:
and in assembler:
LOA #$20
ORA $0011
STA $0011
A CLEAR VIEW
Once hi-res mode has been selected, it will be filled with junk
(often referred to as garbage). To clear this, each location must in
turn be POKEd with zero. A BASIC program to do this would take
the form:
200 SB=8192
210 FOR L=SB TO SB+7999
220 POKE L,0
230 NEXT L
Program 24
125
31.0 DATA 76,62,192 REM JMP $C3E
32.0 REM CLEAR
33.0 DATA 16.0,.0 REM LOY #$.0.0
34.0 DATA 169,.0 REM LOA #$.0.0
35.0 DATA 145,251 REM STA ($FB), Y
36.0 DATA 23.0,251 REM INC $FB
37.0 DATA 2.08,231 REM BNE $E7
38.0 DATA 23.0,252 REM INC $FC
39.0 DATA 56 REM SEC
4.0.0 DATA 176,226 REM BCS $E2
41.0
42.0 REM COLOUR
43.0 DATA 169,.0 REM LOA #$.0.0
44.0 DATA 133,251 REM STA $FB
45.0 DATA 169,4 REM LOA #$.04
46.0 DATA 133,252 REM STA $FC
47.0 DATA 169,231 REM LOA #$E7
48.0 DATA 133,253 REM STA $FD
49.0 DATA 169,7 REM LOA #$.07
5.0.0 DATA 133,254 REM STA $FE
51.0 REM CIN
52.0 DATA 165,252 REM LOA $FC
53.0 DATA 197,254 REM CMP $FE
54.0 DATA 2.08,7 REM BNE $.07
55.0 DATA 165,251 REM LOA $FB
56.0 DATA 197,253 REM CMP $FD
57.0 DATA 2.08,1 REM BNE $.01
58.0 DATA 96 REM RTS
59.0 REM GREEN
6.0.0 DATA 16.0,.0 REM LOY #$.0.0
61.0 DATA 169,13 REM LDA #$.00
62.0 DATA 145,251 REM STA ($FB), Y
63.0 DATA 23.0,251 REM INC $FB
64.0 DATA 2.08,233 REM BNE $E9
65.0 DATA 23.0,252 REM INC $FC
66.0 DATA 56 REM SEC
67.0 DATA 176,228 REM BCS $E4
126
Line-by-Iine
127
line 550 get low byte of current address
line 560 is it the same as the low byte end address?
line 570 no, branch to GREEN
line 580 back to calling routine
line 590 entry for GREEN
line 600 clear indexing register
line 610 get code for green into accumulator
line 620 POKE it into colour memory
line 630 increment low byte of current address
line 640 branch to CIN if no carryover
line 650 increment high byte
line 660 set Carry flag
line 670 and force branch to CIN
128
Appendix 1: 6510 Complete
Instruction Set
129
ASL Shift left NZC
130
BIT Z,N,V
131
BRK Break B flag = 1
132
CLD Clear Decimal flag o flag = 0
133
CPX Compare X register NZC
134
DEY Decrement Y register NZ
EOR Exclusive-OR NZ
135
INX Increment X register NZ
136
LOA Load accumulator NZ
137
LSR Logical shift right N = 0,ZC
ORA Inclusive OR NZ
138
PUA Push accumulator Flags unaltered
139
ROL Rotate left NZC
140
RTS Return from subroutine Flags unaltered
141
SEI Set Interrupt flag 1=1
142
STY Store Y register Flags unaltered
143
TXA Transfer X to accumulator NZ
144
Appendix 2: 6510 Opcodes
145
38 SEC implied 50 EOR absoltlte, X
39 AND absolute, Y 5E LSR absolute, X
3A Future expansion 5F Future expansion
3B Future expansion 60 RTS implied
3C Future expansion 61 ADC (zero page, X)
3D AND absolute, X 62 Future expansion
3E ROL absolute, X 63 Future expansion
3F Future expansion 64 Future expansion
40 RTI implied 65 ADC zero page
41 EOR (zero page, X) 66 ROR zero page
42 Future expansion 67 Future expansion
43 Future expansion 68 PLA implied
44 Future expansion 69 ADC Itimmediate
45 EOR zero page 6A ROR accumulator
46 LSR zero page 6B Future expansion
47 Future expansion 6C JMP (indirect)
48 PHA implied 60 ADC absolute
49 EOR Itimmediate 6E ROR absolute
4A LSR accumulator 6F Future expansion
4B Future expansion 70 BYS relative
4C JMP absolute 71 ADC (zero page), Y
40 EOR absolute 72 Future expansion
4E LSR absolute 73 Future expansion
4F Future expansion 74 Future expansion
50 BYC relative 75 ADC zero page, X
51 EOR (zero page), Y 76 ROR zero page, X
52 Future expansion 77 Future expansion
53 Future expansion 78 SEI implied
54 Future expansion 79 ADC absolute, Y
55 EOR zero page, X 7A Future expansion
56 LSR zero page, X 7B Future expansion
57 Future expansion 7C Future expansion
58 CLI implied 7D ADC absolute, X
59 EOR absolute, Y 7E ROR absolute, X
5A Future expansron 7F Future expansion
5B Future expansion 80 Future expansion
5C Future expansion 81 ST A (zero page, X)
146
82 Future expansion A7 Future expansion
83 Future expansion A8 TAY implied
84 STY zero page A9 LOA lIimmediate
85 ST A zero page AA TAX implied
86 STX zero page AB Future expansion
87 Future expansion AC LOY absolute
88 DEY implied AD LOA absolute
89 Future expansion AE LOX absolute
8A TXA implied AF Future expansion
8B Future expansion B0 BCS relative
8C STY absolute BI LOA (zero page). Y
80 ST A absolute B2 Future expansion
8E STX absolute B3 Future expansion
8F Future expansion B4 LOY zero page. X
90 BCC relative 85 LOA zero page. X
91 ST A (zero page). Y B6 LOX zero page. Y
92 Future expansion B7 Future expansion
93 Future expansion B8 CLY implied
94 STY zero page. X 89 LOA absolute. Y
95 STA zero page, X 8A TSX implied
96 STX zero page, Y BB Future expansion
97 Future expansion BC LOY absolute, X
98 TYA implied BO LOA absolute. X
99 ST A absolute, Y BE LOX absolute. Y
9A TXS implied BF Future expansion
9B Future expansion C0 CPY lIimmediate
9C Future expansion Cl CMP (zero page. X)
90 ST A absolute, X C2 Future expansion
9E Future expansion C3 Future expansion
9F Future expansion C4 CPY zero page
A0 LOY lIimmediate C5 eMP zero page
Al LOA (zero page. X) C6 DEC zero page
A2 LOX lIimmediate C7 Future expansion
A3 Future expansion C8 INY implied
A4 LOY zero page C9 CMP #immediate
A5 LOA zero page CA OEX implied
A6 LOX zero page CB Future expansion
147
CC CPY absolute E6 INC zero page
CD CMP absolute E7 Future expansion
CE DEC absolute E8 INX implied
CF Future expansion E9 SBC lIimmediate
00 BNE relative EA NOP implied
01 CMP (zero page), Y EB Future expansion
D2 Future expansion EC CPX absolute
D3 Future expansion ED SBC absolute
04 Future expansion EE INC absolute
D5 CMP zero page, X EF Future expansion
06 DEC zero page, X F0 BEQrelative
07 Future expansion FI SBC (zero page), Y
08 CLD implied F2 Future expansion
09 CMP absolute, Y F3 Future expansion
DA Future expansion F4 Future expansion
DB Future expansion F5 SBC zero page, X
DC Future expansion F6 INC zero page, X
DO CMP absolute, X F7 Future expansion
DE DEC absolute. X F8 SED implied
OF Future expansion F9 SBC absolute, Y
E0 CPX lIimmediate FA Future expansion
EI SBC (zero page. X) FB Future expansion
E2 Future expansion FC Future expansion
E3 Future expansion FD SBC absolute, X
E4 CPX zero page FE INC absolute, X
E5 SBC zero page FF Future expansion
148
Appendix 3: Commodore 64
Memory Map
FFFF
DCOO'
Colour RAM
D800'
VIC and SID
'Free'RAM
Program area
Screen memory
400
Kernal vectors and flags
300
Input buffers
200
Stack
1m
Zero page
149
Appendix 4: Branch Calculators
The branch calculators are used to give branch values in hex. First, count the number of
bytes you need to branch. Then locate this number in the centre of the appropriate table,
and finally, read off the high and low hex nibbles from the side column and top row
respectively.
Locate 16 in the centre of Table A4.1 (bottom row), then read off high nibble (lIF) and
low nibble (#0) to give displacement value (#F0).
:sN 8
9
0
128
112
2
127 126
III 110
3 4 5
1I8
102
B
117
101
C
116
100
0
115
99
E
114
98
F
II3
97
A 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81
B 80 79 n 77 76 75 74 73 72 71 70 69 68 67 66 65
C 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49
0 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33
E 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
F 16 15 14 I3 12 II 10 9 8 7 6 5 4 3 2 I
0 2 3 4 5 6 7 8 9 A B C 0 E F
0 0 I 2 3 4 5 6 7 8 9 10 II 12 13 14 15
I 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
2 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
3 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
4 64 66 66 67 68 69 70 71 72 73 74 75 76 77 78 79
5 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
6 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 III
7 112 113 1I4 115 1I6 117 1I8 119 120 121 122 123 124 125 126 127
150
Index
151
Other titles of interest
This form should be taken to your local bookshop or computer store. Incase of
difficulty, write to Shiva Publishing Ltd, FreeposL 64 Welsh Row. Nantwich.
Cheshire CW5 5BR, enclosing a cheque for .......................... .