Sunshine Books Commodore 64 Machine Code Master a

Page 1
commodore 64
machine code moster
A library of machine code routines
david lawrence& markengland
Page 2
Page 3
commodore 64
machine code master
A library of machine code routines
Page 4
First published 1983 by: Sunshine Books (an imprint of Scot Press Ltd.) Hobhouse Court,
19 Whitcomb Street,
London WC2 7HF
Copyright © David Lawrence and Mark England Reprinted December 1983
ISBN 0 946408 05 X
All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, elec tronic, mechanical, photocopying, recording and/or otherwise, without the prior written permission of the Publishers.
Cover design by Graphic Design Ltd. Illustration by Stuart Hughes. Typeset and printed in England by Commercial Colour Press, London E7.
2
Page 5
C O N T E N T S
Page
Foreword 7 Parti
1 Mastercode Monitor 11
2 Mastercode Disassembler 27
3 Mastercode File Editor 41
4 Mastercode Assembler 57
Part 2
5 The BASIC Extender 97
6 The BASIC/Machine Code Patch 103
7 BASIC Extender Program II 119
8 Simple BASIC Action Keywords 123 9 The Problem of Parameters 137 10 BASIC Functions 167 11 Breaking New Frontiers 173
Appendices
A Checksum Generator 177
B Mastercode User Guide 181
C Table of Variables 185
D Table of Subroutine Functions 187
E ROM Routines Called 189
F Table of Control Characters 191
3
Page 6
Page 7
Contents in detail
CHAPTER 1 Mastercode Monitor
Examining memory contents, altering them, saving and loading machine code programs.
CHAPTER 2 Mastercode Disassembler
Translating the 64 ROM or our own machine code programs into assembly language.
CHAPTER 3 Mastercode File editor
Entering assembly language programs and saving and loading them.
CHAPTER 4 Mastercode Assembler
Creating machine code programs from assembly language, including automatic error checking.
CHAPTER 5 The BASIC Extender
How to transfer the contents of the 64’s BASIC Interpreter to user memory.
CHAPTER 6
The BASIC/Machine Code Patch
All the machine code techniques needed for extending the BASIC
language.
5
Page 8
Machine Code Master
CHAPTER 7
The BASIC Extender II
The final changes to link extended BASIC to the existing interpreter.
CHAPTER 8
Simple BASIC Action Keywords
Undead, Subex and Rkill.
CHAPTER 9
The Problem of Parameters
Picking up parameters from a BASIC program. Keywords: DOKE, PLOT, DELETE, BSAVE, BLOAD, BVERIFY, MOVE, FILL and RESTORE.
CHAPTER 10 BASIC Functions
Extending the 64s mathematical functions. Keywords: DEEK, VARPTR, YPOS.
CHAPTER 11
Breaking New Frontiers
The FAST command that wasnt.
APPENDICES:
A) Checksum Generator: test your Mastercode Program as you enter it. B) A User Guide to the Mastercode program. C) A complete table of the variables found in the Mastercode program
and their uses.
D) A quick guide to the purpose of each subroutine in the Mastercode
program.
E) The ROM routines called upon by extended BASIC and what they
do.
F) Representation of control characters in the Mastercode program.
6
Page 9
FOREWORD
This is not yet another machine code book for a popular micro which
spends half its pages explaining all the 6502/6510 machine code instruc tions and their various addressing modes, with a crude loader program and a number of machine code routines of dubious usefulness tacked onto the end. The intention of this book is to provide its readers with a solid BASIC
program for the entry of machine code and assembly language routines and, along with it, a selection of machine code programs that are worth having.
The BASIC program is called Mastercode and it is just about a complete machine code programming tool, containing a Monitor to allow you to examine and change the contents of memory, a Disassembler which trans
lates machine code programs into assembly language format, and a File Editor and Assembler which together allow assembly language programs to be developed and transformed into machine code.
For the machine code routines in the second half of the book we have adopted a new approach. What you will find there is a collection of routines which you can use to extend the BASIC language on your 64 with
14 new commands. Apart from increasing the power of BASIC it will also help you to learn the techniques o f effective machine code programming and the ways in which the machine code programmer can make use of the routines already built into the 64s BASIC Interpreter.
The book is not intended to be a primer in machine code. That is not to say that it cannot be used by beginners. It is simply that we have assumed that you will possess, or can get hold of, some other book which explains each 6502/6510 instruction in detail. We decided that we could offer better value by concentrating on the programs themselves and on explaining the techniques that went into them. If you have to look up the odd instruction in your 6502 text-book it will be a small price to pay.
All the programs in the book have been tested in fact the Mastercode program itself has been tested to exhaustion (ours). The machine code routines in this book have all been developed on the Mastercode program because only in that way could we be sure that you would be able to do the same. If you run into bugs in anything you find in this book then the blame is on us but we venture to suggest that they will not be major after the testing that has been put in.
The book is a cooperative venture between two people with very dif
ferent backgrounds. David Lawrence writes mainly BASIC programs and
7
Page 10
Machine Code Master
is the author of several books on microcomputing. His interest in computer hardware is minimal. Mark England studies electronic engineering, juggles
with silicon chips as if it were second nature and learned to write machine code when the BASIC ROM on his micro burned out. He discovered he
didnt need it anyway.
The idea came from David Lawrence, who was tired of buying machine
code books that never seemed to provide anything of interest when he
actually worked through them. Mark England did the vast majority of the
programming, though not without heckling. The final form of the book
arises out of Mark Englands need to explain to his co-author just what the programs were about and have it translated for lesser mortals. In that process of explanation and discussion a style of commentary and expla nation has developed which, we believe, does justice to the programs and to the reader’s need to understand them.
The other partner in the writing of this book has been the Commodore
64. The book would not have been a possibility on many other home micros. It is only because of Commodores philosophy of opening up their machines to the programmer, providing access to a host of facilities and routines within the interpreter that others seem to do their best to lock away, that we have been able to take 64 BASIC apart and put it together again. We have had some arguments with the 64, but it remains an invaluable machine for those who wish to go beyond BASIC.
Finally, our thanks are due to the staff of the Microchips shops in Winchester and Southampton, who provided invaluable help when it came to seeking out equipment and supplies. Thanks are also due to Jane Law rence who regularly, on her way to bed as we pounded the keyboard into the early hours, told us what a wonderful job we were doing. We hope she was right.
8
Page 11
Parti
Page 12
Page 13
CHAPTER 1
Mastercode Monitor
Every computer program, regardless of the language in which it is written, begins its life as a series of instructions stored in a coded form within the computers memory. In the case of most languages, the instructions which make up the program are quite meaningless to the central processing unit or CPU, the computer-within-a-computer which will eventually be called
on to execute the tasks dictated by the program. To overcome this prob
lem, standing in between the program entered by the user and the CPU will be yet another program, most often built into the machine at the time of its
manufacture, which takes the users program and translates it into a form
which the CPU is able to understand
The permanent, built in program, however, performs another fun
ction, for without its help it would be impossible for the user to enter
instructions in the first place. From the moment that the computer is
switched on, the built in program begins its task of scanning the key board
to detect an input from the outside world. It then takes those inputs and
stores them in the memory in such a way that they can later be interpreted for the CPU. The user who writes programs in BASIC will seldom be aware of this process. Program lines will be entered, the return key pressed and the line will become part of the program provided that the correct
grammar of BASIC has been observed. No real effort or thought is
required to insert a new instruction into the program, either at the end or embedded in the middle, for the computers memory is automatically re arranged to make space for the new input.
When we turn to programming in machine code, the situation is not quite as simple. There are no facilities built into the computer to allow a new instruction to be simply entered from the keyboard in the confidence that it will automatically be entered into the computers memory and the present contents rearranged to make room for it. The first task of a machine code programmer is, therefore, to devise a method of entering instructions, examining memory and rearranging it to suit the developing needs of the program that is being entered. This is true whether the machine code instructions are being entered directly in the form of num bers (which is the eventual form in which they must be presented to the CPU) or by means of a special language called assembly language which makes machine code programs easier to enter and understand. The sim
11
Page 14
Machine Code Master
plest tool which allows the necessary management of the memory to take place is called a Monitor and in this chapter we shall build up a flexible Monitor program which will allow you to examine individual bytes of memory or extensive chunks and to modify their contents at will.
SECTION 1: Initialisation and Menu
MODULE 1.1
1 0 00 0 R E M * ** * * * ** * * ** * * * ** * * * ** * * * ** * * *
3.0020 REM GENERAL IN ITIALISATION
3.0030 REM** *** **** *** **** *** ******* *** *
3.003 3. BASE = 16 10032 IF LEN (FTRT) +LEN (ET) < >255 THEN CL.R
: G03UB 19000
10035 DEV = 1
3.0040 DEFFN HEX(X) = (X AND 15)+48-<(X A
ND 15)>9)*7
3.0050 DEFFN DEC ( X ) = X-48+ < X >57) *7 10060 FALSE = 0 ; TRUE = -1 10070 POKE 53281,1 : POKE 53 28 0,15
The purpose of this module is to set up a number of variables which will be used later in the program. The function of the variables is explained briefly in the table given in Appendix but full understanding will only come as subsequent sections of the program are entered and the variables actually used. At this stage it is enough simply to enter the module correctly the only visible effect of RUNning it will be to change the screen colour.
CHECKSUM TABLE
10000 123
10031 3.16
10040 182
10020 238 10032 .1.64
3.0050 3.32
10030 123 10035 2
3.0060 21
10070 220
This table of checksums is here to help you ensure that you make no errors in the entry of what will be a long and complex program. For an understanding of how to use the table see Appendix A, which gives the listing of the checksum program to be added to the end of the Mastercode program when you start, enabling you to generate your own checksum tables for comparison with those given in the book.
12
Page 15
Chapter 1 Mastercode Monitor
MODULE 1.2
19000 REM****************************** 19001 REM TEMPORARY LINES 19002 REM****************************** 19010 RETURN 19011 REM ***END OF MONITOR PROGRAM***
This temporary module is placed into the program at this point to allow for the fact that the initialisation routine calls up a later section of the Mas tercode program which will not be entered yet. The lines contained in this module will be overwritten when subsequent sections of the Mastercode program are entered. The format is not critical, so no checksum table is needed.
MODULE 1.3
mr
10100 REM****************************** 10101 REM CONTROL ROUTINE FOR MONITOR 10102 REM****************************** 10110 DATA EXIT TO BASIC,MEMORY MODIFY,M
EMORY DUMP,MACHINE CODE EXCUTE
10111 DATA LOAD MACHINE CODE FILE,SAVE M
ACHINE CODE FILE
10120 DATA DISASSEMBLER
10130 DATA FILE EDITOR
10140 DATA ASSEMBLER
10190 DATA END
10200 RESTORE
10220 X = 0 10230 PRINT " [BLUE 3 CCLR3
E CODE MO NI TO R
----------
----------
MACH IN
CGREEN3 CCD3" 10250 READ T$ 10260 IF T*<>"END" THEN PRINT TA B (5) X " )" T$ : X= X+l s GOTO 10250 10265 IF X<15 THEN FOR Y = X TO 15 s PRI
NT s NEXT
10270 PRINT "COMMAND ( 0 X-l " ) : "; : INPUT T 10300 IF T<0 OR T>X THEN 10100
10305 IF T=0 THEN PRINT "CCLR3 C4*CD3
CRVS ON3BYECRVS OFF3C4*CD3"
: CLOSE 1 : END
10310 ON T GOSUB 13100,13300,13500,14300
,14100,15800,24800,20000
10320 GOTO 10100
13
Page 16
Machine Code Master
Every complex program needs to provide the user with a means of selecting which of its many functions is to be used next. Such a facility is called a control routine or, more simply, a menu. The menu given here is more complex than it need strictly have been for the current program. This is because the Monitor program is designed so that it can later be extended by adding subsequent sections of the overall Mastercode Assem bler. Rather than having to enter new program lines to take account of the extra functions that will be provided, the menu will automatically extend itself to take account of new option names entered into the data statements.
CHECKSUM TABLE
10100 123 10101 101 101 10 180 10111 10130 170 10140
62 10120
65 10190 10200 140 10220 122 10250 31 10260 210
10270
234
10:300 8
10102 123
10230 10265
/I0305
1 192 160
10310 199 10320 155
SECTION 2: Output of Memory Contents to Screen
In this section of the program we shall examine those sections of the pro
gram which are necessary to enable us to print out, in an orderly fashion,
the contents of a specified area of memory. The modules commented on here may appear very insignificant and you may wonder why it is that they have not been run together to make one module. As you continue through the Mastercode program, however, you will see that individual modules may actually be called up for use from many different parts of the pro gram. Keeping the modules to one particular function and one only will enable us to save on the eventual number of program lines employed rather than have to duplicate the same lines later in another section of the pro
gram.
14
Page 17
Chapter 1 Mastercode Monitor
MODULE 1.4
1 1(300 REM********* ********* *** ****** *** 11001 REM CONVE RT DEC IMAL TO HEX 11002 REM* *** *** *** *** *** *** *** *** ***** 11010 T = H s H$ = "" 11020 H* = CHR* ( FNHE X<T -INT <T/ 16>* 1 6) )+H
* s T = I NT (T /16) : IF T>0 THEN 11020
11050 RETURN
This three line module transforms a decimal number into a hexadeci mal number, that is one with a base of 16 rather than a base of 10. Machine-code programmers almost universally use hexadecimal num bers, for the simple reason that they conform much more logically to the system of binary arithmetic used by a computer.
The hexadecimal numbering system has 16, rather than 10 digits, as follows: 0123456789ABCDEF. Most modern computers store numbers in units of 256 (0 - 255), and the reason that hexadeci mal is so convenient is that with a two digit hexadecimal number, the maximum value which can be expressed is also 255 (15*16 for the high digit and 15 for the low). Using hexadecimal means that a much more orderly representation of the values stored in memory can be made. In addition, the binary system used by the computer means that very often apparently significant numbers in hexadecimal like 1000 (or 4096 in decimal) are also significant in terms of the operation of the
computer. Beginning to think in hexadecimal is an important aid to
beginning to understand the workings of the micro.
Commentary
11020: The operation of this line is b$st explained by use of an exam
ple. Assume that the decimal number 4875 has been stored in the
variable H. To convert that value into hexadecimal, we need to first
recognise that it is made up of 1*16|3 (16|3 = 4096) + 3*16|2 (16|2 = 256)+ 0*16|1 (16jl = 16) + ll*16t0(16|0 = 1). This line isolates
each of these units of different powers of 16 and then translates them
into a character which represents the appropriate hexadecimal digit, using the user defined function FNHEX (see line 10040) to select the
correct character. In the case of 4875 the hexadecimal number will be
130B. For units with a value from 0 to 9, FNHEX simply returns the
value of the appropriate character 0 - 9 (character codes 48 - 57). If the
value of the unit is from 10 - 15, then a further 7 is added to the cha
racter code value to take it into the range A - F in the 64s character set.
15
Page 18
Machine Code Master
CHECKSUM TABLE
11000 123
11010 170
MODULE 1.5
11001 167 11020 74
11002 123 11050 142
11951 REM CO NV ER T HEX IN H* TO DEC IN H 11952 REM***************-******* ******** 11975 ERR = FALSE : H = 0 s IF LEN<H*>= 0
THEN 12030 11980 FOR X = 1 TO LE N(H T ) 11990 T = F N DE C< A S C (M ID *<H * , X , 1 > ) ) : H =
H*BASE+T
12010 IF T > BAS E 1 DR T<0 THEN ERR = TRUE 12020 NEXT X 12030 RETURN
READY.
Although it is more sensible to input numbers in hexadecimal, working
in BASIC does mean that they have to be translated into ordinary decimal
for use by the program. This is accomplished by the current module.
Commentary
11975: Throughout the program the variable ERR (error) will be used to indicate that an error has been discovered. The normal value of ERR will
be 0, which is the value assigned to the variable FALSE in the initialisation routine. Whenever an error is detected ERR is reset to the value of TRUE, which is minus one. The point behShd using these truth* values is that it also allows ERR to be set by a statement such as ERR = (A>50). The expression in brackets has a value according to whether it is true or false. If
false it will take the value zero, if true it will have the value minus one. By this means ERR can be set to show that something is wrong much more
economically than using statements such as IF A> 50 THEN ERR = -1.
11980-12020: Examining each character of the string H$ in turn, this loop extracts the decimal value of the hexadecimal character using the user defined function FNDEC (line 10050). Since the loop works from the left, the result obtained so far must be multiplied by 16 for each subsequent hexadecimal digit. If a character outside the range 0 - F is input, the ERR variable is set to minus one as a warning to subsequent modules.
16
Page 19
Chapter 1 Mastercode Monitor
CHECKSUM TABLE
11950 123V 11951 230- 11952 123-
11975 142/ 11980 1287 11990 40-
12010 208V 12020 2501 12030 1427
MODULE 1.6
12050 REM************************'****** 12051 REM INPUT START ADDRESS 12052 REM****************************** 12057 H* = / 12060 INPUT "START ADDRESS ( IN HEX ) :
H* : GOS UB11950
12080 IF ERR OR H<0 OR H >65535 THEN 1206
0
12090 AD = H : RETURN
When printing the contents of an area of memory to the screen, it is necessary to specify the start point in memory. This is done in hexadecimal, and the input is then translated into decimal by the previous module.
CHECKSUM TABLE
12050 123 12051 19 12052 123 12057 162 /12060 50 12080 128 12090 199
MODULE 1.7
11850 REM******************************
11851 REM ASK CONTINUE ?
11852 REM******************************
11858 T$ = ""
11860 INPUT "CONTINUE ( Y/N ) : "; T$
11870 IF T$="Y" THEN CO = TRUE : GOTO 11
895
11880 IF T*<>"N" THEN PRINT "CCU3"; : GO TO 11850
11890 CO = FALSE 11895 RETURN
When an area of memory is dumped to the screen, this module is called to enquire whether the user wishes to continue with another.
17
Page 20
Machine Code Master
CHECKSUM TABLE
11850
11858
11880
MODULE 1.8
11100 11101
123 11851 174 11860
235 11890
REM* ****** *** **** *** **** *** **** ** REM BYTE INTO
114
1 1852 123
34 11870 72
T <y
11895
142
HEX 11102 REM*** *** **** *** ******* *** **** *** 11110 11120 11130 11140 11150
This module does the actual work of taking a value from a location in the memory specified by the variable AD. Module 2 is then called to transform the value into hexadecimal form single figure hexadecimal numbers are
padded out with a leading zero in order to ensure a standardised format of two digits per byte of memory. Finally the hexadecimal number is added to 02$, which will be used to display the contents of the memory to the screen.
CHECKSUM TABLE
H = PEEK(AD) : AD GOSUB 11000
IF L E N (H $)<2
THEN H$ = "0"+H$ 02$ = 02$ +H$ RETURN
= AD+1
11100 123 11101 66 11110 11140 82
MODULE 1.9
35
11120
159
11150 142
11102 11130
123
13300 REM******************************
13301 REM DUMP MEMORY TO SCREEN 13302 REM****************************** 13310 GOSUB 12050 13320 PRINT "CCLRD" : FOR XI = 1 TO 18 :
H = AD : GOSUB 11000 13340 02#- = "" s 01$ = HiP : 03$ = "" 13350 FOR X2 = 0 TO 7 13360 GOSUB 11100 : 02$ = 02$+" "
13375 IF H >31 AND H<95 THEN 03$ = 03$+CH
R$(H) : GOTO 13380
13377 03$ = 03$+"."
18
Page 21
Chapter 1 Mastercode Monitor
13380 NEXT X2 13390 PRINT 01* T A B (5) 02* T AB (31) 03$ 13400 NEXT XI 13410 PRINT : GOSUB 11850 : IF CO THEN 1
3320 13440 RETURN
We have now entered all the modules which are necessary to define a start address and to pick up data from the memory. We can now proceed to the part of the program which actually does something. Having defined the start point, this module prints out the contents of an area of memory to the screen.
Commentary
13320: The XI loop will be used to print out 18 lines, each with eight values
taken from the memory, starting at the address now stored in AD.
13350-13380: The hexadecimal values returned from the previous modules
are stored in the string 02$. If the value contained in the particular memory location is the code of an ASCII letter or digit, that character is stored in the string 03$, for display next to the values concerned. In most cases, the characters displayed will make no sense, since the fact that the code is that of a printable character will be purely chance. However, when examining areas of memory such as the variables area of the 64, or the structure of the BASIC program itself, or a machine code program which contains strings, this facility will be indispensable in getting a picture of what an area of memory contains, since any strings held there will be displayed.
CHECKSUM TABLE
13300 123 1 13310
165 13320 246 1 13350 104 1 13377 90 13400 43
3301 129 1
3360 100 1 13380 44 1 13410
86
3302 123 3340
173 3375 177 3390 89
13440 142
Review
Having entered this section you have the working basis of the program as a whole. In the sections which follow you will find that many of the modules employed are those which are already entered, since functions such as translating into hexadecimal are common to them all. Before moving on to enter the rest of the program, familiarise yourself with the operation of the program so far. Examine the area of memory which contains the start of
19
Page 22
Machine Code Master
the program itself (starting at 801 hex) and the variables area. This section
of the Monitor, on its own, is a powerful tool in unlocking the secrets of the
64s memory.
MONITOR: Output of Memory from 801 hex
801
25 08
10
27 8F 2A
2A 2A
. 1 . ***
809
2A
2A 2A 2A
2A
2A 2A 2A
********
811 2A 2A
2A 2A 2A 2A 2A 2A
********
819
2A 2A
2A
2A 2A 2A
2A
2A
********
821
2A 2A 2A 00 42 08
24
27 ***. B. $'
829
8F 20
47
45
4E 45
52
41 . GENERA
831
4C 20 49 4E 49 54 49
41
L INITIA
839
4C 49 53 41 54 49
4F 4E
LISATION
841
00 66 08 2E
27
8F 2A 2A ....'.**
849
2A 2A 2A 2A 2A
2A 2A 2A
********
851
2A 2A 2A 2A 2A 2A
2A
2A
********
859
2A 2A 2A
2A
2A
2A 2A 2A
********
861 2A 2A 2A
2A
00 74
08 2F
#*#*. . . /
869
27 42 41 53 45 20 B2 20 'BASE .
871 31
36
00 9B 08
30
27
8B
16...0'.
879
20 C3 28
50
54 52 24
29
. <PTR$>
881
AA
C3 28 45
24 29
B3 B1 .. <E*>..
889
32 35 35 20
A7
20 9C 20 255 . .
CONTINUE ( Y/N ) :
SECTION 3: Modifying the Memory
Having learned how to examine the memory we now proceed to the next
stage, which is altering its contents. In this section we present two more
modules which will allow you to step through the memory, forwards or
backwards, displaying the contents of individual bytes and, if you wish,
altering the contents of the byte currently displayed.
MODULE 1.10
13000 REM**************************'***'#
13001 REM GET 1 BYTE
13002 REM******************************
13007 H$ ""
13010 INPUT "BYTE ( IN HEX ) : "; H$
13030 GOSUB 11950
13040 IF ERR OR H<0 OR H>255 THEN PRINT
"CCUI" : GOTO 13000
13050 RETURN
20
Page 23
Chapter 1 Mastercode Monitor
On the basis of previous modules you should have little difficulty in discer
ning that this module accepts a hex value in the range 0-FF (0-255), calls up
a translation into decimal and returns that value to the next module, from
which it is called.
CHECKSUM TABLE
13000 123
13007 162
13040 192
MODULE 1.11
13001 52 13010 171 13050 142
13002 123 13030 173
13100 REM* ******************* ********* * 13101 REM MEMORY MODIFY 13102 REM* ******************* ********* * 13110 GOSUB 12050 13120 H = AD : GOSUB 11000 : PRINT H$ TA
B (6) "/" ; : 0 2$ = ""
13140 GOSUB 11100 : AD = AD-1 : PRINT H$
S P C (6) ; 13150 T$ = "" 13160 INPUT " + I,E s T$ 13170 IF T $ ~+" AND AD< 65535 THEN AD = A
D+l : GOTO 13120
13180 IF TAND AD>0 THEN AD = AD-1 : GOTO 13120 13190 IF T$="E" THEN RETURN 13200 IF T$<>"I" THEN PRINT" L'2*013 " : GO
TO 13120
13210 GOSUB 13000 : POKE AD,H : GOTO 131
20
The purpose of this module is to allow the user to step through the memory from a chosen start address and to modify the contents of indi vidual bytes. The major part of the module is concerned with outputting the values in each byte to the screen in a comprehensible format and to moving through the memory. Changes to memory contents are accom plished by the last line, including a call to the previous module
21
Page 24
Machine Code Master
Commentary
13120-13140: Having obtained the start address, the address of the current
byte is printed out, together with the value which it contains.
13160-13210: Four prompts are used by the module. + means move on to
the next byte, *-* means move back one byte and E* quits the module. The remaining prompt is T , which calls up the previous module and allows a new value to be placed into the current byte.
CHECKSUM TABLE
13100 123
13101
112
13110 165 13120 220
13150
13180 116 13190
174
13160 192
211
13102 12: 13140
17 13170 75 13200
20
13210 229
MODULE 1.12
13500 REM *** *** *** *** *** *** ********* *** 13501 REM MACHINE CODE EXECUTE 13502 REM* *** **** ******** ******** *** ***
13510 GOSUB 12050 s SYS AD s RETURN
Should you wish to use the monitor to enter machine code programs directly into the memory in hexadecimal form, this one line routine will allow you to call up the machine code routine without having to quit the program. It would be wise not to run any machine code program before ensuring that the program so far entered has been saved.
CHECKSUM TABLE
13500 123 13501 18 13502 123 13510 106
SECTION 4: Saving and Loading Files
Now that you have the ability to enter new values into the memory and
hence to develop a machine code program, you need to be able to save the
programs that you will eventually develop and enter. You also need to be able to reclaim those programs from disc or tape, depending on where you
wish to store them. The four short routines which follow are designed to
make this possible.
22
Page 25
Chapter 1 Mastercode Monitor
MODULE 1.13
11250 REM****************************** 11251 REM INPUT FILE NAME 11252 GOSUB 25500 : IF DEV=4 THEN 11290 11255 IN* = "" 11260 INPUT " FILE NAME s IN* : T = L E N (IN*) 11280 IF T >16 OR T<0 THEN PRINT "CCD3FIL E NAME INVALID" s GOTO 11260 11290 RETURN
When saving a block of information on tape or disc, this is done in the form of a file, a named location which must first be opened before information is sent to it and then closed when all the necessary infor mation has been stored. When the information is recalled, the name of the file needs to be specified. This module allows the necessary file name to be input.
CHECKSUM TABLE
11250 123 11251 192 11252 119 11255 241 11260 137 11280 216
11290 142
MODULE 1.14
11200 REM****************************** 11201 REM INPUT FINISH ADDRESS 11202 REM****************************** 11205 H$ = "" 11210 INPUT "FINISH ADDRESS ( IN HEX) :
H* : GOSUB 11950
11230 IF ERR OR H<0 OR H >65535 THEN 1120
0
11240 EA = H s RETURN
The machine code programs which you will eventually develop with the aid of the programs in this book will be contained in blocks of memory. To save them, the program must be given two pieces of information, namely where the block starts and where it finishes. We already have a routine which obtains the start address, this one performs the same function for the finish address.
23
Page 26
Machine Code Master
CHECKSUM TABLE
11200 123 11201 70 11202 123 11205 162 11210 10.1 11230 123
11240 200
MODULE 1.15
14100 REM******* *** **** *** **** *** **** ** 14101 REM MACHINE CODE SAVE 14102 REM******* *** **** *** **** *** **** ** 14110 GOSU B 11250 ; GOSUB 12050 : GOSUB
11 200
14115 T* = "N" : IF DEV=8 THEN INPUT "OV
ERWRITE EXISTING FILE ( Y/N ) : T*
14116 IF T*="Y" THEN IN* ~ "@0:"+IN* 14120 IF DEV=8 THEN IN* = I N$+ ,S,W" 14125 IF SA>EA THEN 14190 14130 OPEN 2,DE V ,2 , IN* : PRINT# 2 ,AD : P
RINT# 2,EA
14150 FOR X = AD TO EA : PRINT# 2,PEEK<X ) : NEXT : PRINT# 2 : CLOSE 2 14190 RETURN
Now that we can give a name to the file in which the information con
tained in an area of memory is going to be stored and can specify the start point and end point, we can proceed to enter this module, which will store the information on tape or disc.
Commentary
14125: This line simply checks that the user has not defined a block of
memory whose end point is before its start.
14130: A file is opened, in this case an output file, with the destination of the information being dictated by the value of the variable DEV (device). In the listing of this program it is set at 1 (line 10035), which directs the output to a cassette recorder. If you are using a disc drive, then DEV should be set to 8 in line 10035. Once the output file is opened, the first two pieces of information to be stored in it are the start address (AD) and the end address (EA). Later in the program, a facility will be added to allow you to change the current device number at will.
14150: The contents of each byte in the block of memory to be saved are now stored one by one in the file. At the end of the loop the file is closed.
24
Page 27
CHECKSUM TABLE
Chapter 1 Mastercode Monitor
14100 123 14110 224 14120 179 14150 161
MODULE 1.16
14101 46 14115 32
14125 92
14190 142
14102 123
14116 89
14130 108
14300 RE M******* *** **** *** **** *** **** ** 14301 REM MACHINE CODE LOAD 14302 REM****** *** *** **** *** **** *** ****
14310 GOSU B 11250 : IF DEV=8 THEN IN* =
IN*+",S,R" 14320 OPEN 2, D EV ,0,IN* : INPUT# 2,SA,EA
: IF ST THEN CLOSE 2 : RETURN
14350 FOR X = SA TO EA : INPUT# 2,T : PO
KE X ,T : NEXT : C LOSE 2 : RETU RN
This module is simply the mirror image of the last one. Instead of placing
information into a file, this module takes previously stored information
from the file and places it back into the computer’s memory.
CHECKSUM TABLE
14300 123 14301 31 14302 123
14310 206 / 14320 84 14350 50
Summary
Having entered the whole of the Monitor you are now free to play about with it, though its full power will only be realised once the rest of the Mas tercode program is entered. Try entering a new line: 0 A = 13. Call up the menu option which allows the memory to be changed and alter the contents of byte 805 hex to 8F (143). List the program to 1 and you will see that your first line has changed to a REM statment (143 represents REM in the pro gram file). Unless you are very sure of what you are doing it would be wise not to try to change too many other memory locations at present, and certainly not before you have properly saved your final version of the monitor. If you do want to mess about, try modifying some of the colour attribute bytes from D800-DBFF hex, the colour attributes memory of the screen. Mistakes here are not likely to be disastrous.
25
Page 28
Page 29
CHAPTER 2
Mastercode Disassembler
Having now entered the Monitor program, which allows you to examine areas of memory and to change their contents, we now move on to the next stage, which is to enable you to translate the contents of an area of memory which contains a machine code program into a more understandable form. This more readable form for a machine-code program is known as
assembly language.
The advantage of working with assembly language is that while POKEing numbers directly into memory does permit a machine code pro gram to be entered, there is no easy correspondence between the numbers being entered into the memory or read back from it and the operations which the machine code program will carry out. The program is merely a list of numbers and very few programmers are ever capable of reading a program in that form without constant reference to charts containing the relevant codes and their meaning. Assembly language provides a means of inputting instructions which will be both comprehensible to the user (with a little practice) and yet represent every machine-code instruction in the pro gram exactly. In other words the assembly language program consists of a series of instructions, or mnemonics, which correspond to individual machine-code operations which the 6502/6510 chip is capable of recog nising and carrying out.
Instructions in assembly language will normally be in two parts:
1) An operation code (opcode) which specifies the type of operation which the 6502/6510 chip is being asked to carry out, such as move a num ber from one place in memory to another, compare two values or per
form an arithmetic operation on a value.
2) Having defined the type of operation which must be performed it is now necessary to define the number on which the operation is to be performed.
This part of the instruction is known as the operand and may consist of a
number which will be acted upon directly or the address in memory of a number which is to be operated on.
A typical machine code instruction, upon which the assembly language translation is based, will therefore normally consist of one byte specifying the opcode and one or two bytes which are used to derive the number to be operated upon. Some types of instruction need only one byte, that specif
27
Page 30
Machine Code Master
ying the opcode itself, since they invariably imply that the value to be operated upon is at a fixed location which does not need to be spelled out.
In order to translate a machine code program in the computers memory into assembly language, a program is needed which will be capable of identifying an opcode and then of deciding how many of the succeeding bytes of memory (0,1 or 2) are part of the operand associated with that opcode. A program which is capable of doing this is known as a disassem bler. Its effect is to take the incomprehensible numbers which memory normally contains and to translate them into something which (with a little practice) can be read and understood by the user.
The brief and much simplified explanation given above will bear some study if this is the first time you have been introduced to the idea of a disass embler. Once the concept is straight in your mind, you should have little trouble in understanding the basis on which the following section of the Mastercode program works. By means of a series of tables stored in strings, the program is capable of identifying machine code instructions in a specified area of memory and of printing out the type of operations and their operands in assembly language. The program can be used in at least two ways: a) For the user who is developing programs in assembly language, the Disassembler allows the program in memory to be more easily checked during the process of entering and debugging. b) For those who wish to go further in their exploration of the memory of the Commodore 64, the program as listed is quite capable of giving a complete translation of the machines ROM, the permanent built-in pro gram which actually runs the machine. In this way a better understanding of the 64s internal workings can be built up and it is possible to examine ways in which individual routines within the ROM can be used effectively within the users own programs.
SECTION 1: Setting up Tables
MODULE 2.1
1 2 20 0 R E M * * * ** * * ** * * ** ** ** ** ** ** * * * ** * *
12201 REM HEX LOA DER 12202 REM *** ********* ****************** 12210 Tl$ = "" 12220 FOR XI = 1 TO L.EN (T$) STEP 2 12230 Tl* = Tlf+CHRT(FNDE C(A SC(MID*( T*,X 1,1)))*16+FN DEC(ASC <MID$( T$,Xl + 1,1)))) 12260 NEXT XI 12270 RETURN
The real purpose of this module will not become apparent until the tables in the following module have been explained. Its function is to take values
28
Page 31
Chapter 2 Mastercode Disassembler
from the tables and to compact them into strings. The table values have
been set out in the form of two digit hexadecimal values (ie numbers in the
range 0-255 decimal). This module converts a pair of hexadecimal values into a single ASCII character. The characters thus formed can be econo mically stored in a string (Tl$).
CHECKSUM TABLE
12200 123 12201 107 12202 123
' U12210 223 12220 216 12230 154
12260 43 12270 142
MODULE 2.2
19000 REM****************************** 19001 REM INITALISE DECODER TABLES 19002 REM****************************** 19005 BASE = 16 19007 DEFFN DEC(X) = X-48+( X >57) *7
19010 DIM TAt<4> 19011 Tt = "0A22383838220238242202383
8220238"
19012 Tt = Tt+"0922f38383822023q0D22,38383
8220238" 1
19013 Tt = T*+"1C01383806012738260127380
6012738"
19014 Tt = Tt+"07013838380127382C0138383
8012738"
19015 Tt = Tt+"2917383838172038231720381
B172038"
19016 Tt = Tt+"0B1738 38381720380F1738383
8172038"
19017 Tt = Tt + "2A00383838002838250028381
B002838"
19018 GOSUB 12200 : TAt<0> = Tit
19019 Tt = "0C003838380028382E0038383
8002838"
19020 Tt- = Tt+"382F3838312F3038163835383
12F3038"
19021 Tt = T t+"032F3838312F3038372F36383
82F3838"
19022 Tt = Tt+"1F 1D1E381F 1D1E38331D323 81
F1D1E38"
19023 Tt = Tt+"041D383S1F1D1 E3 8 101D34-381
29
Page 32
Machine Code Master
F1D1E38" ;
19(324 It- = T$+" 13 113838J311 1 4 3 8 j.AJ. 115381
3111438" 1
19025 T* = T$ +"08 113 83838111 4 3 8 0 E 1138383
8111438"
19026 SOSUB 12200 : TA$<0> = T A *<0>+ T1*
19027 T$ =- " 122B3838122B:l838;l92B21381
22B1838" , ,!
19028 T$ = T4-+"052B3838582B18382D2B38383
82B1S" 1
19 0 2 9 GO S UB 1 2 2 0 0 :i TAt-,(0) -- TA $<0 )+T 1*
19030 T$
"17111166112011C C1381114411
B111AA1"
19031 J-$
BillAA1"
19032 T*
T$+C7 11 6661 120 1CCC 1 3 8 11 1 4 4 1 1
T$ + " 1711 |l 6 6 1 12 0 1 CC C 1 3 8 11 1 4 4 1 1
B111AA1" 19033 T-f-
T*+" 171 l!l 66112019 CC13811,14411
B1UAA1"
19034 T$
T* + "171 ll6661:1111 C C C 13 8 1 1 4 4 5 1 1
B111A11"
19035 T#
T$ + "27 2 1 6 66 1 ,1 2 11C CC 13 8 1 14 45 1 1
B11AAB1"
19036 T* » TJ;+"27116 6611 2 11C CC13 8 1114411
B111AA1"
19037 T* = T$ + " 27 1166 6 1121 1CCC 1381 114411
Bill A"
19038 GOSUB 12200 : TA*(1> = Tl $ + CH R t (16 0 ) 19040 TA*<2) = "AB CANDASL BC CBCSBE
QB ITlBM IBNEBPLB RKB VCB VS "
19041 TA*(2> = TA# (2) + "CLCCLDCLICLVCMF'CF' XCPYDE CD EXDEYEO RI NCINX" 19042 TA*<2) = TA^(2>+"IN'yjJMF;JSRj_DAj_.DX/..D Y,LSRJMOf^ORApHAfHF;PLAPLP"
19043 TA$ (2) = TA$ (2) + "ROL*RORkTIRTSBBCfeE
C SEDSEI STA STX STYT AXT AY"
19 0 4 4 t a $<2> = T A $ ( 2)+"T SXTX ATX STYA ??? "
19 0 4 6 RET URN
RE AD Y .
30
Page 33
Chapter 2 Mastercode Disassembler
These seemingly daunting tables are in fact remarkably simple if the gen
eral explanation of the working of a disassembler given above has been
understood.
The three sections of the table defined between lines 19011 and 19029 are used to create, via calls to the previous module, a line in the array TA$, containing characters whose codes are in the range 0-56. These values point
to a subsequent table which contains the names, in assembly language, of the 56 opcode types that are available when a machine code instruction is
expressed in assembly language, plus one code which shows that an invalid opcode has been found. There are over 150 opcodes available in 6502/6510 machine code, so why only 56 representations (or mnemonics) in assembly language? The answer to the question is that machine code opcodes fall into groups, such as those which load the accumulator with a value, and such groups have a common mnemonic. Within each group, however, there are wide differences between the operands ie the way in which the value to be worked upon is obtained. Thus each opcode will have a unique operand type associated with it but a mnemonic may be capable of being associated with several different types of operand when the machine code program is translated into assembly language.
Thus, an opcode with a value of 127 would have an entry at position 127 in TA$(0). The ASCII code of the character at that position will be used to give a value between zero and 56. This value will then be used to point to three characters in the section of the table which is defined between 19940 and 19944. These five lines of text, when broken up into units of three rep resent all the available 6502/6510 assembly language mnemonics for opcode types.
The remaining section of the tables, defined by lines 19030 to 19037 give the type of operand which is associated with that particular opcode. The types of operand will be explained more fully subsequently.
SECTION 2: Operands and their Types
As was made clear in the foreword, there is no intention in this book to provide an introduction to 6502/6510 machine code. It is assumed that those who will wish to use the book will either already be familiar to some extent with the concepts that lie behind machine code and assembly lan guage programming or that the book will be used in conjunction with a general 6502/6510 assembly language primer which will explain the various functions available on the 6502/6510 chip. It is, however, necess ary for the understanding of the program at this stage, to provide some brief explanation of the manner in which the 6502/6510 chip understands operands, that is to say the values or memory locations on which it is cap able of performing its 56 types of operation.
31
Page 34
Machine Code Master
The 6502/6510 chip is capable of recognising 11 distinct methods,
known as addressing modes, by which the value which is to be operated
upon is obtained from a machine code program. Each individual opcode
requires the use of one of these 11 different methods. The disassembler
program must be capable of recognising the opcode and then of extracting
from that opcode the type of addressing which is to be used.
The two simplest forms of addressing are accumulator addressing and
implied addressing:
1) Accumulator addressing: some opcodes specify, without the need for
any further spelling out of a value or memory address, that the operation to
be performed is to be carried out on the contents of the accumulator reg
ister within the CPU. An example of this type of addressing would be shift left accumulator (SLA in assembly language), which would shift bits 0-6 in the accumulator one place to the left, effectively multiplying the value represented by those bits by 2. No further reference is needed when an opcode of this type is specified and only one byte of memory is needed to represent an instruction of this kind in a machine code program.
2) Implied addressing: accumulator addressing is a special case of this addressing mode. There are other opcodes which imply within themselves
the place where the value to be operated upon is to be found. An example of
this would be transfer accumulator to Y register (TAY). The effect of this operation is exactly what it says and there is no further need to spell out where the value to be transferred is obtained or where it will be placed. This again is a one byte instruction in machine code.
3) Immediate addressing: opcodes which employ this type of addressing require that the value to be acted upon is specified along with the opcode itself, such values being in the range 0 - 255, or the possible contents of a single byte of memory. An example of this type of opcode would be load accumulator immediate (LDA). An instruction involving this opcode might be LDA #127. The effect of this instruction would be to load the accumulator with the value 127. When put into machine code this type of instruction requires one byte of memory to specify the opcode and a fur ther one byte to specify the value to be operated upon.
4) Relative addressing: this is employed when jumps are to be made in a program and a value is required to specify the point in memory to which the execution of the program will jump. As with the previous addressing type, this value is in the range 0-255 but this range is split into a positive and negative half, with values from 0-127 implying a positive jump and values
from 128 - 255 specifying a negative jump (127 is subtracted from the value). The jump is measured relative to the address of the byte following the jump instruction. An example of this type of opcode would be branch non-zero (BNE). An instruction involving this opcode might take the
form BNE 127 - the effect of the instruction would be that if the previous operation performed by the program had not resulted in a zero, a jump
32
Page 35
Chapter 2 Mastercode Disassembler
forward would be made spanning 127 bytes of the program before exe
cution commenced again. Relative addressing, like the previous type, employs one byte for the opcode and one byte for the operand.
Before discussing the remaining types of addressing it is necessary to
understand two types which are not implemented in a pure form but which
form the basis for others: a) Indexed addressing: this method employs one of two registers in the
6502/6510 chip known as the index registers. This type of opcode uses an operand which specifies an address in memory but, before this address is
used, it or its contents are modified by the addition of the present contents
of one of the index registers. Thus an instruction using indexed addressing
requires that i) there be a value in the index register ii) that the operand specify an address in memory. b) Zero page addressing: this refers to the fact that though the 6502/6510 chip has only five registers (locations within the chip into which values can be placed and easily acted upon) accessible to the machine-code program mer, this limitation compared to other popular CPU chips is overcome by regarding the whole of the memory from address zero to address 255 as being a series of 128 two-byte registers which can be called upon to store values for the CPU to operate upon. Zero page addressing is the addressing mode by which this area of memory is accessed.
Going back now to the main addressing modes provided on the
6502/6510 chip we find:
5) Zero-page indexed addressing: in this form of addressing the two modes
given above are combined. In an instruction of this type the value con tained in the index register might be seven, in which case the two byte operand would refer to an address in zero page memory (0-255) to which would be added the contents of the specified index register plus.
6) Indirect addressing: here the operation specified by the opcode will be performed upon an address which is not directly stated in the assembler instruction but is contained in the two bytes whose address is pointed to by the two byte operand. An example of an instruction of this type would be jump (JMP). This opcode would be followed by a two byte operand. The operand is not itself the address in memory to which program execution should jump, rather the two-bytes beginning at the address specified by the operand contain an address. It is this second address to which the jump should be made. Thus JMP ($AAAA) would not specify a jump to address $AAAA but to the address represented by the value stored in the two bytes at $AAAA and $AAAB in the memory.
There are two further forms of indirect addressing available on the
6502/6510 chip which use the concept of indexing described before:
7) Pre-indexed addressing: as with normal indirect addressing, operands of this type contain addresses at which will be found values to be operated
33
Page 36
Machine Code Master
upon. Before obtaining that first address, however, pre-indexed operands are added to the contents of the CPU X register. Thus if the X register contains $100 and the operand is $100, then the address at which the desired value will be sought is $200.
8) Post-indexed addressing: here the operand specifies a location in memory, and the contents of that location are first obtained, then the con tents of the CPU Y register are added to that value. The result is an address upon whose contents the operation is to be performed.
9) Absolute addressing: in this type, the two byte operand specifies an address in memory at which will be found the value to be operated upon.
Thus the instruction load accumulator, when using this type of
addressing, might have the form LDA $AAAA, which would result in the loading of the accumulator with the value stored in byte $AAAA in the memory.
10 and 11) Absolute X and absolute Y addressing: in the case of these two types the address specified in the two byte operand is added to the contents of either the X or the Y register to arrive at the final address of the value to be operated upon. Thus if the contents of register X is $5 and the operand is $AAAA, then the address of the value to be operated upon for an instruc
tion such as LDA $AAAA,X would be to load the accumulator with the
contents of the byte at $AAAF in the memory.
Having given this brief explanation of the different type of operands which the 6502/6510 chip is capable of understanding, you should now find the sections of the program which deal with the creation of assembly
language instructions out of their machine-code equivalents easier to understand without too much further commentary. In the modules that
follow, when an opcode is picked up from memory, the program will obtain the correct types of addressing for the opcode by accessing the
tables stored in the previous section, obtaining a value which it will record
in the variable OP (OPerand). The value of OP when translated into an
addressing mode is given in the table below and you will find it useful to refer to this when following the program modules for the Disassembler.
VALUE OF OP 0
1
2
3 4 5
6
7
8
34
ADDRESSING MODE Accumulator
Implied
Immediate Relative Zero-page indexed, X Zero-page indexed, Y Zero page Pre-indexed indirect (X) Post-indexed indirect (Y)
Page 37
Chapter 2 Mastercode Disassembler
9
10 11 12
CHECKSUM TABLE
19 0 0 0
19 0 0 5
1901 1
123 1 16 1 36
190 1 4 9 0
1 901 7
93
19 0 2 0 1 30
19 0 2 3 193
19 0 2 6
19 0 2 9
19 0 3 2
19 0 3 5
19 0 3 8
21 3 21 3 1 9 0 3 0 162
1 1 a J. 47 1 9 03 6 125
75
19 0 42 10
19 0 4 6 142
" / .1 '
MODULE 2.3
Absolute indirect Absolute indexed, X Absolute indexed, Y Absolute
19001
66 19 00 2 19 00 7 132 19 01 2 89 19 0 15 190 1 0 19021
91
241
154 190 2 4 61 19 02 7 189
19 0 33
19 04 0 19 04 3
108
84 82
* i
123 1 90 1 0 1 90 1 3 1 901 6 19 01 9 19 02 2
22 8 78
1 16
1 6 4
.c:. cd 19 0 25 87 19 02 8
58
1 90 3 1 1 41 190 3 4 19 03 7
111
11 1 9 04 1 175 19 0 44 23 8
15 4 5 0 REM ********** **************** ****
15451. RE M A C CUMU LAT0R <OP=0> 15 4 5 2 REM ********** **************** **** 15 4 6 0 01* = 01*+"A" 15 5 0 0 REM IMF'LIED <0P=1> 15 5 1 0 RE T URN
This brief module deals with the two simplest types of addressing mode: a) Accumulator addressing: all that is required for the disassembly of this type is the addition of A to the standard opcode. b) Implied addressing: here the opcode itself implies its own operand and no further action is needed.
CHECKSUM TABLE
15 4 5 0 123 15 451 7 7 1 5 45 2 123
154 6 0 1 05 .1.5500 49 1 5 51 0 142
35
Page 38
Machine Code Master
MODULE 2.4
15550 RE M***** *** **** *** *** **** *** **** *
15551 REM IMMEDIATE <OP=2)
15552 RE M** **** *** ******* **** *** **** ***
15560 GOSIJB 11100
15570 01* = 01 $+"#$"+H$
15580 RETURN
This module deals with immediate addressing. The byte following the
opcode is taken to be an operand in the range 0-255.
CHECKSUM TABLE
15550 123 15551 189 15552 123 15560 160 15570 133 15580 142
MODULE 2.5
15600 REM*** *** ******* *** **** *** **** ***
15601 REM RELA TIVE (0P=3)
15602 REM* **** *** **** *** **** *** *** **** *
15610 GOSUB 11100
15620 IF H > 127 THEN H = H--256
15630 H = H+AD
15640 GOSUB 11000
15650 01$ = 01$+"$ "+H$
15660 RETURN
This module deals with relative addressing and translates the byte
following the opcode into a number in the range -128 to +127.
CHECKSUM TABLE
15600 123 15601 139 15602 123 15610 160 15620 239 15630 177 15640 159 15650 98 15660 142
MODULE 2.6
15300 RE M******* ******* *** **** *** **** **
15301 REM ADD OPERAND IN OP TO 01$
15302 REM* *** **** *** **** *** **** *** **** *
15310 ON OP+1 GOTO 1 5450,15 50 0,15550 ,1 56
00
36
Page 39
Chapter 2 Mastercode Disassembler
15330 IF D P>6 AND OP<10 THEN GIT = 01*+"
< "
15340 GOSUB 11100 15350 01* = 01*+"*" : T* = H* 15360 IF O P <9 THEN 15390 15370 GOSUB 11100 15380 01* «= 01*+H* 15390 01* = 0 1*+T$ 15400 IF OF-9 OR OP=8 THEN 01* = 01*+")" 15410 IF O P -I N T<OP /3 >*3=1 THEN 01* = 01*
+ " , X "
15420 IF OP- I NT(O P/3) *3=2 THEN 01* = 01*
+ " , Y "
15430 IF 0P=7 THEN 01* = 01*+")"
15440 RETURN
This simple section of IF statements formats the assembly language
instructions according to the different addressing modes. The best way to understand the section is to compare what it does to the operand, on the basis of the value of OP, given in the table previously.
CHECKSUM TABLE
15300
15310 110
tl5
15380
15410
123
350 156
80 15390 207
15301 158 15302 123 15330 10 15340 160 15360 31 15370 160
15420
cp'P 209 y
15400 230 15430
107
15440 142
SECTION 3: Disassembly of Memory
We have now entered the sections of the program which enable the transla tion to be made from machine code into assembly language. It now remains to add those modules which allow the program to pick up the con tents of a specified area of the 64s memory so that that the machine-code instructions it contains may be disassembled and printed to the screen.
MODULE 2.7
15700 REM****** *** *** **** ******* *** **** 15701 REM DISA SSEMBLE INSTRUCTION 15702 RE M******* **** *** **** *** **** *** **
37
Page 40
Machine Code Master
15710 02$ = ""
15715 GOSUB 11100 t H = H+l
15720 IF H >255 THEN H = 3
15730 T = AS C(M I D$ (T A T (0),H ,1))
15750 O 1$ = MI D$ (T A T (2),T * 3 +1,3)+" " 15760 OP = A SC (MI D$ < T AT (1) , IN T ((H + 1)/2) ,
1) ) 15770 IF (H AND 1) ==1 THEN OP = OP / 16 15780 OP = OP AND 15 15790 RETURN
CHECKSUM TABLE
15700 123 15701 93 15710 15730
15770
This module constructs the assembly language instruction out of the
information picked up from memory.
Commentary
15715-15720: The opcode byte having been obtained, its value is placed
into the variable H.
15730: The opcode is used to obtain a pointer value from TA$(0) which will indicate the position in TA$(2) of the three letter assembly-language format of that opcode.
15750: A space is added after the opcode to conform with standard assem bly language format.
15760-15780: The addressing mode which is associated with the opcode is obtained from the table at TA$(1).
MODULE 2.8
21;9
131 146 15780 133
15715 119 15750 148
15702 15720
123
148 15760 224 15790
142
15800 REM***** *** *** **** *** ******* **** * 15801 REM DI SASSEMB LE MEMORY AREA 15802 REM***** *** *** **** *** ******* **** * 15810 GOSUB 12050 15820 PRINT "CCLR]" : FOR I - 1 TO 20 15825 H « AD : GOSUB 11000 : PRINT H$ TA
38
Page 41
Chapter 2 Mastercode Disassembler
B (6) ;
15830 GDSUB 15700 : GOSUB 15300
15850 PRINT 02# T A B (14) 01$
15860 NEXT I
15865 PRIN T
15870 GOSUB 11850
15880 IF CO THEN 15820 15890 RETURN
CHECKSUM TABLE
15800 123
15801 13
15810 165 15820 93
15830 202 15865 153
15850 115 15870 172
15802 15825 15860 15880
123 244 235 36
15890 142
This is the control module which formats the assembly language instruc tions obtained by the previous modules. For an explanation of the various subroutine calls, see the Table of Subroutine Functions in the Appendix.
Summary
Even if you are working with this book in conjunction with a good 6502/6510 primer it will be worth, at this stage, spending some time play ing with your assembler and monitor. Try disassembling some of the routines within the 64 ROM and trying to understand a little of how they
function. Some interesting addresses to begin disassembly are given below,
together with the purposes of the routines at that position.
Be warned, however, that any disassembler is only as good as the starting position in memory that it is given. If you start the disassembly of memory at a point which is in fact halfway through a machine-code instruction then the first few bytes, at least, of the disassembly listing will be garbage, since parts of operands will be translated as opcodes. Eventually, after rejecting a number of apparently spurious instructions and perhaps listing some nonsense instructions, the disassembler will get itself into synch with the
memory. After this it will be disturbed only by tables contained in the memory, which it will again attempt to translate as if they were machine code instructions. When you run up against such problems the only
solution is to move the start address along until you clear the table and meaningful instructions are discovered from the start of the disassembled listing.
39
Page 42
Machine Code Master
Given below is a specimen disassembly of an area of the 64s interpreter starting at the address of a routine whose function is to accept the input of a new BASIC line using various subroutines in the 64s monitor and
kernal\
SPECIMEN DISASSEMBLY: Start Address A480 hex
A480 A483
6C0203 JMP
2060A5 JSR A486 867A A488
847B A48A 207300 A48D
AA
SIX- *7 A STY *7B JSR
TAX
(*0302)
*A560
*0073
A48E F0F0 BEQ *A480 A490 A2FF
LDX #*FF A492 863A SIX *3A A494 A496 A499 A49C A49F A4A2 A4A4 A4A7
A4A9
A4AB
A4AD
9006 BCC *A49C 2079A5 JSR
*A579 4CE1A7 JMP *A7E1 206BA9 JSR
*A96B 2079A5 JSR *A5'79 840B STY *0B 2013A6 JSR *A613 9044 BCC *A4ED A001 B15F 8523
LDY #*01 LDA
(* 5F ),Y
STA *23
CON TINUE ( Y/N ) :
40
Page 43
CHAPTER 3
Mastercode File Editor
Before proceeding to the main part of the Assembler program we shall examine the File Editor, which allows assembly language programs to be entered in a convenient form and practically edited.
In discussing the Disassembler we have already noted the format of some of the individual instructions which will be used in assembly language pro grams. If you have used the Disassembler to translate part of the 64s ROM then you will also have seen the format in which assembly language pro
grams are normally presented, consisting of three items of information for
every assembly language instruction:
1) The memory address at which the instruction is to be found.
2) The contents, in Hex, of the bytes involved.
3) The assembly language form of the instruction.
When entering an assembly language program to an assembler, only the assembly language instructions are needed. There are, however, some problems with simply entering a long list of assembly language instruc tions. What, for instance, if we have entered a long assembly language pro gram and then discover that it needs a few more instructions somewhere in the middle or that some instructions need to be deleted. Does the whole thing have to entered again in the right order? Obviously the ideal method would be something like that provided by the 64s BASIC interpreter numbered lines which are automatically deleted or inserted in the correct place, with the ability to alter lines anywhere in the program at will. It is the function of the File Editor to provide that facility, though the program section given here goes further than that, allowing renumbering of the pro gram and the saving (or loading) of the assembly language file before the Assembler proper goes to work on it and translates it into machine code.
It should be stressed that the File Editor is not genuinely part of the Assembler in that it makes no test of the material being entered, it is purely there to allow numbered lines of text to be inserted into a file. Nothing will be checked or processed until the Assembler itself is entered and run.
SECTION 1: Setting Up
MODULE 3.1
24E100 REM**********************'*-*-******
2480.1 REM FILE EDITOR MENU
41
Page 44
Machine Code Master
24802 RE M*** *** **** *** **** *** *** **** *** 24820 PRIN T
ILE EDITOR -
24835 PRINT
II
CCLR3 CGREEN]
II
CB L U E3 CCD]"
0)
EXIT FROM FILE EDI
--------------
F
TOR" 24840 PRINT 24850 PRINT 24860 PRINT 24870 PRIN T 24880 PRINT 24890 PRINT 24900 PRIN T 24910 PRINT
II
II
II
II
II
II
II
II
1) INPUT LI NE(S>" LIST LINE(S)"
2) DELETE LI N E ( S > "
3)
4) REN UMBER FILE"
5)
INITIALISE FILE"
6) LOAD FILE"
7)
SAVE FILE"
8)
ADD MA CHINE CODE T
0 FILE" 24915 PRINT
II
9)
CHANGE DEVICE NUMB
ERC5*CD]
24920 INPUT
II
COMMAND ( 0-9 ) : CO
24940 IF CO=0 THEN RETU RN
24950 IF CO>0 THEN ON CO GOSUB 24600,24 4
00 ,245 0 0,24 7 00, 243 00,2 360 0,23 700 ,250 00
24960 IF C O >8 THEN ON CO-8 GOSUB 25500
24970 GOTO 24800
A straightforward menu module.
CHECKSUM TABLE
248 00 123 24801
24820 125 24835 24850 96 24860 24880 102 24910 24940 24970
MODULE 3.2
90 24915 243
148 167
24890 156
24950
11 235 216
30
24802 123
24840
179
24870 218
24900
172
24920 182
24960 252
24300 REM **** *** ******* **** *** **** *** ** 24301 REM INITALISE FILE 24302 REM* **** **** *** *** **** *** **** *** * 24310 PTR* = 11" : E$ = "" : FOR X - 0 TO
254 : E* = E$+CHR*(X> : NEXT s RE TU RN
This module sets up the variables necessary for handling a new file calling this option when a file is already in memory will result in the loss of the existing file. The two main variables are PTR$, which will indicate the
42
Page 45
Chapter 3 Mastercode File Editor
position of entries in the file in their correct order, and E$, which will record the position of spaces for new entries. The use of PTR$ will be described under Module 6.
CHECKSUM TABLE
24300 123 24301 145 24302 123 24310 217
MODULE 3.2A
19980 DIM F I* <254) s GOSUB 2430 0
This module is actually a part of the main initialisation routine for the Disassembler tables. Its function is to set up the main file array (FIS) when the program is first run. Once the program is running the array is re-initia lised by calling the previous module.
CHECKSUM TABLE
19980 101
SECTION 2: Inputting Lines
MODULE 3.3
24600 REM *** ********* *** **** *** *** **** * 24601 REM INPUT LINE(S) 24602 RE M** *** ****** *** ****** *** ****** * 24610 PRIN T " CCLR3 11 24620 IN* = "" : INPUT IN* : BOSUB 24000
: IF LN=-65536 THEN 24665 24650 GOSUB 23900 : IF LEN(I N*)=0 THEN 2 4680 24660 GOSUB 23100 : IF NOT ERR THEN 2462
0
24665 RETU RN 24680 GOSUB 23020 : IF NOT ERR THEN GOSU B 23300 24690 GOTO 24620
This is the module which, when a line is input, allocates the necessary tasks to the File Editors various routines. Other than distributing work around other modules, its only functions are to allow the input of the line in
43
Page 46
Machine Code Master
the form of IN$ and to determine whether a line number without a line attached is being entered ie a deletion.
CHECKSUM TABLE
24600 123 24610 144
24660 94
24601 43 24620 251 24665 142
24602 123 24650 108 24680 6
24690 167
MODULE 3.4
24000 REM****************** -************ 24001 REM GET LINE NUMBER 24002 REM* **** **** *** *** **** *** **** *** * 24010 LN = -65536 24020 IF L E N (IN#)=0 OR IN#<"0" OR LE FT # (
IN # , 1)>"9" THEN 24090 24030 FOR T = 1 TO LEN(IN#) 24040 IF M ID # (IN#,T ,1)< = "9" AND MID#(IN#
,T ,1)>="0" THEN NEXT T 24080 LN = VA L (L E F T # (IN#,T - l)) : IN# * M
I D# <1N #,T )
24090 RETURN
Having obtained an input in the form of INS, a line number is obtained from the beginning of the string. The string is examined character by cha racter to find the first one which is outside the range 0-9, and then the VAL
of the string up to that point is obtained. Strings which do not begin with a line number result in the line number (LN) being set to -65536, thus
flagging an error, otherwise the line number is stored in LN and the cha
racters containing the line number chopped off the original string.
CHECKSUM TABLE
24000 123 24001 192 24 00 2 123 24010 64 24020 99 2403 0 203 24040 150 24080 79 2409 0 142
MODULE 3.5
23900 REM** *** **** *** **** *** **** *** *** *
23901 REM REMOVE LEADIN G SPAC ES 23902 REM**** *** **** *** **** *** **** *** ** 23910 FOR T = 1 TO LEN(IN#)
23920 IF M I D #(I N # ,T ,1)=" " THEN NEXT 7
23950 IN# = M I D# (IN #,T ) : RETURN
44
Page 47
Chapter 3 Mastercode File Editor
The resulting INS, stripped of its line number may now begin with one or
more spaces this module removes them.
CHECKSUM TABLE
23900 123 23901 112 23902 123 23910 203 23920 81 23950 11
MODULE 3.6
2131000 REM ******* ******* **** *** ******* **
23001 REM FILE EDITOR
23002 REM* **** **** *** *** **** *** **** *** *
23010 REM FILE EDITOR
23020 REM FIND LINE NUM BER IN 'LN' IN FI
LE
23030 T = LEN <PTR4;) +1 : T2 = -1
23040 T = T-l : IF T<=0 THEN GOTO 23080
23050 T 1 = ASC(MI D * (PTR$,T , 1 )> 23060 T2 = AS C(M I D$ (FI$ ( T 1),1,1) )+256*AS C< MID$(F I $ ( T 1 > ,2,1)) 23070 IF T2>L.N THEN 23040 23080 ERR » NOT(T2=LN) : IF ERR THEN T =
T+l
23090 RETURN
Before we proceed to the module which actually inserts a line into the file, we must deal with this one, whose function is to determine the correct position for the new line (if it has a valid line number). In examining the module we shall learn something of the use of PTR$.
Commentary
23030: In searching for the correct position to insert a line we shall make use of the string we have called PTR$, short for pointer string. A pointer string is a standard method of overcoming the problems of inserting new lines in multi-line arrays. It is not that this is difficult, it is simply that to insert a new line at the beginning of what is potentially an array of some 250 lines involves shifting all the current lines, a task which can be time con suming and can also create problems with garbage collection, slowing things down even more. Using a pointer string this can be overcome, since the contents of the array need never be shifted at all. All that needs to be done is to manipulate a single string. Instead of finding the correct place in the array and then shifting everything else to make room for the new line,
what we shall do is to find what should be the correct position (as dictated
by the line number), place the line to be entered in the first empty space we
45
Page 48
Machine Code Master
find and then put an indication of its actual position in the right place in the
pointer string.
Thus the pointer string might contain a series of bytes with values of 34,76,233,176 is to be found at position 34, the second line is at position 76, the third at position 233 and so on. To access the array of lines in order we must first look at PTR$, take from that the position of the first line, then look at the second character of PTR$ to find the position of the second line. Because we have accepted the arbitrary limit of 255 lines for any one file all the pointers can be held in the form of single characters in PTR$ single cha racters can have an ASCII value of 0-255. To insert a new entry, all that will be necessary is to split PTR$ into two and place a new indicator in the middle of it a considerable saving of time. In this particular line the main search variable (T) is set to LEN(PTR$) + 1, so that the search will begin at the end of PTR$.
23050: The value of character T in PTR$ is the position of what should be line T in the array (not the line with line number T but position T if we counted from the beginning of the file).
23060: This obtains the line number of the line stored in FIS at position T1. 23070: The search continues until a line number is found which is greater
than that of the line being entered (LN).
.......
What this would mean is that the true first line in the list
23080: Note that ERR is set if the line number being entered is not the same as one already in the file. This is so that the next module will know whether a line is being inserted or overwritten.
CHECKSUM TABLE
;0i0 182 1040 17 ;070 92
MODULE 3.7
23020 3.83 23050 160 23080
16
23030 29 23060 23090
86
142
23100 REM* **** *** *** **** *** **** *** **** * 23101 REM ADD LINE TO FILE 23102 REM **** *** **** *** **** *** **** *** ** 23105 IF LN<0 OR L N>65535 THEN 23215 23110 GOSUB 2302 0 23120 IF NOT ERR THEN T1 = ASC(MID *(P TR*
,T, 1) ) s GOTO 23150
23130 IF E *= ,,H THEN ERR = TRUE s GOTO 23
46
Page 49
Chapter 3 Mastercode File Editor
220
23140 T 1 = ASC(E*> : E* = MID*(E*,2) 23150 T2 = INT(LN/256) 23160 FI*<T1> - CHR$(LN- T2*256)+C HR*<T2>
+ IN *
23170 IF NOT ERR THEN 23220
23180 T* = "" : Tl$ =
23190 IF T >1 THEN T* = LE F T * (PT R * ,T- l )
23200 IF T O L E N (PTR-T) THEN 71* = MID*(PT R * , T ) 23210 PTR* = T*+C H R * ( T 1)+T1*
23215 ERR = FALSE
23220 RETURN
This is the module which actually accomplishes the insertion of the line
into the file.
Commentary
23105: Using two bytes, 0-65535 is the maximum range of possible line
numbers.
23120: If an error is returned from the previous module, all it means is that
a new line number is being entered. If there is no error then the line being
entered will simply overwrite an existing line and PTR$ does not need to be
altered at all.
23130: To speed up the process of entry even more, a second string (E$) is
used to record all the empty spaces in the file. Rather than scanning for the
first available empty space, the line will be inserted in the position indicated
by the first character in E$ this character is now lopped off since it will
no longer be empty.
23150-23160: The line number bytes are created from LN and the new line
inserted. Note that having put the high byte into the variable T2
( = LN/256), there is no need to make another variable equal to
LN-256*INT(LN/256). Simply putting LN into ASCII form will lose
anything above 255 as if LN had been ANDed with 255.
23170-23210: If we are dealing with a new line number then PTR$ must
have a character added to it. The position of the character is indicated by T
47
Page 50
Machine Code Master
and all that is necessary is to take LEFT$(PTR$,T-1) and MID$(PTR$,T)
then to add the necessary character between them.
CHECKSUM TABLE
;i00 123 23101 195 23102 12
105 79
23110
130 40 23140 206 23150
164 23120 1
98
160 84 23170 60 23180 7
;i90 193 23200 201 23210
215 70
MODULE 3.8
23220 142
30
23300 REM****************************** 23301 REM DELETE LINE POINTED AT BY T 23302 REM****************************** 23310 T* « ,,H : Tl* = " 23320 IF T>1 THEN T$ = LEFT*(PTR*,T-l) 23330 IF T<LEN<PTR*> THEN Tl* - MID*(PTR $,T+1> 23340 ES = E$+MID*<PTR$,T,1> 23350 PTR* * T*+T1* 23360 RETURN
This may seem a strange module to discuss under the heading of input of lines, since its purpose is to delete them. The reason we talk about it here is that, when inputting lines, if you input a line number without a line attached, the line with that number is deleted in the same way that it would be in BASIC. The module is therefore called from the main control module for input. The procedure followed is a mirror image of that involved in insertion, with a pointer character being removed from PTR$ and the lines position being recorded as a space in E$. Note that there is no need to actually remove the contents of the line it is still there but the File Editor does not recognise its existence any longer and will overwrite it when a new line is entered.
CHECKSUM TABLE
2
00 123 23301
10 7 23320
40 128 23350
193 23302 193
215
23330 242 23360
123
142
48
Page 51
Chapter 3 Mastercode File Editor
SECTION 3: Listing and Deleting
MODULE 3.9
24200 REM *** ********* *** **** *** ******* * 24201 REM FIRST AND LAST LINES 24202 REM** *** *** **** *** **** *** **** *** * 24205 IN* = "" : INPUT "FIRST - LAST LIN ES : IN* 24210 SL = 0 : FL = 65535 : T3 = 0 : ERR
= FALS E 24220 IF L E N (IN *)=0 THEN 2429 5 24230 GOSUB 24000
24240 IF LN>=0 THEN SL = LN : GOTO 24260
24250 IF L N>-65536 THEN FL = -L.N : GOTO
24295 24260 GOSU B 23900 : IF LEN(IN*) =0 THEN F
L- SL : GOTO 24295
24270 IN* = MID*( IN*, 2) : GO SUB 23900
24290 IF L EN (IN*) >0 THEN GOSUB 24000 : F
L = LN 24295 ERR = SL<0 OR S L >65535 OR FL<0 OR F L >65535 OR ERR : RETURN
This module is used in listing and block deletion to get a pair of line
numbers input in the format 100-330.
Commentary
24210-24220: The start line (SL) and finish line (FL) are set to the ends of
the permissible range. If the user simply presses return when the prompt
appears, the whole of the file will be listed from start to finish. 24230-24250: The first line number is obtained through the subroutine at
24000. If it is greater than zero then SL is set equal to it. If -300 were input
this will be returned as minus 300. In this case SL will remain at zero but FL
will be set to 300 and the file will be listed up to line 300. 24260: Any leading spaces are stripped from what remains of INS after the
first number has been removed. If there is nothing left then FL is set equal to SL and only one line is listed.
24270-24290: INS is stripped of the before the second number, any lead ing spaces are removed and the second value obtained.
CHECKSUM TABLE
24200 123 24201 57 24202 123
24205 168 24210 170 24220 73
Page 52
Machine Code Master
24230 163 24240 11 24250 131 24260 180 24270 6 24290 125
24295 38
MODULE 3.10
23400 REM*** *** **** *** **** *** *** **** *** 23401 REM LIST LINES POINTED AT BY T 23402 REM** *** *** **** *** **** *** **** *** * 23410 PRIN T AS C(MID$ <FI$ ( T > ,1,1))+2 56*AS C< M I D $ ( F I *(T>,2,1)) T AB (6) ; 23420 PRINT MID*(FI#(T),3) 23430 RETURN
This module prints a line whose position is indicated by the variable T.
The line number is obtained from the first two characters of the line, then
the rest of the line is printed.
CHECKSUM TABLE
23400 123 23401 157 23402 123 23410 178 23420 139 23430 142
MO DU LE3.il
23500 REM *** *** ******* *** **** *** **** ***
23501 REM START AND FINISH POIN TERS
23502 REM *** ********* *** **** *** *** **** *
23510 LN = SL : GOSUB 23020
23520 SP = T
23530 LN = FL : GOSU B 23020
23540 FF' = T
23545 IF ERR THEN FP - FP-1 23550 IF FP>LEN(PTR$> THEN FP = LENtPTR *
)
23560 RETURN
Using the start and finish line numbers, this module picks up from PTR$ the pointers to the first and last lines to be listed and stores them in SP and FP.
50
Page 53
CHECKSUM TABLE
Chapter 3 Mastercode File Editor
23500 123 23510 73 23540 220
501 165
:520 233
545 117
23502 123 23530 60 23550 189
23560 142
MODULE 3.12
24400 REM *** ****** *** ******* *** **** *** * 24401 REM LIST LINES 24402 REM* *** *** *** *** *** *** *** *** ***** 24410 GOSUB 24200 : IF ERR THEN 24460 24420 PRINT "CCLR3'1 : G OS UB 23500 : IF F P< SF'OR FF'=0 THEN 24460 24430 FOR T 1 = SP TO FP : T = ASC( MI D*(P TR $,T 1,1)) s GOSUB 23400 : NEXT s PRINT 24455 IF P EE K(152)=0 THEN GET T$ : IF T* ="" THEN 24455 24460 RETURN
Using the start and finish pointers determined by the previous module,
this module now calls up the print module to list the lines to the screen. The strange looking line at 24455 checks to see whether the lines are actually being listed to a device such as the tape recorder or a printer. If not, the listing will be displayed on the screen until a key is pressed.
CHECKSUM TABLE
24400 123 24401 134 24402 123
24410 154 2442 0 241 24430 126
24455 214 24460 142
MODULE 3.13
24500 REM** ***** ******* *** **** *** **** ** 24501 REM DELETE LINE(S) 24502 REM* *** *** *** *** *** *** *** *** *** **
24510 GOSUB 24200 : IF ERR THEN 24460
24520 GOSUB 23500 : IF FPCSP THEN 24560 24530 T = SP : FOR T1 = SP TO FP : GOSUB
23300 : NEXT
24560 RETU RN
This is the block delete module. It is included at this point because its sole
function is to call up modules previously entered, the largest of which is the
51
Page 54
Machine Code Master
get first and last lines routine. Instead of listing the lines specified, the line delete module is called up for each line in turn. Note that because PTR$ is being shortened with each deletion, the character deleted for each iteration of the loop is always at the same position.
CHECKSUM TABLE
24500 123 24501 78 24502 123 24510 154 24520 160 24 530 179
24560 142
SECTION 4: Loading and Saving
MODULE 3.14
23700 RE M******** *** **** *** ******* **** * 23701 REM SAVE FILE TO DEVICE 23702 REM***** **** *** **** **** *** *** **** 23705 GOSUB 11250 23710 IF DEV 8 THEN IN* = I N * + " S ,W" 23715 T* = "N" s IF DEV=8 THEN INPUT "OV ERWRITE EXISTING FILE ( Y/N ) s "; T* 23716 IF T* "Y M THEN IN* = "60: " + IN* 23720 0PEN2,DE V,2 ,IN* s CMD 2 23730 SL = 0 : FL. * 65536 23750 GOSUB 24420 : PRINT#2 , "END" 23760 PR INT#2 s CL OSE 2 23780 RETURN
This module allows a file that you have created to be saved onto tape
or disc, or output to a printer.
Commentary
23705: The routine from the Monitor which requests a file name. 23710-23716: These lines are included for the benefit of those using disc
units for storage. Their effect is to allow the user to overwrite an existing file on drive zero with a sequential file of the contents of FIS. The lines are only accessed if DEV is set to 8 (disc drive).
23720-23760: A file is opened to the specified device and the CMD2 instruction specifies that all further output will be sent to that device. All that remains is to use the normal listing routines to print all the lines of the file, terminate them with END as a marker and finally close the file.
52
Page 55
CHECKSUM TABLE
Chapter 3 Mastercode File Editor
23700 23705
23716
23750
MODULE 3.15
123 166
89
116
23701
177 23710 179 23720 138 23760 54
2-3702 123 23715 23730
TV? 200
23780 142
23600 REM* *** ********* *** **** *** **** *** 23601 REM LOAD FILE FROM DEVICE 23602 REM *** *** **** *** *** **** *** **** *** 23610 GOSUB 11250 23615 IF DEV= 8 THEN IN* = IN*+ H ,S,RH 23630 0P EN 2,D E V,0,1N$ 23635 INPUT#2 , IN* : IF ST THEN GOTO 23 650 23640 IF I N *<>”END" THEN GOSU B 24000 : G OSUB 23900 : GOSUB 23100 : GOTO 23635 23650 CLOSE 2 23660 RETURN
The mirror image of the previous module. Note that when loading the
file back from tape or disc, all the normal input routines have to be used. This is because the lines were listed in full with their line numbers, not the two byte form of the line numbers that is normally stored in FI$. The cass ette saving/loading system has difficulty in saving non-printable ASCII characters and simply saving the contents of FIS would result in the corrup tion of some of the line numbers on reloading.
CHECKSUM TABLE
23600 123 23601 51 23610 166 23615 174 23635 57 23640 215
23602 123 23630 31 23650 242
23660 142
MODULE 3.16
25500 REM *** *** ******* *** **** *** **** ***
25501 REM CHANGE DEVICE NUMBER
25502 REM *** ********* *** **** *** *** **** *
25510 PRINT SPC (19) DEV
25520 INPUT "CC U3NEW DEVICE N U M B E R : D E V
25530 RETURN
53
Page 56
Machine Code Master
The purpose of this module is to allow output to be made to cassette, disc or printer. Note that trying to output to, or input from, a device which is not present, or to input from a device which is not capable of giving an input (such as the printer) may result in the program stopping. Data will not be lost provided that you start the program with GOTO 10000 rather than RUN. Before doing so it would be wise to ensure that file 2 is closed by entering PRINT ^2: CLOSE2 if you were saving when the program stopped or simply CLOSE2 if you were loading. This will avoid the possibility of "FILE ALREADY OPEN" errors being given.
CHECKSUM TABLE
255m 123 25501 14 25502 123 25510 241 25520 113 25530 142
SECTION 5: Renumbering
MODULE 3.17
24700 REM* * *** **** *** **** *** **** *** *** * 24701 REM RENUMB ER FILE IN STEP S OF 10 24702 REM* * *** **** *** **** *** **** *** **** 24710 LN = 10 : ERR « FALSE 24720 IF LEN(PTR*)<1 THEN 24780
24730 FOR T = 1 TO LENtPTR*)
24735 71 = ASC( M I D * (PTR*, T , 1)>
24740 FI$(T1> = CHR$ (LN- INT( L N/25 6)*256)
+CHR *(LN/2 56)+MID * (FI* <T1) ,3)
24750 LN = LN+10 : NEXT
24780 RETURN
Hardly worth a section in its own right, but the module does perform
independently of everything else you have entered so far. Its purpose is to
renumber your file in steps of 10. This is done by stripping each entry in the file of its first two characters and then recreating them from LN, which is
incremented by 10 for each line.
CHECKSUM TABLE
24700 123 24701 235 24702 123
24710 173 24720 169 24730 42 24735 160 24 740 94 24750 45 24780 142
54
Page 57
Chapter 3 Mastercode File Editor
MODULE 3.18
25000 REM *** ********* *** **** *** ******* * 25001 REM ADD TO FILE FROM MEMO RY 25002 REM *** *** **** *** *** **** *** **** *** 25010 60SUB 12050 : GOSUB 11200 : GOSUB 24200 25050 FOR XY AD TO EA STEP 15 25060 IN* * " BYT " : LN » SL s SL = SL+ 5 25070 FOR XZ 0 TO 14 : 02* - "" 25080 GOSU B 11100 : IN* » IN*+"*"+H* 25100 IF XZ< 14 AND A D O E A THEN IN* = IN*
+ '. " : NEXT XZ
25110 GOSUB 23100 . NEXT XY : RE TURN
We confess that this module is a bit of an afterthought, but a nice one for all that. Its relevance really wont become clear until you have entered the Assembler but what it does is allow you to specify an area of memory and then place it into an assembly language program Hie in the form of byte directives the contents of each memory location are specified in the assembler file. No automatic adjustment is made to instructions which access addresses in the area from which the code was originally lifted. Such instructions will still refer to the original area of memory.
CHECKSUM TABLE
25000 123 25001 200 25002 25010 223 25050 130 25070 19
25080
170 25100 13
25060 78
123
25110 120
Summary
Now that you have entered the File Editor it would be wise to play with it for a while before going on to enter the Assembler. This will help to avoid
the upset of entering a long assembly language file and then having it
spoiled because you misuse the File Editor. You could, if you wish, enter
one or two of the assembly language programs to be found later in this book, saving them to disc or tape and then reloading them to check that you have the procedure off pat.
55
Page 58
Page 59
CHAPTER 4
Mastercode Assembler
Having entered the File Editor, we can now begin on the process of entering the most important and complex part of the Mastercode program, the Assembler. Its purpose is to allow you to enter programs in assembly language, together with a variety of features which make such program ming easier, and then to see them automatically translated into a machine code program. The price that has been paid for the flexibility and power of this part of the program is that it is immensely complex. Entering it will be a long job for you, and no doubt there will be many errors along the way, here you must rely on the Checksum Tables to guide you. At the end of the process you will have the same program that we used to develop all our machine code routines for this book. The program works and that is suffi cient justification for the effort that it will involve.
SECTION 1: Initialisation
MODULE 4.1
19046 TA* (2) = TA$ (2) + "B Y7/WRDDBY'END0R6PR
TSYM" !
19047 T* = 116121 0 690B0F 0 2 430D0 1000507
018D858"
19048 T$ = T*+"B8 CDE CCC CEC A88 4DE EE8 C84 C2
0ADAEAC"
19049 T* = T-$+"4A EA0D48 0868 282A6 A406 0ED3
8F8788D"
19050 T$ = T$ + "8E 8CAAA 6 B A8A9A 9 8" 19051 GOSLIB 12200 : TA$(3> = Tl* 19052 T* = "FF 11FFFFF F 0 90AFF F F 1D0EFFF
F051EFF"
19053 T $ = T$+ " FF 15 F F FFFFF F F FFFFF 0 1FFFFF
F1916FF"
19054 T-t = I $: + " FF2D FFFF2C 293 EFFFF3D2 EFF F F2526FF"
19055 T$ = T* + ”FF35 FFFFFFFFFFFFFF31 FFFFF F3936FF"
19056 T $ = "FF5 1F FFFF F495 EFFF F5D4 EFF6
57
Page 60
Machine Code Master
C4546FF"
19057 TT = TT + "FF55FFFFFFFRFFFFFF4-llFFFFF
F5956FF"
19058 TT = T7 + " FrF6DFFF FFF69,7EF F FF7D 6EFFF
F6566FF"
19059 BOSUB 12200 : TAT-(4) >= TIT
19060 TT = " FF75FFFF-FFFFFFFF'FF J TFFFFF
F7976FF"
19061 TT = T7+ " F F9 1FFFF9 49D 96FF FFF FFFF F8
48586FF"
19062 TT = T$ + " FF9 5FFF FFFF F FFFF FF81FFFFF
F99FFFF"
19063 T* = Tt+"BCB1BEFFA0A9A2FFFFBD,FFAFA
4A5A6FF"
19064 T*
4B9B6FF"
19065 T$
= T$+"FFB5FF F F FFFFF F F FFFA1FFFFB = Tt+ " FFD l FF FFC 0C9-DEFFFFDe|f FFFC
4C5C6FF"
19066 T$
_ T$ + f p d s f f F F FFFFFF F F F F C1FFFFF
FD9D6FF"
19067 BOSUB 12200 : TA * (4) = T A *(4)+T 1 $
19068 T# = 'FFF1FFFFE0E9FEFFFFFDFFFFE
4E5E6FF"
19069 T:$ = 7'$+ " FFF 5 FFFFFF FFF FFFFFE 1FF FFF
FF9F6
19070
19080 19101 19103
II
BOSUB 12200 : T A T(4) = T A T (4)+717 SM - 50 : SE =: 0 s DIM ST ABLET (SM) DIM ERRT(18) ERRT(l) = SINGLE BYTE OUT OF RANG
E"
19104
E R RT (2) = "DOUBLE BYTE OUT OF RANG
E"
19105
E"
19106
19107
19108
II
19109
19110
19112
19113
19 114
ERRT < 3) = "INVALID OPRAND OR OF:'COD
E R RT (4) = "INVALID OPERATOR" E R RT (5) = "INDEX IS NOT X OR Y" E R RT (6) = "LABEL NOT ALPH A-NUMERI C
E R RT (7) = "INCORRECT NUMBER BASE" E R RT (8) = LABEL DEFINED TWICE" E R RT (10) = "BRANCH OUT OF RANGE" E R RT (11) = "UNDEFINED LABEL" E R RT (12) = "ONLY SINGL E CHR. EXPEC
TED"
58
Page 61
Chapter 4 Mastercode Assembler
19116 E R R* (14) =
19.1.17 ERR* (15) = 19120 ERR* (1.8) =
AILBL.E WITH THIS
19980 DIM F I* (25
"OUT OF SYMBOL. SPACE "DIVISION BY ZERO" "ADDRESSING MODE NOT
OPCODE"
1) : GOSLJB 24300
AV
1,9990 RETU RN REA D Y .
If you have been taking note of what you have entered so far you will immediately realise that what you are about to enter here is not a module that stands alone in its own right but an addition to an existing module, namely the initialisation module for the tables of opcodes and operand types upon which the Disassembler works. In the case of the Assembler the same tables will be used, but in the reverse direction. Instead of finding a value in the memory and then looking up an appropriate opcode mnemo nic and addressing mode, the assembler will scan the files entered through the File Editor and try to construct the machine-code equivalent of each line either that or reject the line as an invalid instruction.
If you think about it, this requires some more information for, instead of being able to read a value and then choose a format based upon that opcode, the Assembler must, on finding an instruction like load at the beginning of a line like LDA SAAAA.X, be able to scan through all the possible formats for a load instruction to see whether or not the present instruction is a permissible one. In order to achieve this, two more tables are added to those already stored in the program. Between 19047 and 19050 is stored a table of two-character hex numbers corresponding to each of the possible opcodes stored in TA$(2) for the Disassembler. These show, for each opcode, the first operand type which may be used. Lines 19052-19067 consist of further operand types for each particular group of opcodes.
Later in the program we shall see how each possible operand type is compared with what is actually in the assembler instruction contained
within a line in FIS. For the moment you will do well to simply understand
that on detecting an instruction beginning with ADC (the first three cha
racter opcode in TA$(2), the Assembler will go to TA$(3). It will then discover that this may possibly be an instruction involving opcode 61 (hex) and will examine the format of the assembler instruction to see whether it fits the format required by opcode 61 hex (eg ADC ($50,X). If the format of the line being entered does not conform to that needed by opcode 61 hex, then the value of 61 hex (97 decimal), will be used to find the next possible opcode in TA$(4). This will be found in the 98th character pair of TA$(4) (numbering always starts from zero) and the opcode there is 6D signifying another instruction involving ADC, but this time taking a format such as ADC $AAA. The value 6D is then used to find the next opcode in the table which would produce an instruction beginning with ADC.
59
Page 62
Machine Code Master
In the case of ADC there are eight possible opcodes and if after examin ing each one against the actual format of the instruction in the line in FIS none of them fit, the last possible opcode will contain the value FF, indi cating that the end of the chain of possible ADC instructions has been reached and that no permissible opcode conforms to what is actually in the line. If you care to work through the tables with any three letter opcode
type you care to choose, first of all finding its position in TA$, then finding
the start of the corresponding chain of opcode values in TA$(3) and following the chain through TA$(4) you should quickly be able to see what is happening. The one real addition to the tables set up already by the disassembler is that made by line 19046. This apparently adds seven new opcode types to the list which the Disassembler worked upon. These are the assembler directives, seven instructions which are not actually assembly language instructions but rather instructions to the Assembler to behave in a certain way while it is processing on the assembly language program. The seven directives, BYT, WRD, DBY, END, ORG, PRT and SYM will be explained fully later in the program.
From 19100 to 19120 you will find the various error messages the Assem bler is capable of generating when it comes across invalid instructions or omissions from the program. These too will be explained more fully in due course.
CHECKSUM TABLE
19046 193 19049 19052
*-> c;
uL uJ
251 19053 19055 1 19058 238 19061 198 19064 38 19067 221 19070
221 19103 53 19106 19109 191 13
91
152
8 19117 122
19990
MODULE 4.2
142
19047 19050
171 170
248 19056 19059
187
245 19062 53 19065 19068
13
91 19080 27 19104 47 19107 19110 19114 19120
192 215 184
37
19048 189
19051 244
19054 187
19057 8
19060
19063
79
216 19066 68 19069 19101 19105
192 109
77 19108 1 191 12 253 19116 40 19980 101
20000 REM*** *** *** **** *** **** *** **** *** 20001 REM GENERATE ASSEMBLY LISTING 20002 REM*** *** **** *** *** **** *** **** ***
60
Page 63
Chapter 4 Mastercode Assembler
20005 SE = 0 : FMAX = LEN(PTRT) : SY = F AL.SE 20010 INPUT " ERROR ONLY LISTING ( Y/N )
: ; TT 20020 EO = LEFTT(TT, 1 >="Y" 20025 INPUT " A SSEMB LE TO MEMORY ( Y/N )
: " ; TT 20029 AM = LE F TT (T T ,1)="Y "
20030 AD - 0 : REM SET START ADDRESS
20040 FOR Q = 1 TO FMAX
20050 I NT = FI LET (ASC (MIDT (F'TRT , Q , 1) ) ) :
OT = ""
20060 GOSUB 26400
20070 IF EXIT THEN GMFMAX+1
20080 NEXT Q 20085 T = FRE(X) 2009 0 AD = 0 : EC = 0 : PRINT "ADD. DAT
A SOURCE CODE" 20100 FOR Q = 1 TO FMAX
20110 INT = FILET (ASC (Ml'DT (F'TRT,Q, 1 >) ) :
OT = "" 20120 Q1 = AD 20130 GOSUB 27600 20140 IF ERR THEN 20250 20145 IF EO THEN 20222 20150 H = Q1 : GOSUB 11000 20160 QT = HT 20180 Q2 = 3 : IF L E N (O T )<Q2 THEN Q2 = L EN(OT) 20185 Q1T ="" : IF OT="" THEN 20221 20190 FOR Q3 = 1 TO Q2 20200 H = AS C (M I D T (O T ,Q3 ,1)) : GOSUB 110 00 20210 IF LE N(HT )=1 THEN HT = "0"+HT 20220 Q1T = Q1T+HT : NEXT Q3 20221 PRINT QT SPC (6-L..EN (QT) > Q1T SPC(8- LEN(QIT)) ; : GOSUB 28100 20222 IF NOT AM OR OT*"" THEN 20250 20225 FOR X = 1 TO LEN(OT) : POKE Ql+X-1
,AS C(M I DT (O T ,X ,1)) : NEXT 20250 IF EXIT THEN Q = FMAX+1 : REM LEAV E LOOP
20260 NEXT Q
20270 PRINT : PRINT " TOTAL ERRORS IN FI
61
Page 64
Machine Code Master
LE
---
" EC : PRINT
20280 IF SY THEN GGSU B 26900
20290 IF P E EK (152) <> 0 THEM PRINT#2 : C
L0SE2 : GOTO 20300
20295 GET TT : IF T$="" THEN 20295
20300 RETU RN
READ Y .
EXAMPLE ERRORS: Error only listing
ADD. DATA SOURCE CODE
50 LBL000 LDQ *A000
LABEL DEFINED TWICE ERROR
60 JSR ($=300)
ADDR ESSING MODE NOT AV AILBLE WITH THI
S OPCODE ERROR
70 L.DA #L BL000/H
DIVI SION BY ZERO ERROR
80 LDX #LBL000-LB L00 0/256
@256
INVALID OPERATOR ERROR
140
BCC LB L000
BRANCH OUT OF RANGE
150 JMP L.BL001
UNDEFI NED LABEL ERROR
150 JMP LBL.001
UNDEFI NED LABEL ERROR
160 LBL000 RTS
LABEL DEFINED TWICE ERROR
TOTAL ERRORS IN FILE
H 0
LBL000 C800
TOTAL NUMBER OF SY MB OLS
62
ERROR
---
0
8
---
2
Page 65
Chapter 4 Mastercode Assembler
EXAMPLE ERRORS: FuU listing
ADD. DATA SOURCE CODE 0 10 PRT 0 20 SYM 0 30 ORG $C800 C800 40 H = 0
50 LBL000 LDQ $A000
LABEL DEFIN ED TWICE ERROR
C800 50 LBL000 LDQ $A000
60 JSR ($300)
ADDR ESSING MODE NOT AVAI LBLE WITH THI
S OPCODE ERROR
70 LDA #LBL000/H
DIVI SION BY ZERO ERROR
80 LDX #LBL 000-L BL0 00/25 6
@256
INVALID OPER ATOR ERROR
C804
C806 8642
C808 60
C809
CA00 18
8543 90 ST A S<103
1 0 0
STX Sc 102
1 1 0
RTS
1 2 0
ORG $CA00 130 CLC 140 BCC LBL000
BRANCH OUT OF RANGE ERROR
150 JMP LBL001
UNDEFI NED LABEL ERROR
150 JMP LBL001
UNDEFI NED LABEL ERRO R
160 LBL0 00 RTS
LABEL DEFIN ED TWICE ERROR
CA06 160 LBL000 RTS
TOTAL ERRORS IN FILE
---
8
H 0 LBL000 C800
TOTAL NUMB ER OF SYMBOLS
---
2
63
Page 66
Machine Code Master
In previous sections of the overall program we have adopted the approach of first explaining all the modules which are necessary to make a control module work before entering the control module itself. To do that in the case of the Assembler would result in scores of pages of explanations before any picture could be built up of what the program is setting out to do. The sheer complexity of the Assembler dictates that we adopt a top down approach and attempt to work our way from a simple explanation of the working of the program to a detailed examination of the full listing, filling in details all the time. It is for that reason that we begin our commen tary on the main part of the Assembler with this main control module. The module on its own is totally helpless, it does almost no work itself but simply allocates work between various other sections of the program. Nev ertheless, commenting on it at this early stage will help to give us a much needed overview of the Assemblers functioning.
Commentary
20010-20029: The Assembler is capable of compiling a machine code pro gram in four different ways. It can provide a full listing of the assembly language instructions, together with a notification of any errors present or it can skip the listing and provide only the errors. An example of both of these was provided at the end of this module. It can also be directed to place the machine code program resulting from the assembly into memory or it can be told to run through the program but leave the memory untouched.
If, for instance, you wish to place a machine code routine in a specific area of memory between a specified start point and a specified finish point, without corrupting any of the memory outside those points, you would do well to ask first for a full listing without the program being placed into memory. This will show exactly where the assembled machine code would have been placed in memory before anything irrevocable is done.
20030-20085: Before starting work on the assembly language program the variable AD is set to zero, signifying that the address at which the eventual machine code program will start is zero. During the course of the assembly language program this start point will in almost every case be reset to some other point in the memory using the assembler directive ORG (origin). The assembler will now work through the program twice in what are called
passes. This loop calls up the section of the program which performs
Pass 1. During Pass 1 any variables (including a special kind of variable called a label, which defines the correct destination in the memory for a jump instruction) are examined and placed, together with their associated values, into a table known as the symbol table which will be used in the later assembly of the program.
64
Page 67
Chapter 4 Mastercode Assembler
Each line of the assembly language program is obtained in INS before Pass 1 is executed upon it. On returning from the execution of Pass 1 on any particular line, a test is made of the variable EXIT, which is set to TRUE if the assembler directive END is met with during the examination of the program. At this point the assembly will cease, even if the end of the file in FIS has not been reached. At the conclusion of the loop the FRE function is called, thus ensuring that garbage collection is done and there are no dangers of running out of memory.
20090-20300: This is the loop which controls the second pass through the program to be assembled. The routine for the second pass is called up at line 20130. During the second pass the program will actually be assembled, with each valid instruction being translated into the bytes necessary to rep resent the opcode and operand in machine code, including the translation of variables into values and the assignment of values to labels used for jumps. On returning from the routine a test is made of the variable ERR which records whether an error has been detected. If so, no further processing is done on the instruction. If an error only listing has been spe cified (EO is set to TRUE) the print routine is omitted. In lines 20150-20221 the information returned from the second pass is printed out in a formatted layout. It includes the address at which an instruction will be placed in the memory if the program is in fact assembled to memory, the hex represen tation of the 1,2 or 3 bytes that will be placed there and the original assem bly language instruction. The bytes of the necessary machine code instruc tion are contained in OS and in lines 20222-20225. Provided that AM is TRUE, these bytes are placed into memory beginning at the appropriate location. A test is made that the END directive has not been found and the next line of the program is picked up if not. Finally, if the assembler directive SYM has been encountered during the course of the program the variable SY will be set to TRUE and the symbol table will be printed out at the end of the listing of the assembled program
CHECKSUM TABLE
20000 123
20005
20025
3
197 20029 189 20030
20040 37
20070 214
-20090
244
20120 249
20.145 30
20180 109
20200
5
20001 .180
2000.2 123
20010 227 20020 195
144 20050 139 20060 20080 243 2008 5
169
167 20100 37 201.1.0 139 20130
20.1.50 20185 40 20190 175 20210
172 213 20160 21.1
'" t ~i -j
20140 i 16
20220 .244
65
Page 68
Machine Code Master
2 0 2 21 8 6
20250 6
20280 236
20222 58 20260 24 20290 63
20300 142
SECTION 2: Pass One Routines
MODULE 4.3
2:6400 RE M** **** *** **** *** **** *** **** *** 26401 REM DO PASS 1 ASSEMBLY ON IN* 26402 REM* **** **** *** *** **** *** **** *** * 26405 PRINT " C HOME 3 C22*CD 3 L'40 SPACES]
26406 PR IN T
26407 PRINT "CHOM E 3 C 2 2*CD 3" G OSUB 281 00 26410 PASS = 1 : EXIT = FALSE : PTR = 2 26420 GOSUB 28850 26430 IF NOT ERR THEN 26540 26440 IF T=58 AND LEN< H$>=0 THEN 26420 26450 IF T=59 OR T=--l THEN RE TU RN 26460 GOSUB 28700 26480 GOSUB 28850
26490 IF NOT ERR THEN 26540 26500 IF T=58 AND L.EN(Ht)=0 THEN 26420 26520 RETUR N 26540 IF P O>55 THEN GO SU B 26600 : GOTO 2
6556 26550 GOSUB 26100 26552 GOSUB 26 30 0 : IF ERR AND O P >3 AND OP< 7 THEN OP = OP+ 6 : GOTO 26552 26555 GOSUB 26560 26556 IF L.EN (IN$> >PTR AND NOT EXIT THEN 26420 26557 RETURN
Having examined the overall control module for the two passes we now turn to the control module for Pass 1. Once again we shall leave until later an explanation of how the specific tasks necessary are actually accomplished and concentrate on achieving an overview of what the pass actually does.
66
Page 69
Chapter 4 Mastercode Assembler
Commentary
26400-26407: These lines clear the bottom two lines on the screen and print there the assembly language instruction currently being processed, purely to guide the user as to how far the pass has progressed.
26410: The variable PTR indicates where the examination of the current line will begin. It is set to 2 in order to skip over the two bytes containing the line number.
26420: The routine which identifies the mnemonic using the table in TA$(2) is called. The routine will scan IN$ from the character after that indicated by PTR until it finds a character which is not a letter or a digit, then return.
26430-26520: On return from the previous GOSUB, H$ will contain a string of characters which were terminated by a space, colon or any other character which is not a letter or digit. If, on return from the previous GOSUB a valid mnemonic for an opcode has not been found and placed into H$, line 26440 tests whether any characters at all were found before the colon separator between instructions on the same line (or any other character which is not a letter or digit). If not, the colon is ignored and the subroutine to find a menomonic is called again, starting after the colon.
In 26540 a test is made to see whether a semi-colon or the end of line has been reached. If so no further action is taken in respect of the current line. Comments may thus be entered in a program without confusion, provided that they commence with a semi-colon. If H$ does contain characters then, since they have not been identified as a mnemonic they are assumed to be a label of some kind and the name is entered into the symbol table by the subroutine at 28700. On return from placing the assumed label into the symbol table the program goes back to searching for the opcode mnemonic which should follow the label.
26540: At this point in the program a valid mnemonic must have been detected. If its position in the tables, as indicated by the variable PO, is greater than 55 then it is an assembler directive and the subroutine at 26600 is called up to evaluate it.
26550: Having found a valid opcode mnemonic at this point, the subrou tine which evaluates the operand type is called.
26552: We now have a valid mnemonic and, hopefully, a valid operand type. However there is no guarantee that the particular operand type is appropriate to the particular opcode. This line calls the subroutine which established whether they do in fact make a valid pair. The subroutine, if it comes across an address which could accessed by a zero page addressing mode, will assume that zero page addressing mode is being used, even though this may result in an error being flagged because the particular
67
Page 70
Machine Code Master
opcode cannot use zero page addressing. On return from the subroutine, if the addressing mode selected is zero page and a mismatch is indicated, the operand type represented by the variable OP is incremented by 6 to trans form it into an absolute addressing mode.
26555: In assessing the assembly language instruction there is always a need to keep a count of how many bytes the assembled instruction will require so that the next instruction will commence at the correct place in memory. This is accomplished by the subroutine at 26560.
26556: If the line is not exhausted by what has so far been analysed and END has not been detected, the rest of the line is processed in the same way.
CHECKSUM TABLE
26400 26405
123 26401
'--i Cj
26406 56 26410 255 26420 180 26430 26440 84
26450
26480 180 26490
1 0 2
6 8
26520 142 26540 34 26550 26552 190 26555 176
26402 123 26407
26460 26500
'? ~7
6 8
174
84
166
26556 247
26557 142
MODULE 4.4
28100 REM**** *** **** *** **** *** **** *** ** 28101 REM PRINT IN* TO THE SCREEN 28102 REM**** *** **** *** **** *** **** *** ** 28120 PRIN T 2 5 6* A S C(M I (IN # ,2,1))+ AS C (M
ID*(I N *,1,1)) MID* (IN* ,3)
28140 RETURN
This module simply prints out the current line of the assembly language program, including its line number. This is printed to the bottom of the screen on the first pass. In the second pass the assembler directive PRT can be included in the program to send the output to a printer.
68
Page 71
Chapter 4 Mastercode Assembler
CHECKSUM TABLE
28:1.00 123 28101 187 28102 123 28120 80 28140 142
MODULE 4.5
28150 REM********* *********************- 28151 REM SYMB OL TO MON -LE TTER/DIG IT 28152 REM** *** **** *** **** *** **** *** **** 28160 H* = "" : T = -1 28165 RTF: = PTR+1 28170 IF P T R> L E N<IN*) THEM 28210 28180 T = ASC (MID* (I N* , RTF:, 1) ) 28185 IF T=32 AND LEN (H$ >=0 THEN 28160 28190 IF T <48 OR T >90 OR < I">57 AND T<65
) THEM 28210 28200 H* = H * +C H R* (T ) : G OTO 28165 28210 RETU RN
This simple module scans the line in INS from the point indicated by the variable PTR, making up a string, H$, from which any leading spaces are stripped and which ends whenever a character which is not a letter or digit is encountered. The module is used by the following module to return a string which may contain an opcode mnemonic or a label.
CHECKSUM TABLE
28150 123 28151
240 28160 62 28165 185 28180 178 28185
79 28190
28152 28170 5
123
179
28200 9 28210 142
MODULE 4.6
28850 REM*********** ************* ******
28851 REM TEST FOR ORCODE/D IRE CTIVE 2 81352 R E M * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 28860 (30SUB 28150 28870 ERR = FALSE 28890 FTR = RT R.1 28895 IF LEN <hi*) < >3 THEN 28940 28900 PO = --2 28910 PO F'0-1-3
69
Page 72
Machine Code Master
28920 IF H T = MI D T ( TA T (2 ),P0,3) THEN 28950 28930 IF (F'O+3) < =LEN (TAT (2) > THEN 28910 28940 ERR = TRUE 28950 PO = (P0-l)/3 28960 ERR = <P0=56> OR ERR 28970 IF P O>56 THEN PO = PO--1 28980 RETURN
RE A D Y.
Having obtained a string of characters which may or may not contain a valid opcode or label we now begin the process of actually evaluating what we have found. The rough method of searching for the correct opcode was described under Module 1 and the process begins with this module.
Commentary
28890: If the string returned in H$ is not three characters long then it cannot be a valid opcode and there is no point in searching the tables.
28895: PTR is reset to point to the last character of H$ in the line from which it was drawn.
28900-28940: This is a loop which scans TA$(2) which contains the valid three letter mnemonics to compare each set of characters with what has been picked up in H$. The pointer for this purpose is first set to -2 in order that on the first iteration of the loop, when 3 is added, the search starts at one. If the whole loop is executed and line 28940 reached, it can only be because the three characters do not conform to any of the mnemonics for opcodes specified in the table.
28950: The address in TA$(2), which was incremented in steps of three, is now adjusted so that, for instance, the three characters at position 19-21 are now identified in PO as mnemonic 7.
28960: This strange looking line is here to take account of the fact that the Disassembler tables on which the Assembler works contain the three cha racters ??? to cope with times when the Disassembler cannot provide a valid opcode for what is in the memory. Without this check you would be able to enter ? ? ?1 into an assembly language program and throw the whole thing into confusion when it was found as a valid menomonic. The line flags an error if H$ consists of ???\
28970: This line is also there to take account of the *??? in the table. The assembler directives fall after the question marks and so, when numbering them for the purposes of the assembler, their position is reduced by one.
70
Page 73
CHECKSUM TABLE
Chapter 4 Mastercode Assembler
28850 28860 173 28895 176 28900 28920 57 28950
123 28851 158/
28870 70
1 10 28930 24 28960
193
28852 28890 28910
123
186
13 28940 27 28970
89
2 o 9 8 061142
MODULE 4.7
28700 R E M * * * * * * * * ********* * * * * ***** * * * *
28701 REM ADD SYMBOL TO SYMBOL TABLE 28702 REM********************##******** 28710 IF BE >~SM THEM EXIT « TRUE : PASS
2 : EM « 14 s GOTO 28000 28720 GOSUB 28250 ; IF NOT ERR THEN 2883
0
28740 T* = LEFT*(H* +" ", 6) 28745 TB = PTR 28750 GOSUB 2815 0 : REM DOES « FOLLOW 28760 IF T<>61 THEN PTR - TB : RE = AD :
GOTO 28780 28770 70 - T ; GOSUB 28600 28780 EN 0
28790 IF RE<0 OR RE >65535 'THEN ST*( SE>=T *+CHR* (0) + CHR* (0) +C HR* (2) n GOTO 28810 28800 S T * (SE ) = T * + C HR * (RE-1 NT (RE/ 25 6)*2
56 ) + CH R *<I N T(RE/256)) 28810 SE = SE+1 28820 RETURN 28830 IF P A S S 551 AND L E N( S T* (71))<9 THEN S T * (T 1) = S T * (T 1)+ CH R* (8) 28835 IF P A S S 0 2 THEN 28840 28836 TA = PTR : GOSUB 28150 : IF 7 0 6 1 THEN PTR = TA : GOTO 2884 0 23837 GOSUB 26000 : REM SCAN PAST « SIGN
(IF PRESENT) ON PASS 2 28840 IF PA SS O-2 OR LEN (ST* (T 1) ) <9 THEN RETURN 28845 EN = AS C (MI D* (ST *(T1),9,1)) : GOTO
28000
REA D Y .
This is the control module for evaluating variables and labels and plac
ing them into the symbol table if they have not already been defined. Ear-
71
Page 74
Machine Code Master
Her, under Module 2, a label was described as a kind of variable for the sake of simplicity. In fact a label is a constant which identifies a point in a machine code program to which a jump may be made. By using labels it becomes possible to assemble a machine code program to a different place in the memory without having to recalculate the addresses to which jumps will be made. The Assembler will automatically identify the position in memory of a labelled instruction and replace a jump to the label with a
jump to that address.
Commentary
28710: If there are more symbols than the symbol table is set up for (50), then assembly of the program ceases immediately and the appropriate error is flagged.
28720: The label in H$ is now sent to the next module, which examines the symbol table (STS) to see whether it is already present. If it is present then ERR is returned as false, and an error label defined twice will be flagged. This reverse use of error may seem confusing but is necessary since a later use of the module at 28250 will require an error to be flagged if a label is
not in the symbol table.
28740: H$ is padded out to six characters if it is shorter than that. Six cha racters is the maximum for any label.
28745-28760: The content of H$, if it is valid at all, may be either a varia ble or a label. If it is a label then all the Assembler will need to know is the address of the instruction so labelled. If it is a variable it will be followed by an = to set its value. The scanning module at 28150 is called up to get the next character. If the next character after the variable (ignoring spaces) is not an equals sign then it must be a label and RE (REsult) is used
to store the current address of the instruction. PTR is backed up to the
end of the label again using the temporary variable TB.
28870: If the contents of H$ do contain a variable then the expression evaluator section of the program is now called up. No attempt will be made to explain the working of the expression evaluator until the end of
the program since it would interrupt our attempt to follow through the
main workings of the Assembler. For the moment all that you need to accept is that a call to the expression evaluator for a line like VAR = 256*BYTE1 -I-15 would return in the variable RE the result of the right hand part of the equation. All will ultimately be made clear!
72
Page 75
Chapter 4 Mastercode Assembler
28790: If RE is less than zero or greater than 65535 (the maximum value which can be dealt with by the CPU in one instruction) then to the variable name or label in the symbol table are added two characters which represent a result of 0 and another which flags an error double byte out of range.
28800: If RE is a valid number then the number is added in two byte form to the end of the variable or label name in ST$. Since the name has been set to 6 characters in every case it will be simple to recover the value of RE for any variable or label.
28830: This line is only accessed if the current name is already in the symbol table. Provided that an error code is not already attached to the name, it has error code 8 added to it, indicating label defined twice.
28835-28837: This module is also used by the second pass through the pro
gram. On pass 2 the name will already be in the symbol table (placed there
by pass one) and so the first part of the module will not be carried out. On pass 2, having obtained the name in H$, if the next character is an equals, then the result of the expression has already been obtained and the module at 26000, which finds the end of an expression or line, is called to skip over the rest of the expression.
28840: Error messages are only printed on pass 2 and, fairly obviously, only if there is an error code attached to the end of a name in the symbol table.
CHECKSUM TABLE
28700 123 28710 239 28745
126
28770 241
28701
28720 28750 28780
175
112
81
18 i. 28800 251 28810 253 28820 28830 28837
MODULE 4.8
106 160
28835 28840
101
126
28702 1 23 28740 31 28760
227
28790 40
142 28836 28845
1 1 7
55
28250 RElM* **** *** **** *** *** **** *** **** *
28251 REM FIND LABEL IN ST* 28252 REM* *** *** **** *** **** *** **** *** ** 28260 ERR = FALSE s H = 0 : T1 = 0 28270 IF LEN( H * > < 6 THEN H* = H*+" " : GO
TO 28270
28280 IF T1=SE THEN ERR = TRUE s RETURN
28290 IF MID* <ST* <T1> ,1,6) O H * THEN T1 =
T 1 +i s GOTO 28280
73
Page 76
Machine Code Master
28295 H = ASC (MID4> <STT (T1) ,8,1) ) *256+ASC
(MID *(ST*(T1),7,1)) : RETURN
This a straightforward module which is called by the previous one to determine whether a variable or label name is already in the symbol table. The module returns an error flag of 1 or 0 to indicate the presence or absence of the variable or label. Also returned, if present is the result con tained in characters 7 and 8.
CHECKSUM TABLE
28250 123 28251 242 28252 123 28260 75 28270 249 28280 132 28290 219 28295 92
MODULE 4.9
28000 REM** *** **** *** **** *** **** *** **** 28001 REM ASSEMBLER ERROR ROUTINE 28002 REM** *** **** *** **** *** **** *** **** 28005 IF PT R>=300 OR PA S S < >2 THEN 28050
: REM SUPR ESS SECONDARY ERROR S IN LINE 28010 PRINT SF'C (14) ; : GOSUB 28100 28015 EC = EC+1 28020 FOR X = -13 TO PTR : PRINT " = " NEXT X : P RINT "ECU 3" 28030 PRINT " " ERR*(EN> " ERROR" 28040 PTR = 300 : ERR * TRUE 28050 RETURN
This module, which is called by line 28840 in Module 4.7, prints out an
error message where an error is flagged.
Commentary
28005: If an error has already been notified for the current line, the varia ble PTR is set to the impossible value of 300 (maximum length of a string is
255) and no subsequent error messages are printed for that line. Errors are not printed on pass 1.
28010: On the second pass, the memory address and byte data take 14 spaces on the line. When a line is printed and an error is to be flagged the address and data are not printed.
28020-28030: The error is not only flagged by an error message in the output, a pointer is printed at the approximate position in the line where
the error has been detected, as indicated by the value of PTR.
74
Page 77
CHECKSUM TABLE
Chapter 4 Mastercode Assembler
28000
28005
28020
123 28001 61 28002
cpr?
1 2
28010 106 28015 28030 124 28040
28050 142
MODULE 4.10
26000 RE M*** **** *** ******* *** **** *** ***
26001 REM SYMB OL UP TO COLON ETC.
26002 RE M*** **** *** ******* *** **** *** ***
26010 H$ = "" : T 1 = L EN UN $ ) 26020 PTR = PTR+1 26030 IF T 1<PTR THEN 26060
26040 T = ASC(MI D * (IN*,P T R,1)>
26045 IF T=32 THEN 26020 26050 IF T< >58 AND T< >59 THEN H* = H*+CH R$<T) : GOTO 26020 26060 RETURN
This module is similar to the module at 28150 (Module 5), its purpose
being to determine the end point of an assembler instruction. It is different
from Module 5 in that it does not return on finding a non-letter/non-digit character but only on finding a delimiter such as a colon, semi-colon or the end of line, dropping any spaces which are present in the original line.
CHECKSUM TABLE
26000
1 ^ ~:'I
26001 26010 98 26 020 185 26040 178 26045 247 26050
2 1 0
26002
123
26030 190
2 0 1
26060 142
MO DU LE4.il
26600 REM **** *** **** *** **** *** **** *** **
26601 RE M CA LCULATE DIRE CTI VE LENGT H
26602 REM** *** **** *** **** *** **** *** *** *
26610 T 1 = L EN (IN$) 26620 IF P0 =5 6 THEN 26720 : REM BYT DIRE CTIVE 26625 IF PO=60 THEN GOSUB 28600 : AD = R ESULT : REM DEAL WITH ORG DIRECT IVE
75
Page 78
Machine Code Master
26627 IF P0 =5 9 THEN EXIT = TRUE 26630 IF PC)>58 THEN RE TURN : REM END & 0 RG DIREC TIV ES 26640 REM FIND LEN. OF WRD & DBY 26650 AD = AD+2
26660 PTR = PTR+1
26670 IF P T R > T1 THEN RETURN 26680 T = A S C (MI D T(IN T,P T R,1 )) 26690 IF T=58 OR T=59 THEN RETURN 26700 IF T< >46 THEN 26660 26710 GOTO 26650 26720 REM LE NGTH FOR BYT. 26730 AD = AD+1 26740 PTR = PTR+1 26750 IF P T R > T1 THEN RETURN 26760 T = AS C (M I D T(I N T,P T R,1)) 26770 IF T=58 OR T=59 THEN RETURN 26780 IF T< >46 THEN 26740 26790 GOTO 26730
This module is used exclusively by Pass 1 and acts upon those assembler directives which are relevant to that part of the program execution, these being BYT, WRD, DBY, END, ORG. The module is called from Module 3 whenever an assembler directive is detected.
Commentary
26620: This deals with the BYT directive and will be discussed under 26720. 26625:60 is the code for the ORG directive, which is used to set the address
in memory on which subsequent assembly will be based. ORG will be followed on the line by an expression and the expression evaluator (not explained yet) is called to get the desired address from the expression. AD, the address at which the next machine code byte will be placed is then set equal to the result of the expression.
26627: If the END directive is encountered the variable EXIT is set to TRUE.
26630: Other than ORG and END, none of the directives with a code
greater than 58 (SYM, PRT) affect program execution on the first pass.
26640-26710: At this point in the program execution, what has been encountered must be one of the two directives WRD and DBY. These take
the form in the assembly language program:
WRD (or DBY) $AAAA.$BBBB.$CCCC ie the directive followed by a series of two byte values which will be placed directly into memory thus
76
Page 79
Chapter 4 Mastercode Assembler
allowing a table to be defined.
The difference between the two directives is that WRD will take the two bytes specified by, for instance $ABCD and store them in the memory in the order CD, AB while DBY will store them in the order AB, CD. The CPU chip normally works upon two byte numbers where the least significant byte (CD in our example) comes first. The problem with these two directives on the first pass is that, as we have previously noted, a record must be kept of the length in bytes of each instruction in order that labels may be given their correct addresses in the memory when they are defined on the first pass. BYT and WRD can have any number of two byte values after them up to the maximum string length of 255. This loop there fore scans the line, counting the number of two byte values and incrementing the address counter AD by two for each value found.
26720-26790: The BYT instruction specifies single byte values to be placed into memory. This loop performs the same function as the previous one but only increments the address counter by one for each value specified.
CHECKSUM TABLE
26600
123 26601 26610 70 26627
189 26630 61 26640 4
26620 38
f? '~?
26602 123
26625 40
26650 216 26660 185 26670 76 26680 26710 26740
178 26690 247
172
185 26750 76 26760 178 26770 247
MODULE 4.12
26720 181 26730
26780
183 26790
26700 184
215
171
26:1.00 REM******************.************ 26101 REM OP ER AND TYPE TO BE USED 26102 REM* **** *** *** *** *** *** *** *** *** * 26110 T6 = PTR : GOSUB 26000 26120 ERR = FALSE 26130 IF LEN<H$>=0 THEN OP = 1 : RETURN 26140 IF H$="A" THEN OP = 0 : RETURN 26145 IF A SC(H $)=35 THEN OP = 2 : RETURN
26170 OP = 12
26180 IF LE FT * (HIT, !)="(" THEN OP = OP-3
26190 T = 1 : T 1 = LEN(HT)
26200 T2 = ASC(MID$(H:T,T, 1) >
26210 IF T 2< >46 AND TCTi THEN T = T+i :
GOTO 26200
77
Page 80
Machine Code Master
26220 IF T2<>46 THEN 26275 26230 T = T+l : IF T> T 3. THEN 26270 26240 T2 = ASC (MID* < FIT , T ,1) ) 26250 IF" T2=89 THEN OP = O P - 1 : GOTO 262
75
26260 IF T28 8 THEN OP «* OP-2 : GOTO 262
75
26270 REM NOT A VALID INDEX
26272 EN « 5 s GOTO 28000
26275 IF (OP= :l. 2) AND ( (PO >2ANDP0< 6 ) OR (PO >6 A NDF'OC 10) QRP0 = 1 2 0 R P 0=11) THEN OP = 3 26281 REM ZERO PAGE OPRANDS
26282 IF OP< 1 0 THEN RETURN
26284 T'7 = PTR : PTR = T 6
26286 GOSUB 28600
26288 IF ERR OR R E S U L T >255 THEN 26292
26290 OP = OP - 6 26292 PTR « T7 26294 RETURN
Following on the development of Pass 1, as laid down by the control module, we now come to the two routines which determine the type of operand to be used and whether that operand type actually fits the opcode type, remembering that not every addressing mode can be used by every opcode type. The purpose of the present module is to determine the operand type which fits the format laid down in the instruction.
Commentary
26110: At this point PTR is indicating the character after the opcode mnemonic and the subroutine at 26000 is called to obtain the operand part of the instruction, stripped of its spaces.
26130: If the operand has zero length then the addressing mode must be implied, and the value of OP is zero.
26140: If the operand is A then the addressing mode is accumulator addressing, OP = 1.
26145: If the first character of the operand is then the addressing mode is immediate, OP = 2.
26150-26160: The temporary assumption is now made that the operand type is 3, relative addressing mode. The following subroutine is called to see if the tables in TA$ indicate that this is possible for the opcode that has been derived (ie the opcode must be a branch of some kind). The method by
78
Page 81
Chapter 4 Mastercode Assembler
which this is done will be described under the next module. The references to 0$ are only relevant to Pass 2. The subroutine at 26300 will place into 0$ the byte whose value represents the relevant opcode.
At this point, however, we are only using the subroutine to determine
whether the operand type is 3 we do not wish to increment 0$ at this point so we take a note of its length before the subroutine is called and then reset it to the same length on return. If an error is flagged on return from the subroutine at 26300 then operand type three does not fit the opcode we have and the subroutine continues.
26170-26260: These lines are a mirror image of the lines in the Disassembler
which work out the format of the operand from the value of the operand byte in a machine code instruction. In this case we work out the operand
type from examining the format.
26270-26280: If a full stop is detected and the format does conform to that for indexed addressing, error 5 is flagged index is not X or Y \
26282-26294: These lines test whether it is possible to perform the instruc
tion with a zero page addressing mode the format for absolute
addressing and zero-page addressing is the same and the assumption has been made up to this point that operands which could be either are in fact absolute addresses. This is only possible with operand types of 10 and above, representing the absolute addressing modes. The PTR is reset to the end of the opcode and the operand re-evaluated by the Expression Evalua tor. If the result falls in the range 0-255 then it is possible to use the faster zero page addressing mode and the operand type OP is reduced by 6 to transform the addressing mode into zero page addressing of some kind.
CHECKSUM TABLE
26100 123
26110 145
26140 254
26180 160 26210 243 26240 243 26270 41 26281 99 26286 173 26292 115
26101 213 26120 70 26145 250 26190 232 26220 236 26250 112 26272 215 26282 211 26288 156 26294 142
26102 123 26130 190 26170 244 26200 243 26230 12 26260 112 26275 213 26284 95 26290 17
79
Page 82
Machine Code Master
MODULE 4.13
26300 REM *** **** *** **** *** ******* *** *** 26301 REM EVALUAT E OPCODE 26302 REM *** **** *** **** *** ******* *** ***
26310 T 1 = 3 s T = PO
26320 T = ASC< M ID*<T A * <T1>, T + 1,1>>
26330 IF 1=255 THEN ERR = TRUE s RETURN
26340 T 1 = 4 s T2 = AS C (MI D * < T A $ <1>,IN T <
T/2 + 1 ) ,1))
26350 IF (1 AND T)=0 THEN 72 = INT(T2/16
)
26355 T2 = T2 AND 15
26360 IF T 2 O 0 P THEN 26320 26370 D* = 0*+CHR*<T> 26380 ERR = FALSE 26390 RETURN
At this point we again make full use of the new tables which were added to TA$ in the first module of the Assembler. The purpose of the module is to match the opcode that has been obtained with the operand type and see whether they are in fact compatible. If not an error must be flagged.
Commentary
26320: T has been set equal to PO, the position of the opcode mnemonic in
TA$(2) and thus the string equation in this line points to a pair of bytes in TA$(3). TA$(3) contains, for each of the possible opcodes types, the first
of the possible byte forms that the opcode can take. The value is also the first link in the chain of possible byte forms of the opcode.
26330: If, on subsequent iterations, the value found in the table (TA$(4) subsequently) is FF hex, then there are no more forms of the opcode availa ble and an error is flagged.
26340-26355: Having found the possible opcode, it is now compared with
the necessary addressing mode in TA$(1). The addressing modes for each
opcode are stored in TA$(1), two to a character. A single character can be used to store two numbers in the range 0-15, simply by multiplying one of
the numbers by 16 and then adding them together. Thus the addressing
mode for opcode one in the table of opcodes will be found in the first cha racter of TA$(1), as will the addressing mode for opcode two. Lines 26350
and 26355 extract the necessary half of the character value (0-15 and
16-255). If the opcode position (PO) in the table is odd, then the high half of the byte is used (T2/16) and if PO is even the low half of the byte is used (T2 AND 15).
80
Page 83
Chapter 4 Mastercode Assembler
26360: If the resulting addressing mode is not the same as that obtained by
examining the operand of the instruction in assembly language, then the
subroutine returns to 26320 and picks up the next possible form of the
opcode, together with its associated addressing mode and so on until there
are no further forms of that opcode mnemonic.
26370: If program execution has reached this point it is because an
addressing mode has been found in the tables which conforms to the
format of the operand picked up from the assembly language instruction.
The correct opcode for the operand and the opcode type is added to 0$, which is being used to store what will eventually be placed into memory, though this is only relevant on Pass 2.
CHECKSUM TABLE
26300 123
26310 9 26340 167 26360 24
26301 224 26320 191 26350 81 26370 238
26302 123
26330 87
.26355 .83
26380 70
26390 142
MODULE 4.14
26560 REM*** *** *** *** *** *** *** *** *** *** 26561 REM BYTE LE NG TH 26562 REM*** *** *** *** *** *** *** *** *** *** 26565 AD = AD+1 26570 IF 0P>1 THEN AD = AD+1 26580 IF O P> 8 THEN AD = AD+1 26590 RETU RN
We finish following through the work of the Assembler on Pass 1 with this short module. It simply uses the opcode type to determine how many bytes the assembled instruction will require when it is finally placed into memory on Pass 2. This is in order that the variable AD may be correctly updated for the purpose of defining labels.
CHECKSUM TABLE
26560 123 26561 197 2 6562 123 26565 215 26570 234 26580 241 26590 142
SECTION 3: Pass Two Routines
MODULE 4.15
27600 REM* *** **** ******** *** ******** *** 27601 REM DO PASS 2 ASSEMBLY
81
Page 84
Machine Code Master
27602 RE M** *** *** *** *** *** *** *** *** *** * 27605 PASS = 2 27610 0$ = "" 27620 EXIT = FALSE : ERR = FALSE 27625 F'TR = 2 27630 GOSUB 28850 27640 IF NOT ERR THEN 27720 27650 IF T=58 AND L EN<H$)= 0 THEN 27630 27660 IF T~59 OR T=-l THEN ERR = FALSE :
RETURN 27665 GOSUB 28700 27670 GOSUB 28850 27680 IF NOT ERR THEN 27720 27690 IF T=58 AND LEN(H$ >*0 THEN 27630 27695 IF T=59 OR T=-l THEN ERR » FALSE :
RETURN 27700 EN = 3 : GOTO 28000 27720 IF P O >55 THEN GOSUB 27200 s GOTO 2 7745 27723 T5 = F'TR : GOSUB 26100 : 78 * F'TR
: F'TR = T5 27725 GOSUB 26300 : IF NOT ERR THEN 2773 0 27727 IF 0P<7 AND O P >3 THEN OF' = 0F'+6 : PTR = T5 : GOTO 27725 27728 EN = 18 : GOTO 28000 27729 REM THIS BIT AT TEMPS TO MATCH ABSL OUTE ADD MODE TO OPCODE IF ZP HAS FAILED
27730 GOSUB 26560 27740 IF NOT ERR AND LEN (O# )>0 THEN GOSU B 27000 : PTR = 78 27745 IF LEN (IN$) >F'TR AND NOT EXIT THEN 27630 27750 RETURN
Having worked through Pass 1, we now turn our attention to Pass 2. As with Module 4.3, this is the control module of the Pass.and we shall follow through the Pass in outline before examining it in detail.
Commentary
27605-27700: Apart from setting the output string (OS) to empty and PASS equal to 2, these lines are similar to the first part of the Pass 1 module in
their effect. A test is made for an opcode, if this fails it is assumed that the
first part of the line is a label or variable. Following this another search is
82
Page 85
Chapter 4 Mastercode Assembler
made for an opcode and if the line is not setting a variable equal to something and there is no opcode present, error 3 invalid operand or
opcode is flagged.
27720: If the opcode type is greater than 55 then an assembler directive has been encountered and the relevant module is called up to evaluate it.
27723: The subroutine at 26100 is now called to evaluate the operand.
27725-27728: The subroutine at 26300 examines the match between the opcode and addressing mode so far obtained, then attempts to match them
in absolute mode, flagging error 18, addressing mode not available with
this opcode if the match is not correct. 27730: The byte counter AD is incremented by this call. 27740: If no error has been found and there is something in OS then the
operand part of the instruction is actually evaluated. T8 is a variable used
to move the pointer past an index such as .X at the end of the operand,
since the operand evaluator will not scan past these. T8 was set in line
27723, when returning from the routine which evaluates the operand type,
which scans to the very end of the operand, including any index attached. 27745: This line allows multiple statements on the same line to be evalu
ated.
CHECKSUM TABLE
27600
123 27601 107 27605 91 27625 27650 27670
27695
26
8 8
180 27680 69
38 2770 0
/27723 138
27728
1 1
/27740 46
MODULE 4.16
27610 169 27630 180 27660 38
27725 104
/27 7 2 9
27745 251
213
248
27602 123 27620
87 27640 69 27665 27690
27720
27727
27730
27750
174
8 8
~r
178 176 142
2720G) REM* *** *** ****** *** ****** *** ***** 27201 REM DIRE CTIVE OPERAND EVALUATOR
27202 REM* *** **** ******** *** ******** *** 27205 ERR = FALSE 27210 IF PO=60 THEN GOSUB 28600 : AD =RE SUL.T 27214 IF P0=62 THEN SY = TRUE
83
Page 86
Machine Code Master
27215 IF P0--61 THEN OPEN 2,4 : CMD 2 : P PINT " [.CD] ADD. DATA SOUR CE CODE LCD I
II
27220 IF P0=59 THEN EXIT = TRUE 27230 IF P0>58 THEN RETURN 27240 IF P0=5 6 THEN 27330 27250 REM DBY ?< WRD DIRECTIVES 27260 GOSUB 28600 27270 IF RESUL.T<0 OR RESU L T >65535 THEN E N = 2 t GOTO 28000 27280 IF P0=58 THEN RESULT = INT(RESULT/
256 ) + 2 5 6 * (RESULT -INT(RESU LT/256)*256)
27281 REM 2728 0 REVERS ES HI. 2< LO. BYTES
IF DI RE CT IVE IS DBY
27290 T 1 =T : GOSUB 27100 : AD = AD+2
27300 IF T 1=32 THEN GOSUB 28150
27310 IF T 1=46 THEN 27260
27320 RETU RN
27330 REM BYT DIRECTIVE
27340 GOSUB 28600
27350 IF RE SULT C0 OR RE S ULT >255 THEN EN
= 1 : GOTO 28000 27360 GOSUB 27140 : AD = AD+1 27370 IF T=32 THEN GOSUB 28150 27380 IF T=46 THEN 27340 27390 RETURN
In Pass 1 we examined a module which determined any actions necessary when an assembler directive was encountered and also the length of the directive if it was BYT, WRD or DBY. This module is similar except that it performs such actions as opening a channel to the printer for output, flags SY to print out the symbol table or places the data from a BYT, WRD or DBY directive into the output string,
o$.
Commentary
27210: If an ORG directive is encountered, its operand is evaluated and the byte counter AD set equal to the result.
27214: Entering SYM in the program flags SY to print the symbol table at the end of the listing of source code.
27215: Entering PRT in the program opens an output channel to the printer for the listing of source code, otherwise output is to the screen.
84
Page 87
Chapter 4 Mastercode Assembler
27220: END results in the pass finishing at this point. 27250-27320: The value of a two byte directive (DBY, WRD) is obtained
using the Expression Evaluator and the two bytes reversed if the directive is DBY. This is because the routine at 27100, which is now called, places the two bytes into the string 0$ in LO/HI order. AD is incremented by 2. Line 27300 scans past any leading spaces and the subroutine loops back to pick up another double byte if a full stop is encountered.
27340-27380: The same routine as above, but for the single byte directive BYT.
CHECKSUM TABLE
~J f-y
0 0
7* "J 7
05
X2 7 2 15
272 40 77 272 70
7'77>
90 30
2 0
273
273 50 67 273 80
123 27201 70 154
27210 27220 189
V 27250
176
27280 150 27300
142
27330 93 27340 173 27360 27390
74
27202 123
166 27214 41
27230
9 9 J
243 27260
27281
219 V 27310 o «=* '*;>
27370 170
31 52
142
173
MODULE 4.17
27000 REM *** ********* *** **** *** *** **** * 27001 REM EVALUATE OPER AND 27002 REM *** ********* *** **** *** *** **** * 27010 ERR = FALSE 27020 IF O P<2 THEN RETUR N 27030 IF 0P=3 THEN 27500 27040 IF QP= 2 THEN 27400 27050 GOSUB 28600 27060 IF ERR OR LEN( Ot) =0 THEN RETURN 27070 IF (R E SULT C 0 OR RE S U L T >255) AND OP <9 THEN EN = 1 : GOTO 28000 27080 IF R E SULT S0 OR RES U L T >65535 THEN E N= 2 : GOTO 28000
27090 IF OF'<9 THEN 27140
27100 T = INT(RESULT/256)
27110 RESULT = RESUL.T-T*256
27120 GOSUB 27140
27130 RESULT T
27140 0$ = O^ +CHRS (RESULT)
27150 RETURN
85
Page 88
Machine Code Master
This module evaluates an operand whose type has already been determined, placing the result in one or two byte form into 0$.
Commentary
27020: If OP is less than two then there will be no operand. 27030: If the OP is 3 then relative addressing mode is required and the
routine at 27500 is called up. 27040: If OP is two then the addressing mode is immediate and the routine
at 27400 is called up. 27050-27080: For all other values of OP, the Expression Evaluator is used
to obtain a result and this is tested against the requirements of the addressing mode for 1 or 2 bytes.
27090-27140: These are the two routines that place the result obtained through the Expression evaluator into byte form in 0$. Note that two byte numbers are placed into 0$ with the high byte second.
CHECKSUM TABLE
27000
27010 27040 27070
27100
27130
MODULE 4.18
123 70 18 14 117
37
27001 47
27020 164 27030
27050 173
27002
123
2 0
27060 98 27080 144 27090 27 27110 27140
248
1 2 1
27120 171
27150 142
27500 REM *** ********* ******************
27501 REM EVALU ATE RELAT IVE EXPRESSION
27502 RE M******* ******* *** **** *** **** **
27510 GOSUB 28600
27520 IF L EN (0$)=0 OR ERR THEN RETURN
27530 RESULT = RESULT-AD
27540 IF R ESULT C0 THEN RESULT = RESULT+2
56 27560 IF RESUL TS256 AND RE SULT>=0 THEN 2 7140
27570 EN = 10
27580 GOTO 28000
This module evaluates the operand of an instruction using relative
addressing, ie where a jump is specified from the current address up to 127
positions positively in the memory or 128 negatively.
86
Page 89
Chapter 4 Mastercode Assembler
Commentary
27530: Because we are talking about a relative address, a jump is specified first of all as being to an address and then the relative jump is calculated by subtracting the current address, recorded in AD.
27540: Negative jumps cannot be placed straight into the machine code program, they must be transformed into what is known as twos comple ment form, where any negative value has 256 added to it, so that it ends up as a positive number in the range 128-255. Thus jumps with a value above
128 are in fact negative jumps and their value can be obtained by subtrac
ting 256.
CHECKSUM TABLE
27500 12 27510 17: 27540 75
27501 178
27520 98
27560 32
27502 123
27530 224
27570 230
27580 16:
MODULE 4.19
27400 REM* *** *** *** *** *** *** *** *** *** ** 27401 REM EVALUATE IMMEDIATE EXPRESSION 27402 REM* *** *** *** *** *** *** *** *** *** ** 27410 T5 = PTR : GOSUB 26000 27420 IF ASC( H*><> 35 THEN 27480 27430 IF MID$(H*,2,1)=“ THEN 27450 27440 PTR = T5 27442 IF P T R >L E N(I N$) THEN 27446 27444 IF ASC(MID$ <IN *,PT R,1 ))<>35 THEN P TR = PTR+1 s GOTO 27442 27446 OP = 8 : GOSUB 27050 : OP = 2 27448 RETURN 27450 REM SINGLE CHR. EXPEC TED 27460 IF L EN (H $)< >3 THEN 27480 27470 0$ = 0:$+MID*<H:*,3,1 > i R ETURN 27480 EN = 12 27490 GOTO 28000
This module obtains the value of an operand for an instruction involving immediate addressing, ie where a register is loaded directly with a value in the range 0-255.
87
Page 90
Machine Code Master
Commentary
27410-27420: The operand is obtained in H$ by the use of the routine at
26000. If it does not begin with a then an error will be flagged. 27430: If the second character of the operand is a single quotation mark,
then the routine will expect a single character following quote, whose ASCII value will be the value of the operand. A second quote should not be used.
27442-27444: These two lines skip over any spaces in INS to the hash sign. 27446: Since immediate addressing always involves a single byte, the
routine at 27050 is used to evaluate the operand as if it were addressing mode 8 (indirect Y) and to place the byte into OS. This is simply a short-cut.
27460-27470: These two lines deal with single characters in quotes. If the length of H$ is not 3 then the format is invalid and an error is flagged. If H$
is three characters long then the middle character is taken as the one whose
ASCII value is to be the operand.
CHECKSUM TABLE
27400
27410 144
27440 113 27442
27446
27460 174
123
43
27401 229 27402 123
, 27420 230 27430
15 V 27444 27448 27470
142 27450
205
27480
"? 4 3
169 14
232
27490 163
MODULE 4.20
26900 REM *** ********* *** **** *** *** **** * 26901 REM DUMP SYMBOL TABLE TO SCREEN 26902 REM *** ********* *** **** *** *** **** * 26910 IF SEC 1 THEN 26975 26915 PRINT 26920 FOR X = 0 TO SE-1 26930 PRINT LE F T *( S T * (X ),6 ) TAB (10) ; 26940 H = ASC(MID$(S T * < X >,8 ))*256+ASC(MI DiMST'f-(X) ,7) ) 26950 GOSUB
11000 26960 PRINT H* 26970 NEXT X 26975 PRINT "CCD3 TOTAL NUMBER OF SYMBOL S
---
" SE
26980 RETURN
88
Page 91
Chapter 4 Mastercode Assembler
This module is not truly part of Pass 2: it simply outputs the symbol table at the end of Pass 2 if the SYM directive was present in the assembly language program.
CHECKSUM TABLE
26900 123 26910 27 26930 80 26960 37
26901 26915 153 26920 26940 26970
6
26902 123
64 26950 250
26975 248
115 159
26980 142
SECTION 4: The Expression Evaluator
Up to now we have had several references to the shadowy beast known as the Expression Evaluator, taking it on trust that there was such an animal and, more importantly, that it does the necessary job. It would, of course be quite possible to write an assembler which required all values to be
spelled out in either decimal or hexadecimal but a great deal of time and effort is saved if the user can enter variables, jump to a position six bytes after a particular label or calculate bytes by entering something like LDA
jfVAL/256. The Expression Evaluator makes all of this possible, as you
will discover when you move on to enter our machine code routines.
MODULE 4.21
28300 REM *** *** *** *** *** *** *** *** *** *** 28301 REM EVALUATE LABEL OR NUMBER 28302 REM* ****** *** *** *** *** *** *** *** ** 28320 GOSUB 28150 28325 IF T=40 AND LEN( H$)=0 THEN GO SUB 2 8150 28330 T 1 - LEN(H$> 28335 IF (T= l OR T=32 OR T=58 OR T=59 0 R T=41 OR T=46) AND T1 = 0 THEN RETURN
28340 IF T 1 =0 THEN 28390 28350 IF ASC<H*)<=57 THEN H = VAL(H$> : GOTO 28492 28360 GOSUB 28250 : REM FIND LABEL IN SY MBOL TABLE 28370 IF ERR THEN EN = 11 s H = 0 : GOTO
28000
28380 GOTO 28492
28390 REM HEX,OCTAL OR BINA RY NUM BERS EV ALUATE
89
Page 92
Machine Code Master
28400 T2 = T : GOSUB 28150 28410 IF L E N (H $)=0 THEN 28450 28420 IF T2=36 THEN 2847 0 28430 IF T2=37 THEN BASE = 2 : GOTO 2847 0 28440 IF T2=38 THEN BASE = 8 : GOTO 2847 0 28450 REM INVALID LABEL
28460 H = 0 : EN = 6 : GOTO 28000
28470 REM TEST IF VALID NUMBER
28475 GOSUB 11950 28480 BASE = 16 : REM DEFAULT BASE 28490
IF ERR THEN H = 0 :
EN = 7 : GOTO 28000 28492 PTR =
PTR - 1 :
GOSUB 28 15 0
: REM GE T NEXT OPER ATOR 28495
CHECKSUM TABLE
RETURN
28300
123
28301
48
28302 123
28320 173 28325 250 28330 247
'28335 198 28340 255
28350 206 28360 173 28370 99 28380 178 28390 28420 56 28450 54 28475 173 28492 213
This module is the core of the Expression Evaluator, its job being to extract the value of number or label, numbers being permitted in decimal, hexadecimal, octal (base 8) or binary (base 2) form. The subroutine returns a value in the variable H and the permissible range of values is integers from 0 to 65535.
Commentary
28320: the number or label is obtained in H$. 28325: If the first character encountered is an open bracket (, then the
routine is called again to obtain the actual number. 28835: On entering the routine at 28150, the variable T is set to minus one.
If it remains at that value then no characters of any significance have been found. The other values for T indicate that a space, colon, semi-colon,
140 28400
28430 28460 28480 28495
243 28410
155 28440 162 188 28470
221 28490 56
142
247
90
Page 93
Chapter 4 Mastercode Assembler
close bracket or full stop have been found. If any of these is combined with an H$ of length zero then there is no number or label in the instruction and the program returns from the subroutine.
28340: If none of the delimiters tested for in the previous line is present it is assumed that the number has a $ \ 9o or in front of it, indicating hexadecimal, octal or binary and execution goes to the routine which extracts a decimal number from these.
28350: If the first character is a digit then the VAL of H$ is taken varia bles must therefore not begin with a number, since the value of the number will be picked up and the rest of the variable name ignored.
28360-28380: If the first character is not a digit then what has been picked up is assumed to be a label and it is sent to the routine at 28250 in order to obtain its value.
28390-28490: The pointer represented by T has now passed a character which is assumed at this point to indicate a different number base. This assumption is now tested. If a different base is specified, the variable BASE is altered to take account of it and the routine in the Monitor which converts non-decimal numbers to decimal is called up. If the character indicated by T2 is not one of the base changing indicators then it is invalid and the label is not alphanumeric error is flagged. If a different base has been specified but the representation is incorrect (eg binary 101012) then an error incorrect number base will be flagged after the return from the routine at 11950.
28492: The main pointer, PTR, which is indicating the character after the end of the current operator, is now backed up one in order that the procedure may be re-executed on the rest of the line.
MODULE 4.22
28500 REM****************************** 28501 REM EVALUATE TERM WITH * OR / 28502 REM****************************** 28510 BOSUB 28300 : TERM = H 28520 IF PTR>LEN(IN*> THEN RETURN 28530 IF T=42 THEN GOSUB 28300 s TERM =
INT <TERM*H> s GOTO 28520
28550 IF T< >47 THEN RETURN 28560 GOSUB 28300 28570 IF H=0 THEN TERM - 0 : EN = 15 : G OTO 28000 28580 TERM = INT(TERM/H)
28590 GOTO 28520
91
Page 94
Machine Code Master
One of the problems of evaluating an expression is that of precedence, ie
which part of an expression such as A*B/C + D/E*F must be evaluated
first. The Expression Evaluator can deal with the precedence between + ,
and 7* but not with precedence forced by the use of brackets. Brackets would anyway make it more difficult to assess the operand type. This particular module deals with the two high precedence operations, multiply and divide.
Commentary
28510: A value is picked up using the previous module and stored in the variable TERM.
28530: If the character pointed to by T is a multiply sign then the next value
is immediately picked up and multiplied by TERM.
28550-28580: If the character indicated by T is a V, representing a division sign, then a test is made that the divisor is not zero if it is the division by
zero is flagged. TERM is now divided by the value just obtained in H.
CHECKSUM TABLE
28500 123 28510 150 28550 67 28580 93
MODULE 4.23
28501 20 28520 150 28560 170 28590 170
28502 123
28530 162
28570 152
28600 R E lvi * * * ¥. * -» # * * * *
28601 R E M E V A L U A T E E X P R E 8 S I 0 N
28602 R EL' M * * * * * *: * * * * * ¥.■ *: * *
28605 ERR == FALSE
28610 GO SUE* 2B500 : RESULT = TERM
28620 I F T -
.
1 OR T=32 OR T=58 OR T=59 OR 7
=41 OR T=46 OR PTR>LEN<IN$) THEN RETURN
28630 IF T 43 THEN GOSUB 28500.: RESULT = I N T(EES U L T + T ERM) : GOTO 28620 28640 IF T=45 THEN GOSUB 28500 : RESULT = INT(RESULT-TERM) : GOTO 28620
28650 RESULT = 0 :: EN = 4 : GOTO 28O00
READY
This module evaluates the lower precedence operations add and
subtract.
92
Page 95
Chapter 4 Mastercode Assembler
Commentary
28610: The module does not directly call the main module at 28300, but rather it calls the high precedence operator module. This ensures that before any values are returned they have been tested to see whether they should first have been divided or multiplied by something else. Thus if the expression being evaluated were A*B + C, A*B would be evaluated before the result was returned to this module.
28620: If one of the delineators is encountered after the operand then there is nothing more to evaluate.
28630-28640: If a plus or minus sign is indicated by T as following the value obtained so far then the appropriate calculation is made.
28650: If the character indicated by T is neither a plus nor a minus sign (multiply or divide would have been dealt with by the previous module) then the invalid operator error is flagged.
CHECKSUM TABLE
28600 123 28601 54 28602 123 28605 70 28610 47 28620 5 28630 226 28640 229 28650 81
Summary
Its finished! Or at least its entered. Whether you have the heart to go on
and develop the Mastercode program further depends on your own
stamina it is one of the largest single programs ever published in book
form for a popular micro. In the rest of the book we examine a series of
machine code routines which can be entered using the Assembler. If you
have other books on 6502 programming then you may find in them useful
subroutines which you can enter. It is not a bad idea to enter one or two
small routines before you go on to extending the 64*s BASIC with the rest
of this book, if only to familiarise yourself with the working of the
program. The usual word of caution applies, however: do make sure that
the program is saved before you try to do anything with machine code. Anyone can make a mistake and regret it if the program is lost.
93
Page 96
Page 97
Part 2
95
Page 98
Page 99
CHAPTER 5
The BASIC Extender
In order to achieve our aim of practical machine code routines to extend the BASIC language on the 64 it is first of all necessary to understand a little how BASIC actually works. How is a normal BASIC command
picked up and acted upon, let alone the commands we wish to add to the language.
Consider first a straightforward BASIC command such as a line reading
1 GOTO 10. When you press RETURN to enter the line, it is scanned by the
BASIC interpreter and the fact that it contains a BASIC keyword is detected. This keyword is then crunched, that is to say shrunk down to a
single byte in the program file. All the BASIC keywords have such bytes, or
tokens, with values in the range 128-202 (plus 255 for PI). In the case of GOTO the token is 137.
When the program containing this line is RUN the BASIC interpreter scans the line, skipping the line number and finds the token, which it recog nises as such since it is above 128 and not contained within quotes. The
token indicates a position in a table and at that position is the address of a
machine code routine which will execute the command you see as GOTO
10. The interpreter now executes this machine code routine which first scans the line following the GOTO token for a line number. Having obtained this from the BASIC line the rest of the machine code routine for
this particular command is devoted to finding the particular line number
referred to and altering a number of system variables so that program exe cution jumps to that point. If no line number is found alongside the GOTO
then a syntax error is indicated. If the line number is found but is not in the
program then an undefined line error is given. Assuming that everything has gone according to plan, control of the program now returns to that part of the BASIC interpreter whose job is to seek out the next token in the program.
From all this we learn that a number of actions are necessary for the
execution of a BASIC keyword:
1) The interpreter must recognise it as a keyword and be able to crunch it
down to the form of a token.
2) The interpreter must be able to recognise the token once the program is run.
3) There must be a table in the memory somewhere from which the inter
97
Page 100
Machine Code Master
preter can draw the start address of a machine code routine to perform the command.
4) The machine code routine may have to be able to pick up further infor mation for the command (eg the 10 for GOTO 10).
5) There must be provision to recognise and notify errors which prevent the execution of the routine.
Having RUN the program one more requirement is discovered when it is LISTed. It is no use trying to print out the token for the keyword. The interpreter must also have a table which allows it to look up the word which corresponds to the token so that it may be printed in a listing of the pro gram.
In order to enter new keywords we must take account of all these requirements. Our keywords must be placed into the interpreter, tokens must be specified for them, routines to execute them must be provided and, most important of all, the interpeter must be persuaded to recognise and act upon the information given. All this will clearly involve altering the BASIC interpreter and that itself presents the first problem since, as you no
doubt already know, the interpreter is not in a part of memory that we can
choose to alter (RAM) but rather in custom-built chips whose contents are
fixed at the time of their manufacture. All that is true but fortunately it is not the whole of the truth.
When you switch the 64 on its 64K of memory is taken up (roughly) by
8K of memory for what is known as the Kernal (a set of useful machine code routines common to most Commodore machines), 8K for the BASIC interpreter, IK for system variables (locations which the 64 uses to store important values and addresses for its operation), 4K of RAM which cannot be used by BASIC and 4K for running other devices such as the VIC chip, discs, tape, printers etc. However it is.possible to switch certain sections of this memory over to user control (RAM) in fact there is a complete 64K of RAM available, provided that you are willing to switch everything else in the machine off, meaning no BASIC, no communication with the outside world and so on.
The BASIC interpreter, appears to occupy the 8K of memory from
40960 onwards. In fact the 64 cheats by fooling the CPU into thinking that the entirely separate BASIC interpreter chip occupies that position. The
actual 8K of RAM at that point is totally unused for the simple reason the
6502/6510 chip can only see 64K of memory at one time, so that if it is to see the BASIC interpreter it must cease to see 8K of the actual user memory. The importance of this for our purposes is that there is 8K of memory going unused, exactly the right amount of space to hold the BASIC interpreter if it were to be held in RAM and not in ROM, and in exactly the place where the CPU would expect to find the BASIC interpreter.
Our first step in altering BASIC, therefore, is to copy the contents of the
BASIC interpreter into that area of RAM. This has its drawbacks the
98
Loading...