You are on page 1of 314

Written by James Farvour

Microsoft BASIC Decoded & Other Mysteries


Foreword by Harvard Pennington

Edited by Jim Perry


Graphics by John Teal Cover by Harvard Pennington

TRS-80 Information Series Volume 2

Contents
Foreword ............................................................................. 4 Chapter 1: Introduction ....................................................... 5 Overview ......................................................................... 6 Memory Utilization ......................................................... 6 Communications Region ................................................. 8 Level II Operation ........................................................... 8 Input Phase ...................................................................... 8 Interpretation & Execution .............................................. 9 Verb Action ................................................................... 11 Arithmetic & Math ........................................................ 11 I/O Drivers..................................................................... 12 System Utilities ............................................................. 13 IPL................................................................................. 13 Reset Processing (non disk)........................................... 13 Reset Processing (disk) ................................................. 14 Disk BASIC................................................................... 14 Chapter 2: Subroutines ...................................................... 15 I/O Calling Sequences ................................................... 15 Keyboard Input.............................................................. 15 Scan Keyboard .......................................................... 15 Wait For Keyboard.................................................... 16 Wait For Line ............................................................ 16 Video Output ................................................................. 16 Video Display............................................................ 16 Clear Screen .............................................................. 17 Blink Asterisk............................................................ 17 Printer Output................................................................ 17 Print Character........................................................... 17 Get Printer Status ...................................................... 17 Cassette I/O ................................................................... 18 Select & Turn On Motor ........................................... 18 Write Leader.............................................................. 18 Read Leader............................................................... 18 Read One Byte .......................................................... 18 Write One Byte.......................................................... 18 Conversion Routines ..................................................... 19 Data Type Conversions ................................................. 19 FP To Integer............................................................. 19 Integer To SP............................................................. 19 Integer to DP ............................................................. 19 ASCII to Numeric ......................................................... 19 ASCII To Integer....................................................... 19 ASCII To Binary ....................................................... 19 ASCII To DP............................................................. 20 Binary To ASCII ........................................................... 20 HL To ASCII & Display ........................................... 20 Integer To ASCII....................................................... 20 FP To ASCII.............................................................. 20 Arithmetic Routines ...................................................... 21 Integer Routines ............................................................ 21 Integer Addition ........................................................ 21 Integer Subtraction .................................................... 21 Integer Multiplication................................................ 21 Integer Division......................................................... 21 Integer Comparison ................................................... 21 Single Precision Routines.............................................. 21 SP Addition ............................................................... 22 SP Subtraction ........................................................... 22 SP Multiply ............................................................... 22 SP Divide .................................................................. 22 SP Comparison.......................................................... 22 Double Precision Routines ............................................ 22 DP Addition............................................................... 22 DP Subtraction .......................................................... 23 DP Multiply............................................................... 23 DP Divide.................................................................. 23 DP Comparison ......................................................... 23 Math Routines ............................................................... 23 Absolute Value.......................................................... 23 Return Integer............................................................ 23 Arctangent ................................................................. 24 Cosine........................................................................ 24 Raise Natural Base .................................................... 24 Raise X To Power Of Y ............................................ 24 Natural Log ............................................................... 25 FP To Integer............................................................. 25 Reseed Random Number........................................... 25 Random Number ....................................................... 25 Sine............................................................................ 25 Square Root ............................................................... 25 Tangent...................................................................... 26 Function Derivation....................................................... 26 System Functions .......................................................... 27 Compare Symbol....................................................... 27 Examine Next Symbol............................................... 27 Compare DE:HL ....................................................... 27 Test Data Mode ......................................................... 27 DOS Function Call .................................................... 28 Load DEBUG............................................................ 28 Interrupt Entry Point.................................................. 28 SP In BC:DE To WRA1............................................ 28 SP Pointed To By HL To WRA1 .............................. 28 SP Into BC:DE .......................................................... 29 SP From WRA1 Into BC:DE .................................... 29 WRA1 To Stack ........................................................ 29 General Purpose Move .............................................. 29 Variable Move........................................................... 29 String Move............................................................... 30 BASIC Functions .......................................................... 30 Search For Line Number ........................................... 30 Find Address Of Variable.......................................... 30 GOSUB ..................................................................... 31 TRON........................................................................ 31 TROFF ...................................................................... 31 RETURN................................................................... 31 Write Message........................................................... 31 Amount Of Free Memory.......................................... 31 Print Message ............................................................ 32 Number Representation............................................. 32 Chapter 3: Cassette & Disk ............................................... 33

Microsoft BASIC Decoded & Other Mysteries

Cassette I/O....................................................................33 Cassette Format .............................................................34 SYSTEM Format ...........................................................34 Disk I/O .........................................................................35 Disk Controller Commands ...........................................35 Disk Programming Details.............................................37 DOS Exits ......................................................................37 Disk BASIC Exits..........................................................38 Disk Tables ....................................................................38 Disk Track Format .........................................................39 Granule Allocation Table...............................................39 Hash Index Table...........................................................39 Disk DCB ......................................................................40 Disk Directory ...............................................................41 Chapter 4: Addresses & Tables .........................................42 System Memory Map.....................................................42 Internal Tables ...............................................................42 Reserved Word List .......................................................42 Precedence Operator Values ..........................................43 Arithmetic Routines.......................................................43 Data Conversion Routines .............................................43 Verb Action Routines ....................................................43 Error Code Table ...........................................................44 External Tables ..............................................................44 Mode Table....................................................................44 Program Statement Table...............................................44 Variable List Table ........................................................45 Literal String Pool Table ...............................................46 Communications Region................................................46 DCB Descriptions ..........................................................48 Video DCB ................................................................48 Keyboard DCB ..........................................................48 Printer DCB ...............................................................48 Interrupt Vectors............................................................48 Memory Mapped I/O .....................................................49 Stack Frame Configurations ..........................................49 FOR Stack..................................................................49 GOSUB Stack............................................................50 Expression Evaluation ...............................................50 DOS Request Codes.......................................................51 Chapter 5: Example 1 ........................................................52 A BASIC SORT Verb ...................................................52 Chapter 6: Example 2 ........................................................55 BASIC Overlay Program ...............................................55 Chapter 7: BASIC Decoded.............................................. 58 the new ROMs .............................................................. 58 Chapter 8: BASIC Decoded.............................................. 61 Comments Disassembled ROMs................................... 63

Acknowledgments
This book has been a long time in its creation, without the help, advice and support of many people it would not have been possible. In particular thanks are due to Rosemary Montoya for her days of keyboarding, David Moore for hours of example testing, Jerry De Diemar, Mary and MG at Helens place for turning the Electric Pencil files into type and Al Krug for his 24 hour message service. This book was produced with the aid of several TRS-80 computer systems, an NEC Spinterm printer, the Electric Pencil word processor with a special communications package to interface to an Itek Quadritek typesetter, plus lots of coffee and cigarettes. Copyright 1981 James Farvour Microsoft BASIC Decoded & Other Mysteries ISBN 0 - 936200 - 0l - 4 The small print
All rights reserved. No Part of this book may be reproduced by any means without the express written permission of the publisher. Example programs are for personal use only. Every reasonable effort has been made to ensure accuracy throughout this book, but the author and publisher can assume no responsibility for any errors or omissions. No liability is assumed for damages resulting from the use of information contained herein.

First Edition First Printing January 1981


Published by

IJG Computer Services


1260 W Foothill Blvd, Upland, CA 91786 USA

Microsoft is a registered trademark of the Microsoft Corporation. Radio Shack and TRS-80 are trademarks of the Tandy Corp. NEWDOS and NEWDOS + are trademarks of Apparat Inc. BASIC is a trademark of the Trustees of Dartmouth College.

Foreword
A little over a year ago, I said to Jim Farvour, 'Jim, why don't you write a book about Microsoft BASIC and the TRS-80? You have the talent and the expertise and thousands of TRS-80 owners need help, especially me!'. Needless to say, he agreed. Now it's one thing to SAY you are going to write a book and quite another thing to actually do it. Writing a book requires fantastic discipline, thorough knowledge of the subject matter, talent and the ability to communicate with the reader. Jim Farvour has all of the above. This is no ordinary book. It is the most complete, clear, detailed explanation and documentation you will see on this or any similar subject. There have been other books and pamphlets purporting to explain the TRS-80 BASIC interpreter and operating system. They have had some value, but only to experienced machine language programmers - and even then these books had many short-comings. This book will delight both professional and beginner. Besides walking you through power-up and reset (with and without disk) there are detailed explanations of every single area of the software system's operation. Examples, tables, and flow-charts complement the most extensively commented listing you have ever seen. There are over 7000 comments to Microsoft's BASIC interpreter and operating system. These are not the usual machine language programmer's comments whose cryptic and obscure meanings leave more questions than answers. These are English comments that anyone can understand. Not only that, but when a comment needs more explanation, you will find it on the next page. This book even has something for anyone running Microsoft BASIC on a Z-80 based computer. Microsoft, in its great wisdom, has a system that generates similar code for similar machines. Although you may find that the code is organized differently in your Heath or Sorceror the routines are, for the most part, identical! Is this a great book? It's an incredible book! It may well be the most useful book you will ever own. H.C. Pennington November 1980

Chapter 1

Introduction
Level II consists of a rudimentary operating system and a BASIC language interpreter. Taken together, they are called the Level II ROM System. There is a extension to the Level II system called the Disk Operating System DOS, and also an extension to the BASIC portion of Level II called Disk BASIC. Both Level II and DOS are considered independent operating systems. How the two systems co-exist and cooperate is a partial subject of this book. The real purpose is to describe the fundamental operations of a Level II ROM so that assembly language programmers can make effective use of the system. A computer without an operating system is of little use. The reason we need an operating system is to provide a means of communication between the computer and the user. This means getting it to 'listen' to the keyboard so that it will know what we want, and having it tell us what's going on by putting messages on the video. When we write programs, which tell the computer what to do, there has to be a program inside the machine that's listening to us. This program is called an operating system. It is impossible to give an exact definition of an operating system. There are thousands of them, and each has slight variations that distinguish it from others. These variations are the result of providing specific user features or making use of hardware features unique to the machine that the operating system is designed for. In spite of the differences between operating systems, the fundamental internal routines on most are very similar at least from a functional point of view. The common components in a general purpose, single user system, such as Level II would consist of:
1. Drivers (programs) for all peripheral devices such as the keyboard, video, printer, and cassette. 2. A language processor capability (such as BASIC, COBOL, or FORTRAN) of some kind. 3. Supporting object time routines for any language provided. This would include math and arithmetic routines, which are implied by the presence of a language. 4. Ancillary support routines used by the language processor and its implied routines. These are usually invisible to the user. They manage resources such as memory and tables, and control access to peripheral devices. 5. A simple monitoring program that continually monitors the keyboard, or other system input device, looking for user input. 6. System utility commands. These vary considerably from system to system. Examples from Level II would be: EDIT, LIST, CLOAD, etc.

Remember that these definitions are very general. The exact definition of any individual component is specific to each operating system. In the case of the Level II ROMs we'll be exploring each of the components in more detail later on. First we will discuss how the operating system gets into the machine to begin with. Generally, there are two ways an operating system can be loaded. The operating system can be permanently recorded in a special type of memory called Read Only Memory (ROM) supplied with the system. In this case the operating system is always present and needs only to be entered at its starting point, to initialize the system and begin accepting commands.

Level II And DOS Overview


Level II is a stand alone operating system that can run by itself. It is always present, and contains the BASIC interpreter plus support routines necessary to execute BASIC programs. It also has the facility to load programs from cassette, or save them onto a cassette. A Disk Operating System, (such as TRSDOS or NEWDOS) is an extension to Level II that is loaded from disk during the IPL sequence. It differs from Level II in several ways. First, it has no BASIC interpreter, in order to key-in BASIC statements control must be passed from DOS to Level II. This is done by typing the DOS command BASIC. As well as transferring control from DOS to Level II this command also performs important initialization operations which will be discussed later. Second, the commands recognized by DOS are usually disk utility programs not embedded routines - such as those in Level II. This means they must be loaded from disk before they can be used. In turn this means that there must be an area of RAM reserved for the loading and execution of these utilities.

Another way of getting the operating system into the machine is to read it in from some external storage medium such as a disk or cassette. In this case, however, we need a program to read the operating system into the machine. This program is called an Initial Program Loader (or IPL), and must be entered by hand or exist in ROM somewhere on the system. For the sake of simplicity, we'll assume that all machines have at least an IPL ROM or ROM based operating system. In the TRS-80 Model I we have a combination of both ROM and disk based operating systems. A Level II machine has a ROM system which occupies the first 12K of addressable memory. When the Power On or Reset button is pressed control is unconditionally passed to location 0 or 66 respectively. Stored at these locations are JUMPS to another region of ROM which initializes the system and then prints the user prompt 'MEMORY SIZE?'. In a Level II system with disks, the same ROM program still occupies the first 12K of memory, however during Power On or Reset processing another operating system is read from disk and loaded into memory. This Disk Operating System (DOS) occupies 5K of RAM starting at 16K. After being loaded control is then transferred to DOS which initializes itself and displays the prompt 'DOS READY'. So, even though a ROM operating system is always present, if the machine has disks another operating system is loaded also. In this case, the Level II ROM acts as an IPL ROM. It should be emphasized that the DOS and ROM operating systems are complementary and co-operative. Each provides specific features that the other lacks. Elementary functions required by DOS are found in ROM, and DOS contains extensions to the ROM, as well as unique capabilities of its own.

Memory Utilization
From the description of DOS and Level II we can see that portions of RAM will be used differently depending on which operating system is being used. Immediately after IPL the memory is setup for each of the operating systems as shown in figure 1.1 below. Notice the position of the Central Processing Unit (CPU) in each part of the figure.
Level II ( no disk ) 0K --> CPU Level II Here ---> ROM 12K --> --------------Communications Region 16k --> --------------ROM Addresses -----------RAM Addresses 19k --> Free Space List end of memory Figure 1 21k --> Level II ( with disk } Level II ROM ---------------Communications Region ---------------Dos Nucleus <-- CPU ---------------Here Overlay Area ---------------Free Space List

Figure 1.1: Memory organization after the Initial Program Load.

A Level II system with disks that has had a BASIC command executed would appear as in figure 1.2. The first 16K of memory is dedicated to Level II and the Communications Region regardless of the operating system being used.

Starting at the end of the Communications Region or the Disk BASIC area, depending on the system being used, is the part of memory that will be used by Level II for storing a BASIC program and its variables. This part of memory can also be used by the programmer for keeping assembly language programs. A detailed description of this area for a Level II system without disks follows.

The Program Statement Table (PST) contains source statements for a BASIC program in a compressed format (reserved words have been replaced with tokens representing their meaning). The starting address for this table is fixed, but its ending address varies with the size of the program. As program statements are added or deleted, the end of the PST moves accordingly. A complete description of this table can be found in chapter 4 (page 44). Following the PST is the Variable List Table (or VLT). This contains the names and values for all of the variables used in a BASIC program. It is partitioned into four subtables according to the following variable types: simple variables (non dimensioned); single dimensioned lists; doubly dimensioned lists and triple dimensioned lists. Variable names and their values are stored as they are encountered during the execution of a program. The variable table will change in size as new variables are added to a program, and removing variables will cause the table to shrink. After a variable is defined it remains in the table, until the system is reinitialized. For a full description of this table see chapter 4 (page 45). Not shown in figure 1.3 is the Free Space List or FSL. It is a section of memory that initially extends from the end of the Communications Region to the lower boundary of the String Area. There are two parts to this list, the first is used to assign space for the PST and VLT. For these areas space is assigned from low to high memory. The second part of the FSL is used as the Stack area. This space is assigned in the opposite direction - beginning at the top of the String Area and working down towards Level II. The stack area shown is a dynamic (changeable) table. It is used by the Level II and DOS systems as a temporary storage area for subroutine return addresses and the hardware registers. Any CALL or RST instruction will unconditionally cause the address of the following instruction to be saved (PUSH'd) onto the stack, and the stack pointer is automatically decremented to the next lower sequential address. Execution of a RET instruction (used when exiting from a subroutine) removes two bytes from the stack (the equivalent of a POP instruction) and reduces the stack pointer by two. Storage space in the stack area can be allocated by a program, but it requires careful planning. Some BASIC subroutines such as the FOR-NEXT routine, save all values related to their operation on the stack. In the FOR NEXT case an eighteen byte block (called a frame) is PUSH'd onto the stack and left there until the FOR-NEXT loop is completed. Before space is assigned in either part of the FSL (except for Stack instructions such as CALL or PUSH) a test is made (via a ROM call) to insure there is enough room. If there is insufficient space an Out of Memory error is given (OM). See chapter 2 (page 31) for a description of the ROM calls used to return the amount of space available in the FSL.

0K --> 12K --> 16k --> 19k --> 19k --> 19k --> end of memory --> Level II ROM ---------------Communications Region ---------------DOS Nucleus ---------------Overlay Area ---------------Disk BASIC ---------------Free Space List

Figure 1.2: Memory allocation for a system with disks, after a BASIC command.

Although figure 1.3 shows the sub-divisions of RAM as fixed they are not! All of the areas may be moved up or down depending on what actions you perform. Inserting or deleting a line from a program, for example, causes the BASIC Program Table (called the Program Statement Table or PST) to increase or decrease in size. Likewise defining a new variable would increase the length of the variables list. Since the origin of these tables may shift, their addresses are kept in fixed locations in the Communications Region. This allows the tables to be moved about as required, and provides a mechanism for letting other users know where they are.

16K -->

Level II and Comm. Region --------------BASIC Program Table --------------BASIC Program Variables ---------------

--------------Stack --------------String Area

Figure 1.3: Allocation of memory in a Level II system without disks.

The last area shown in the memory profile is the string area. This is a fixed length table that starts at the end of memory and works toward low memory. The size of this area may be specified by the CLEAR command. Its default size is 50 bytes. String variables are stored in this area, however strings made equal to strings, String$ and quoted strings are stored in the PST. Earlier it was mentioned that there are six general components that form an operating system. Because of the way Level II was put together the individual pieces for some components are scattered around in ROM, instead of being collected together in a single area. Figure 1.4 is an approximate memory map of addresses in Level II. For exact addresses and description of these regions see chapter 4.
Level II ROM Decimal Address 0000 --> 1800 --> 5600 --> 6700 --> 7100 --> 11000 --> 12000 -->

addresses are changed to addresses within Disk BASIC which allows changes to be made to the way Level II operates. The Disk BASIC addresses are used by Level II when a Disk BASIC command such as GET or PUT is encountered. They are needed because the code that supports those operations is not present in Level II. It is a part of Disk BASIC that is loaded into RAM, and since it could be loaded anywhere Level II needs some way of locating it. The Disk BASIC exits are a group of fixed addresses, known to both Level II and Disk BASIC, which allows Level II to pass control to Disk BASIC for certain verb action routines. Another interesting aspect of the Communications Region is that it contains a section of code called the Divide Support Routine. This code is called by the division subroutines, to perform subtraction and test operations. It is copied from Level II to the RAM Communications Region during the IPL sequence. When a DOS is present it is moved from ROM to RAM by the DOS utility program BASIC. An assembly language program using the Level II division routine on a disk system which has not had the BASIC command executed will not work because the Divide Support Routine is not in memory. Either execute the BASIC utility or copy the support routine to RAM, when executing assembly language routines that make division calls.

Peripheral Drivers --------------Math and Arithmetic --------------Support --------------Monitoring --------------BASIC Interpreter --------------Utilities

Figure 1.4: Approximate memory map of Level II addresses

The Communications Region


The Communications Region is a scratch pad memory for the Level II ROMs. An example of addresses stored here are those for the PST and the variables list. Also BASIC supports variable types that require more space than the working registers can provide, and as a result certain arithmetic operations require temporary storage in this region. Another important use of the Communications Region is to provide a link between Level II and DOS - for passing addresses, and data, back and forth. The DOS Exit addresses and Disk BASIC addresses are kept in this area. As mentioned earlier a Level II system, with disks, begins execution in the DOS system. Control is passed from DOS to Level II only after the command BASIC has been executed (which also updates the Communications Region by storing the DOS Exits and Disk BASIC addresses). Because Level II is in ROM it is impractical to try and modify it. Yet, changes to an operating system are a practical necessity that must be considered. In order to solve this problem the Level II system was written with jumps to an area in RAM, so that future changes could be incorporated into the ROM system. Those jumps are called DOS Exits, and on a system without a DOS they simply return to Level II. When a DOS is present, the jump

Level II Operation
Earlier in this chapter there was a brief description of six components which are generally found in all operating systems. Using those components as a guideline, Level II can be divided into the following six parts:
Part 1 ... Input or scanner routine. Part 2 ... Interpretation and execution routine. Part 3 ... Verb action routines Part 4 ... Arithmetic and math routines Part 5 ... I/O driver routines. Part 6 ... System function routines.

There is another part common to all systems which is not included in the above list. This part deals with system initialization (IPL or Reset processing), and it will be discussed separately. Continuing with the six parts of Level II, we will begin at the point where the system is ready to accept the first statement or command. This is called the Input Phase.

Part 1 - Input Phase


The Input Phase is a common part of all operating systems. Its function is to accept keyboard input and respond to the commands received. In the case of a Level II system it serves a dual purpose - both system commands and BASIC program statements are processed by this code.

Entry to the Input Scan routine is at. This is an initial entry point that is usually only called once. The message 'READY' is printed, and a DOS Exit (41AC) is taken before the main loop is entered. Systems without disks jump to this point automatically, at the end of IPL processing. For systems with disks, this code is entered by the DOS utility program BASIC at the end of its processing. The Input or Scanner phase is summarized below.
1. Get next line of input from keyboard. 2. Replace reserved words with tokens. 3. Test for a system command such as RUN, CLOAD, etc. or a DIRECT STATEMENT (BASIC statement without a line number) and branch to 6 if true. 4. Store tokenized statement in program statement table. 5. Return to step 1. 6. Begin interpretation and execution

Program execution by interpretation is not common except on microcomputers, and even then only for selected languages such as BASIC and APL. The alternative to an interpreter is program compilation and execution, with the use of a compiler. Compilers translate source statements into directly executable machine language code (called object code). The object code is then loaded into RAM as a separate step using a utility program called a Loader. After loading the object code into RAM, control is passed to it and it executes almost independently of the operating system. Not all source code is converted to object code by a compiler. Some statements such as READ and WRITE or functions such as SINE or COSINE may be recognized by the compiler, and rather than generate code for them, subroutine calls for the specific routines will be produced. These routines are in object code form in a library file. When the loader loads the object code, for the compiled program, any subroutine calls are satisfied (the subroutines are loaded) from the library file. A loader that will take modules from a library is called a linking loader. An interpreter operation is much simpler by comparison. Each source statement is scanned for reserved words such as FOR, IF, GOTO, etc.. Every reserved word is replaced by a unique numeric value called a token then the tokenized source statement is saved. In Level II it is saved in the Program Statement Table. When the program is run control goes to an execution driver which scans each statement looking for a token. When one is found control is given to a routine associated with that token. These token routines (also called verb action routines) perform syntax checks such as testing for valid data types, commas in the correct place, and closing parenthesis. In a compiler entered action routine there is no syntax checking because that would have been done by the compiler - and the routine would only be called if all of the parameters were correct.

The Input Phase loop begins at 1A33. After printing the prompt >, or a line number if in the Auto Mode a CALL to 03612 is made to read the next line. Then the line number is converted from ASCII to binary with a CALL to 1E5A. The statement is scanned and reserved words are replaced by tokens (CALL 1BC0). Immediately after tokenization a DOS Exit to 41B2 is taken. Upon return a test for a line number is made. If none is found a System Command or Direct Statement is assumed, and control is passed to the Execution Driver at 1D5A. On systems without disks this test is made at 1AA4. On a disk system the test, and branch, is made at the DOS Exit 41B2 called from 1AA1. If a line number is present the incoming line is added to the PST, the pointers linking each line are updated by the subroutine at 1AFC to 1B0E. If the line replaces an existing line, the subroutine at 2BE4 is called to move all of the following lines down over the line being replaced. When in the Auto Mode the current line number is kept in 40E2 and 40E3 the increment between lines is stored at 40E4. The code from 1A3F to 1A73 prints and maintains the automatic line number value. Null lines (statements consisting of a line number only) are discarded. They are detected by a test at 1ABF.

Part 2 - Interpretation & Execution


Statement and command execution in a Level II system is by interpretation. This means that a routine dedicated to the statement type, or command, is called to interpret each line and perform the necessary operations. This is a common method for system command execution. With DOS, for example, separate modules are loaded for commands such as FORMAT and COPY. In some Systems, commands which are related may be combined into a single module, after the module has been loaded it decides which subfunction to execute by examining (interpreting) the name which called it.

In Level II the execution phase is entered when a statement without a line number has been accepted, or when a RUN command is given. This may be a system command or a single BASIC statement that is to be executed. When a RUN command is received an entire BASIC program is to be executed. The Execution driver loop starts at 1D5A and ends at 1DE1. These addresses are deceptive though, because portions of this code are shared with other routines. The steps in this phase are summarized as follows. For more details see figure 1.5.
1. Get the first character from the current line in the PST. If the end of the PST has been reached then return to the Input Phase. 2. If the character is not a token. go to step 6. 3. If the token is greater than BC it must be exactly FA (MID$), otherwise a syntax error is given. 4. If the token is less than BC. use it as an index into the verb action table. 5. Go to action routine and return to step 1. 6. Assignment section. Locate variable name, if it's not defined, then create it. 7. Call expression evaluation. 8. Return to step 1.

directly rather than through a table look-up process. Before it is entered a return address of 1D1E in the execution driver is PUSH'd onto the stack, so it can exit as any other action routine. The assignment routine assumes that the pointer for the current line is immediately to the left of the variable name to be assigned. It locates, or creates an entry for the variable name, tests for an equals () after the name - and then CALLs 2337. The routine at this location evaluates the expression. The result is converted to the correct mode, and stored at the variable address. Assuming that a good token was found as the first character, a second test is made to see if it is valid as the first token in a line. Valid tokens which can occur at the start of a line are 80 - BB. The tokens BC - F9 can only occur as part of an assignment statement or in a particular sequence such as 8F (IF) 'Expression' CA (then) XXXX. The MID$ token FA is the only exception to this rule. There is a test for it at 2AE7 where a direct jump to its Disk BASIC vector (41D9) is taken. If the token is between 80 and BB it is used as an index into a verb action routine table and the address of the action routine, for that token is located. Control is then passed to that action routine which will do all syntax checking and perform the required function. Parameters for the verb routines are the symbols in the statement following the token. Each routine knows what legitimate characters to expect, and scans the input string from left to right (starting just after the token) until the end of the parameters are reached. The end of the parameters must coincide with the end of the statement, or a syntax error is produced. Symbols which terminate a parameter list vary for each action routine. Left parentheses ')' terminate all math and string functions. A byte of machine zeros (00) stops assignment statements, other routines may return to the execution phase after verifying the presence of the required value. As each verb routine is completed control is returned to the Execution driver, where a test for end of statement (EOS) or a compound statement (:) is made. The EOS is one byte of machine zeros. If EOS is detected the next line from the Program Statement Table is fetched, and it becomes the current input line to the Execution driver.

Figure 1.5: Flowchart of the execution driver routine.

The Execution driver begins by loading the first character from the current line in the PST. This character is tested to see if it is a token (80-FA) if not, the current line is assumed to be an assignment statement such as: A = 1. The assignment statement routine begins at 1F21. It is similar to the other action routines, except that it is entered

When a System Command or a Direct Statement has been executed there is no pointer to the next statement, because they would have been executed from the Input Phase's input buffer. This is in a different area than the PST where BASIC program statements are stored. When the RUN command is executed, it makes the Execution driver get its input from the PST. When the end of a BASIC program, or a system command, is reached, control is unconditionally passed to the END verb which will eventually return to the Input Phase. Any

10

errors detected during the Execution and Interpretation phase cause control to be returned to the Input Phase after printing an appropriate error code. An exception is the syntax error, which exits directly to the edit mode.

Register

Contents

AF - Next element from code string following token. CARRY - if numeric No CARRY - if alpha BC - Address of the action routine DE - Address of action token in code string HL - Address of next element in code string

Part 3 - Verb Action


The verb action routines are where the real work gets done. There are action routines for all of the system commands such as CLOAD, SYSTEM, CLEAR, AUTO as well as the BASIC verbs such as FOR, IF, THEN, GOTO, etc. In addition there are action routines for all the math functions and the Editor sub-commands. Verb action routines continue analyzing the input string beginning at the point where the Execution phase found the verb token. Like the Execution phase, they examine the string in a left to right order looking for special characters such as (,,), or commas and tokens unique to the verb being executed. If a required character is missing, or if an illogical condition arises, a syntax error is generated. The verb routines use a number of internal subroutines to assist them while executing program statements. These internal routines may be thought of as part of the verb action routines, even though they are used by many other parts of the Level II system. A good example of an internal routine is the expression evaluation routine, which starts at 2337. Any verb routine that will allow, and has detected, an expression as one of its arguments may CALL this routine. Examples of verb action routines that allow expressions in their arguments are IF, FOR, and PRINT. In turn the expression evaluation routine will CALL other internal routines (such as 260D to find the addresses of variables in expressions being evaluated). Since subscripted variables can have expressions as their subscript, the find address routine may in turn CALL back to the expression evaluation routine! This type of processing is called recursion, and may be forced by the following expression: c0 = c(1a/bc(2d)/c(1*c0)) Other internal routines used by the verb action routines are : skip to end of statement 1F05; search Stack for a FOR frame 1936 and build a literal string pool entry 2865. Any intermediate results, which may need to be carried forward, are stored Work Register Area 1 (WRA1) in the Communications Region. Some verbs such as FOR build a stack frame which can be searched for and recognized by another verb such as NEXT. All of the action routines except MID$ are entered with the registers set as shown in figure 1.6. A full list of verb action routines, and their entry points is given in chapter 4 (page 43).

Figure 1.6: Register settings for verb action routine entry.

Part 4 - Arithmetic & Math


Before going into the Arithmetic and Math routines we should review the arithmetic capabilities of the Z-80 CPU and the BASIC interpreter. The Z-80 supports 8 bit and 16 bit integer addition and subtraction. It does not support multiplication or division, nor does it support floating point operations. Its register set consists of seven pairs of 16 bit registers. All arithmetic operations must take place between these registers. Memory to register operations are not permitted. Also operations between registers are extremely restricted, especially with 16 bit quantities. The BASIC interpreter supports all operations e.g., addition, subtraction, multiplication, and division for three types (Modes) of variables which are: integer, single precision and double precision. This support is provided by internal subroutines which do the equivalent of a hardware operation. Because of the complexity of the software, mixed mode operations, such as integer and single precision are not supported. Any attempt to mix variable types will give unpredictable results. The sizes for the variable types supported by BASIC are as follows:
Integer. 16 bits (15 bits 1 sign bit) Single Precision .... 32 bits (8 bit biased exponent plus 24 bit signed mantissa) Double Precision . 56 bits (8 bit biased exponent plus 48 bit signed mantissa)

11

From this it is clear that the registers are not large enough to hold two single or double precision values, even if floating point operations were supported by the hardware. Because the numbers may be too big for the registers, and because of the sub-steps the software must go through an area of RAM must be used to support these operations Within the Communications Region two areas have been set aside to support these operations. These areas are labeled: Working Register Area 1 (WRAl) and Working Register Area 2 (WRA2). They occupy locations 411D to 4124 and 4127 to 412E respectively. They are used to hold one or two of the operands, depending on their type, and the final results for all single and double precision operations. A description of the Working Register Area follows.
Address 411D 411E 411F 4120 4121 4122 4123 4124 LSB MSB LSB NMSB MSB Exponent Integer Single Precision Double Precision LSB NMSB NMSB NMSB NMSB NMSB MSB Exponent

Because mixed mode operations are not supported integer operations can only take place between integers, the same being true for single and double precision values. Since there are four arithmetic operations ( +, -, *, and / ), and three types of values, there must be twelve arithmetic routines. Each of these routines knows what type of values it can operate on, and expects those values to be loaded into the appropriate hardware or working registers before being called. Figure 1.8 shows the register assignments used by the arithmetic routines. These assignments are not valid for the Math routines because they operate on a single value, which is always assumed to be in WRA1. The math routines have a problem in that they must perform arithmetic operations, but they do not know the data type of the argument they were given. To overcome this another byte in the Communications Region has been reserved to indicate the data type (Mode) of the variable in WRA1. This location is called the Type flag. Its address is 40AF and contains a code indicating the data type of the current contents of WRAl. Its codes are:
CODE 02 03 04 08 ............ ............ ............ ............ DATA TYPE (MODE) Integer String Single precision Double precision

Where: LSB = Least significant byte NMSB = Next most significant byte MSB = Most significant byte WRA2 has an identical format. Figure 1.7: Working Register Area layout.

The math routines do not usually require that an argument be a particular data type, but there are some exceptions (see chapter 2, page xx, for details).

Part 5 - I/O Drivers


Drivers provide the elementary functional capabilities necessary to operate a specific device. Level II ROM contains Input/Output (I/O) drivers for the keyboard, video, parallel printer, and the cassette. The disk drivers are part of the DOS system and consequently will not be discussed. All devices supported by Level II, with the exception of the cassette, require a Device Control Block (DCB). The drivers use the DCB's to keep track of perishable information, such as the cursor position on the video and the line count on the printer. The DCB's for the video, keyboard, and printer are part of the Level II ROM. Since information must be stored into them, they are moved from ROM to fixed addresses in RAM (within the Communications Region) during IPL. The Level II drivers must be called for each character that is to be transmitted. The drivers cannot cope with the concept of records or files, all record blocking and deblocking is left to the user. Level II has no general purpose record management utilities. For BASIC programs you must use routines such as PRINT and INPUT to block off each record.

Integer Destination Register HL HL HL WRA1 Operation Addition Subtraction Multiplication Division Single Precision Destination Register WRA1 WRA1 WRA1 WRA1 Operation Addition Subtraction Multiplication Division Double Precision Destination Register WRA1 WRA1 WRA1 WRA1 Operation Addition Subtraction Multiplication Division Source Registers WRA1 WRA1 WRA1 WRA1 + * / WRA2 WRA2 WRA2 WRA2 Source Registers WRA1 WRA1 WRA1 WRA1 + * / (BCDE) (BCDE) (BCDE) (BcDE) Source Registers HL HL HL DE + * / DE DE DE HL

Figure 1.8: Register arrangements used by arithmetic routines.

12

When writing to a cassette, for example, the PRINT routine produces a header of 256 zeroes, followed by an A5. After the header has been written each individual variable is written as an ASCII string, with a blank space between each variable, finally terminating with a carriage return. Non string variables are converted to their ASCII equivalent. INPUT operation begins with a search for the 256 byte header. Then the A5 is skipped and all variables are read into the line buffer until the carriage return is detected. When the INPUT is completed all variables are converted to their correct form and moved to the VLT. The keyboard, video and line printer drivers can be entered directly or through a general purpose driver entry point at 03C2. Specific calling sequences for each of these drivers are given in chapter 2. The cassette driver is different from the other drivers in several respects. It does its I/O in a serial bit mode whereas all of the other drivers work in a byte (or character) mode. This means that the cassette driver must transmit data on a bit-by-bit basis. The transmission of each bit is quite complex and involves many steps. Because of the timing involved, cassette I/O in a disk based system, must be done with the clock off (interrupts inhibited). For more details on cassette I/O see chapter 4.

Reset Processing (non-disk)


Operations for this state begin at absolute location zero when the Reset button is pressed. From there control is passed to 0674 where the following takes place. 00UFC A) Ports FF (255 decimal) to 80 (128 decimal) are initialized to zero. This clears the cassette and selects 64 characters per line on the video. B) The code from 06D2 to 0707 is moved to 4000 - 4035. This initializes addresses for the restart vectors at 8, 10, 18 and 20 (hex) to jump to their normal locations in Level II. Locations 400C and 400F are initialized to RETURNs. If a disk system is being IPL'd 400C and 400F will be modified to JUMP instructions with appropriate addresses by SYS0 during the disk part of IPL. The keyboard, video, and line printer DCB's are moved from ROM to RAM beginning at address' 4015 to 402C after moving the DCB's locations 402D, 4030, 4032 and 4033 are initialized for non-disk usage. They will be updated by SYS0 if a disk system is being IPL'd. C) Memory from 4036 to 4062 is set to machine zeros. (00) After memory is zeroed, control is passed to location 0075 where the following takes place: 00UFC A) The division support routine is moved from @FT218F7-191B to 4080-40A6. This range also includes address pointers for the program statement table. Location 41E5 is initialized to: LD A, (2C00) B) The input buffer address for the scanner routine is set to 41E5. This will be the buffer area used to store each line received during the Input Phase. C) The Disk BASIC entry vectors 4152-41A5 are initialized to a JMP to 012D. This will cause an L3 ERROR if any Disk BASIC features are used by the program. Next, locations 41A6-41E2 (DOS exits) are set to returns (RETs). 41E8 is set to zero and the current stack pointer (CSP) is set to 41F8. (We need a stack at this point because CALL statements will be executed during the rest of the IPL sequence and they require a stack to save the return address). D) A subroutine at 1B8F is called. It resets the stack to 434C and initializes 40E8 to 404A. It then initializes the literal string pool table as empty, sets the current output device to the video, flushes the print buffer and turns off the cassette. The FOR statement flag is set to zero, a zero is stored as the first value on the stack and control is returned to 00B2. E) The screen is cleared, and the message 'MEMORY SIZE' is printed. Following that, the response is accepted

Part 6 - System Utilities


System utilities in Level II ROM are the Direct Commands: AUTO, CLEAR, CSAVE, CLOAD, CLEAR, CONT, DELETE, EDIT, LIST, NEW, RUN, SYSTEM, TROFF and TRON. These commands may be intermixed with BASIC program statements. However, they are executed immediately rather than being stored in the program statement table (PST). After executing a Direct Command, control returns to the Input Phase. After an entire BASIC program has been entered (either through the keyboard or via CLOAD or LOAD, on a disk system), it must be executed by using the RUN command This command is no different from the other system commands except that it causes the BASIC program in the PST to be executed (the Execution Phase is entered). As with other system commands, when the BASIC program terminates, control is returned to the Input Phase.

System Flow During IPL


The IPL sequence has already been discussed in general terms. A complete description of the procedure follows. The description is divided into separate sections for disk and non-disk systems.

13

and tested, then stored in 40B1. Fifty words of memory are allotted for the string area and its lower boundary address is stored in 40A0. F) Another subroutine at 1B4D is called to turn Trace off, initialize the starting address of the simple variables (40F9), and the program statement table (40A4). The variable type table 411A is set to single precision for all variables, and a RESTORE is done. Eventually control is returned to 00FC. G) At 00FC the message 'RADIO SHACK Level II BASIC' is printed and control is passed to the Input Phase.

Assuming a carriage return was not detected the Granule Allocation Table (GAT) sector (track 11 sector 0) is read and the E0 byte is tested for a carriage return value. Again, if one is found (the default case) control goes to 4400, otherwise a 20 byte message starting at byte E0 of the GAT sector is printed. Then control is passed to 4405 where the AUTO procedure is started. Following execution of the AUTO procedure control will be passed to the DOS Input Phase which starts at 4400.

Disk BASIC
One of the DOS commands is a utility program called BASIC. In addition to providing a means of transferring control from DOS to Level II, it contains the interpretation and execution code for the following Disk BASIC statements:
TRSDOS and NEWDOS CVI CVS CVD MKI$ MKS$ TIME$ CLOSE FIELD GET PUT KILL MERGE NAME LSET RSET &O CMD"S" CMD"T" CMD"R" CMD"D" MID$(left side of equation) OPEN"R" NEWDOS only OPEN"E" RENUM REF CMD"E" MKD$ AS INSTR CMD"A" OPEN"O" DEFFN DEFUSR LOAD SAVE LINE &H USR0-USR9 OPEN"I"

Reset Processing (disk systems)


Operations for this state begin at location 0000 and jump immediately to 0674. The code described in paragraphs A, B, and C for RESET processing (non-disk systems on page xx) is common to both IPL sequences. After the procedure described in paragraph C has taken place a test is made to determine if there are disks in the system. If there are no disk drives attached, control goes to 0075, otherwise. 00UFC A) Disk drive zero is selected and positioned to track 0 sector 0. From this position the sector loader (BOOT/SYS) is read into RAM locations 4200 - 4455. Because the sector loader is written in absolute form it can be executed as soon as the READ is finished. After the READ finishes, control is passed to the sector loader which positions the disk to track 11 sector 4. This sector is then read into an internal buffer at 4D00. The sector read contains the directory entry for SYS0 in the first 32 bytes. Using this data the sector loader computes the track and sector address for SYS0 and reads the first sector of it into 4D00. B) Following the READ, the binary data is unpacked and moved to its specified address in RAM. Note that SYS0 is not written in absolute format so it cannot be read directly into memory and executed. It must be decoded and moved by the sector loader. Once this is done control is passed to SYS0 beginning at address 4200. C) The following description for SYS0 applies to NEWDOS systems only. It begins by determining the amount of RAM memory and storing its own keyboard driver address in the keyboard DCB at 4015. The clock interrupt vector address (4012) is initialized to a CALL 4518. Next, more addresses are initialized and the NEWDOS header message is written. D) After writing the header, a test for a carriage return on the keyboard is made. If one is found, the test for an AUTO procedure is skipped and control passes immediately to 4400 were the DOS Input SCANNER phase is initiated.

CMD"DOS command"

An additional command peculiar to TRSDOS only is: CMD"X", <ENTER> - Version 2.1 CMD"#", <ENTER> - Version 2.2 & 2.3

These hidden, and undocumented commands display a 'secret' copyright notice by Microsoft. Also undocumented is CMD'A' which performs the same function as CMD'S'. Disk BASIC runs as an extension to Level II. After being loaded, it initializes the following section of the Communications Region: 00UFC 1. DOS exits at 41A6 - 41E2 are changed from RETURN's to jumps to locations within the Disk BASIC utility. 2. The Disk BASIC exits at 4152 - 41A3 are changed from JP 12D L3 syntax error jumps to addresses of verb action routines within Disk BASIC. Following the initialization of the Communications Region, DCBs and sector buffers for three disk files are allocated at the end of Disk BASIC's code. Control is then given to the Input Scanner in Level II (1A19). Disk BASIC will be re-entered to execute any Disk BASIC statement, or whenever a DOS Exit is taken from Level II. The Disk BASIC entry points are entered as though they are verb action routines. When finished control returns to the execution driver. Note: Disk BASIC occupies locations 5200 - 5BAD (NEWDOS system). Each file reserved will require an additional (32 256 decimal) bytes of storage. Assembly programs should take care not to disturb this region when running in conjunction with a BASIC program.

14

Chapter 2

Subroutines
Level II has many useful subroutines which can be used by assembly language programs. This chapter describes a good number of the entry points to these subroutines. However there are many more routines than those described here. Using the addresses provided as a guide, all of the Level II routines dealing with a particular function may be easily located. Before using the math or arithmetic calls study the working register concept and the mode flag (see chapter 1 page 14). Also, remember that the Division Support Routine (see chapter 1 page 10) is loaded automatically only when IPL'ing a non-disk system. On disk systems it is loaded by the Disk BASIC utility. If you are using a disk system and executing an assembly language program, which uses the any of the math or arithmetic routines that require division, you must enter BASIC first or load the Division Support Routine from within your program. The I/O calling sequences described are for Level II only. The TRSDOS and Disk BASIC Reference Manual contains the DOS calling sequences for disk I/O. The SYSTEM calls and BASIC functions are somewhat specialized, consequently they may not always be useful for an application written entirely in assembly language. However if you want to combine assembly and BASIC you will find these routines very useful. of memory mapped devices are the video, the keyboard, and the disk. Programmed I/O (via ports) is a direct transfer of data between a register and a device. The only device using port I/O is the cassette.

Keyboard Input
The keyboard is memory mapped into addresses 3800 3BFF. It is mapped as follows:

Bit

<------------------- Keyboard Addresses -------------------> 3801 3802 H I J K L M N O 3804 P Q R S T U V W 3808 X Y Z 3810 0 1 2 3 4 5 6 7 3820 8 9 : ; , . / 3840 ENTER CLEAR BREAK UP ARW DN ARW LT ARW RT ARW SP BAR 3880 SHIFT

0 1 2 3 4 5 6 7

@ A B C D E F G

I/O Calling Sequences


Input and Output (I/O) operations on a Model I machine are straight forward, being either memory mapped or port addressable. There are no DMA (direct memory access) commands and interrupt processing is not used for I/O operations. The selection of entry points presented here is not exhaustive. It covers the more general ones and will point the reader in the right direction to find more specialized entry points, if needed. In memory mapped operations, storing or fetching a byte from a memory location, causes the data to be transferred between the CPU register and the target device. Examples

When a key is depressed, a bit in the corresponding position in the appropriate byte, is set, also bits set by a previous key are cleared. You will notice that only eight bytes (3801 - 3880) are shown in the table as having any significance. This might lead one to believe that the bytes in between could be used. Unfortunately this is not the case as the byte for any active row is repeated in all of the unused bytes. Thus all bytes are used.

CALL 002B

Scan Keyboard

Performs an instantaneous scan of the keyboard. If no key is depressed control is returned to the caller with the Aregister and status register set to zero. If any key (except the BREAK key) is active the ASCII value for that character is returned in the A-register. If the BREAK key is active, a RST 28 with a system request code of 01 is executed. The RST instruction results in a JUMP to the

15

DOS Exit 400C. On non-disk Systems the Exit returns, on disk systems control is passed to SYS0 where the request code will be inspected and ignored, because system request codes must have bit 8 on. After inspection of the code, control is returned to the caller of 002B. Characters detected at 002B are not displayed. Uses DE, status, and A register.
; ; SCAN KEYBOARD AND TEST FOR BREAK OR ASTERISK ; PUSH DE ; SAVE DE PUSH IY ; SAVE IY CALL 2BH ; TEST FOR ANY KEY ACTIVE DEC A ; KEY ACTIVE, WAS IT A BREAK JR M,NO ; GO IF NO KEY HIT JR Z,BRK ; ZERO IF BREAK KEY ACTIVE INC A ; <A> BACK TO ORIGINAL VALUE CP 2AH ; NO, TEST FOR * KEY ACTIVE JR Z,AST ; ZERO IF * . . .

Video Output
Video I/O is another example of memory mapped I/O. It uses addresses 3C00 thru 3FFF where 3C00 represents the upper left hand corner of the video screen and 3FFF represents the lower right hand corner of the screen. Screen control codes such as TAB, CURSON ON/OFF, BACKSPACE and such are processed by the video driver routine. The video device itself does not recognize any control codes. Codes recognized by the driver and their respective actions are:
Code (hex.) 08 0E 0F 17 18 19 1A 1B 1C 1D 1E 1F Action backspace and erase character. turn on cursor. turn off cursor. select line size of 32 char/line. backspace one character (left arrow) skip forward one character (right arrow) skip down one line (down arrow). skip up one line (up arrow). home cursor. select 64 char/line. position cursor to Start of current line erase from cursor to end of line erase from Cursor to end of frame

CALL 0049

Wait For Keyboard Input

Returns as soon as any key on keyboard is pressed. ASCII value for character entered is returned in A- register. Uses A, status and DE registers.
; ; WAIT FOR NEXT CHAR FROM KEYBOARD AND TEST FOR ALPHA ; PUSH DE ; SAVE DE PUSH IY ; SAVE IY CALL 49H ; WAIT TILL NEXT CHAR ENTERED CP 41H ; TEST FOR LOWER THAN "A" JR NC,ALPHA ; JMP IF HIGHER THAN NUMERIC . .

CALL 05D9

Wait For Next Line

Character and line size (32/64 characters per line) is selected by addressing the video controller on port FF, and sending it a function byte specifying character size. The format of that byte is:
7 6 5 4 3 2 1 0 x x x x x x x x not used used for cassette operations character size select 1 = 32 char/line 0 = 64 char/line = bit

Accepts keyboard input and stores each character in a buffer supplied by caller. Input continues until either a carriage return or a BREAK is typed, or until the buffer is full. All edit control codes are recognized, e.g. TAB, BACKSPACE, etc. The calling sequence is: On exit the registers contain:
; ; GET NEXT LINE FROM KEYBOARD. EXIT IF BREAK STRUCK. ; LINE CANNOT EXCEED 25 CHARACTERS ; SIZE EQU 25 ; MAX LINE SIZE ALLOWED LD HL,BUFF ; BUFFER ADDRESS LD B,SIZE ; BUFFER SIZE CALL 5D9H ; READ NEXT LINE FROM KEYBOARD JR C,BREAK ; JMP IF BREAK TYPED . . BUFF DEFS SIZE ; LINE BUFFER . .

CALL 0033

Video Display

Displays the character in the A-register on the video. Control codes are permitted. All registers are used.
; ; DISPLAY MESSAGE ON VIDEO ; LD HL,LIST ; MESSAGE ADDRESS LOOP LD A,(HL) ; GET NEXT CHARACTER OR A ; TEST FOR END OF MESSAGE JR Z,DONE ; JMP IF END OF MESSAGE (DONE) PUSH HL ; NT END, PRESERVE HL CALL 33H ; AND PRINT CHARACTER POP HL ; RESTORE HL INC HL ; BUMP TO NEXT CHARACTER JR LOOP ; LOOP TILL ALL PRINTED DONE . . . LIST DEFM 'THIS IS A TEST' DEFB 0DH ; CARRIAGE RETURN DEFB 0 ; END OF MESSAGE INDICATOR

HL B C A

Buffer address Number of characters transmitted excluding last. Original buffer size Last character received if a carriage return or BREAK is typed. Carry Set if break key was terminator, reset otherwise. If the buffer is full, the A register will contain the buffer size.

16

CALL 01C9

Clear Screen

Clears the screen, selects 64 characters and homes the cursor. All registers are used.
; ; CLEAR SCREEN, HOME CURSOR, SELECT 32 CHAR/LINE ; SKIP 4 LINES ; CALL 01C9H ; CLEAR SCREEN LD A,17H ; SELECT 32 CHAR/LINE CALL 0033H ; SEND CHAR SIZE TO VIDEO LD B,4 ; NO. OF LINES TO SKIP LD A,1AH ; CODE TO SKIP ONE LINE LOOP PUSH BC ; SAVE BC CALL 33H ; SKIP I LINE POP BC ; GET COUNT DJNZ LOOP ; LOOP TILL FOUR LINES DONE

; ; WRITE MESSAGE ON PRINTER. IF NOT READY WITHIN 1.5 SECONDS ; DISPLAY ERROR MESSAGE ON VIDEO ; LD HL,LIST ; ADDR OF LINE TO PRINT START LD B,5 ; PREPARE TO TEST FOR PRINTER ; READY LOAD LD DE,10H ; LOAD DELAY COUNTERS TST CALL 05D1H ; GET PRINTER STATUS JR Z,RDY ; JP IF PRINTER READY DEC DE ; NOT READY, DECREMENT ; COUNTERS AND LD A,D ; TEST IF 1.5 SEC HAS ELAPSED OR JR DJNZ JP RDY POP LD OR JR LD CALL INC JR NTRDY LD DONE LIST CALL . . . DEFM DEFB DEFB NTRDM DEFM DEFB . . E NZ,TST LOAD NTRDY HL A,(HL) A Z,DONE C,A 58DH HL START HL,NTRDM VIDEO* ; ; ; ; ; ; ; ; ; ; FIRST DE MUST = 0 JMP IF DE NOT 0 LOOP TILL 1.5 SEC PASSED GO DISPLAY 'PRINTER NOT READY RESTORE ADDR OF PRINT LINE GET NEXT CHAR TO PRINT TEST FOR END OF LINE JMP IF END OF LINE PUT CHAR IN PROPER REGISTER

CALL 022C

Blink Asterisk

Alternately displays and clears an asterisk in the upper right hand corner. Uses all registers.
; ; BLINK ASTERISK THREE TIMES ; LD B,3 ; NO. OF TIMES TO BLINK LOOP PUSH BC ; SAVE COUNT CALL 022CH ; BLINK ASTERISK ONCE POP BC ; GET COUNT DJNZ LOOP ; COUNT 1 BLINK DONE . .

; PRINT CHARACTER ; BUMP TO NEXT CHAR ; LOOP TILL ALL CHARS PRINTED ; HL = ADDR OF NOT READY NSG ; PRINT MEG ; LINE PRINTED ON PRINTER

'THIS IS A TST ODH ; CR MAY BE REQUIRED TO START ; PRINTER 0 ; END OF MSG FLAG 'PRINTER NOT READY' 0 ; TERMINATE PRINTED MSG

Printer Output
The printer is another example of a memory mapped device. Its address is 37E8H. Storing an ASCII character at that address sends it to the printer. Loading from that address returns the printer status. The status is returned as a zero status if the printer is available and a non-zero status if the printer is busy.

CALL 05D1

Get Printer Status

Returns the status of the line printer in the status register as zero if the printer is ready, and non-zero if not ready. Other status bits are returned as shown:
7 6 5 4 3 2 1 0 = bit x x x x 0 0 0 0

CALL 003B

Print Character

The character contained in the C-register is sent to the printer. A line count is maintained by the driver in the DCB. When a full page has been printed (66 lines), the line count is reset and the status register returned to the caller is set to zero. Control codes recognized by the printer driver are:
CODE 00 ACTION Returns the printer Status in the upper two bits of the A-register and sets the status as zero if not busy, and non-zero if busy. Unconditionally skips to the top of the next page. Resets the line count (DCB 4) and compares its previous value to the lines per page (DCB 3) value. If the line count was zero, no action is taken. If the line count was non-zero then a Skip to the top form is performed. Line terminator. Causes line count to be incremented and tested for full page. Usually causes the printer to begin printing.

NOT USED 0 - PRINTER NOT SELECTED 1 - PRINTER SELECTED 0 - NOT READY 1 - READY 0 - PAPER 1 - OUT OF PAPER 0 - NOT BUSY 1 - BUSY The out of paper and busy bits are optional on some printers. ; ; MONITOR PRINTER STATUS ACCORDING TO STATUS BITS ABOVE ; AND PRINT APPROPRIATE ERROR MESSAGE ; LD BC,10 ; TIMER COUNT FOR PRINTER START CALL 05D1H ; GET PRINTER STATUS JR Z,OK ; JUMP IF READY BIT 7,A ; IS IT STILL PRINTING? JR Z,TIME ; YES IF NZ. GO TIME IT BIT 4,A ; NOT PRINTING. IS IT SELECTED JR Z,NS ; ZERO IF NOT SELECTED ; WE HAVE A HARDWARE PROBLEM BIT 5,A ; UNIT IS SELECTED AND NOT BUSY JR Z,NR ; ZERO IF NOT READY

0B 0C

0D

17

; ; UNIT IS SELECTED, READY, AND NOT BUSY. ASSUME OUT OF PAPER ; OP LD HL,OPM ; DISPLAY OUT OF PAPER MSG . . JP WAIT ; GO WAIT FOR OPERATOR REPLY ; AND RETRY OR ABORT NR BIT 6,A ; UNIT IS NOT READY, TEST FOR OUT JR NZ,OP ; OF PAPER ALSO. JMP IF OUT OF PAPER LD . . JP NB LD . . JP POP DEC PUSH LD OR JR LD . . JP . HL,NRM WAIT HL,NSM WAIT BC BC BC A,B C NZ,START HL,TOM WAIT ; DISPLAY NOT READY MSG ; GO WAIT FOR OPERATOR REPLY ; AND RETRY OR ABORT ; GET DISPLAY NOT SELECTED MSG ; ; ; ; ; ; ; ; GO WAIT FOR OPERATOR REPLY AND RETRY OR ABORT GET TIME COUNTER COUNT 1 LOOP SAVE NEW VALUE IF ITS GONE TO ZERO WE HAVE TIMED OUT LOOP TILL OP FINISHED OR TIME-OUT

CALL 0296

Read Leader

Reads the currently selected unit until an end of leader (A5) is found. An asterisk is displayed in the upper right hand corner of the video display when the end is found. Uses the A-register.
LD CALL CALL . . A,1 0212H 0296H ; CODE FOR UNIT 1 ; SELECT UNIT 1, TURN ON MOTOR ; READ HEADER. RTN WHEN A5 ENCOUNTERED

CALL 0235

Read One Byte

TIME

Reads one byte from the currently selected unit. The byte read is returned in the A-register. All other registers are preserved.
LD CALL CALL CALL CP JR . . . A,1 0212H 0296H 0235H 41H Z,YES ; ; ; ; ; ; UNIT TO SELECT SELECT UNIT TURN ON MOTOR SKIP OVER HEADER READ FOLLOWING BYTE TEST FOR OUR FILE NAME (A) JMP IF FILE A

; DISPLAY TIMEOUT MSG ; GET OPERATOR REPLY AND RETRY ; OR ABORT

Cassette I/O
Cassette I/O is not memory mapped. Cassettes are addressed via port FF after selecting the proper unit, and I/O is done a bit at a time whereas all other devices do I/O on a byte basis (except for the RS-232-C). Because of the bit-by-bit transfer of data, timing is extremely critical. When any of the following calls are used, the interrupt system should be disabled to guarantee that no interruptions will occur and therefore disturb the critical timing of the output.

CALL 0264

Write One Byte

Writes the byte in the A-register to the currently selected unit. Preserves all register.
LD CALL CALL LD CALL . . . A,1 0212H 0284H A,41H 0264H ; ; ; ; ; UNIT NO. MASK. SELECT UNIT, START MOTOR WRITE HEADER (256 ZEROS AND A5) WRITE FILE NAME (OURS IS A) WRITE A AFTER HEADER

CALL 0212

Turn On Motor

Selects unit specified in A-register and starts motor. Units are numbered from one. All registers are used.
LD CALL . . . A,1 0212H ; CODE TO SELECT CASSETTE 1 ; SELECT UNIT 1, TURN ON MOTOR

CALL 0284

Write Leader

Writes a Level II leader on currently selected unit. The leader consists of 256 (decimal) binary zeros followed by a hex A5. Uses the B and A registers.
LD CALL CALL . . . A,1 212H 284H ; CODE TO SELECT UNIT I ; SELECT UNIT, TURN ON MOTOR ; WRITE HEADER

18

Conversion Routines
These entry points are used for converting binary values from one data type or mode to another, such as integer to floating point, and for conversions between ASCII and binary representation. These conversion routines assume the value to be converted is in WRA1 and that the mode flag (40AF) reflects the current data type. The result will be left in WRA1 and the mode flag will be updated.

CALL 0ADB

Integer To Double

Contents of WRA1 are converted from integer or single precision to double precision. All registers are used.
; ; ; LD LD LD LD LD LD CALL LD LD LD LDIR . . . VALUE DEFS . . . A,59H (4121H),A A,67H (4122H),A A,2 (40AFH),A 0ADBH DE,VALUE HL,411DH BC,B ; LSB OF 26457 (10) ; ; ; ; ; ; ; ; MSB OF 26457 (10) TYPE CODE FOR INTEGER SET TYPE TO INTEGER CONVERT INTEGER TO DP NOW, MOVE DP VALUE FROM WRA1 TO LOCAL AREA NO. OF BYTES TO MOVE MOVE VALUE

Data Type Conversions CALL 0A7F Floating Point Integer

; HOLDS OP EQUIVALENT OF 26457

The contents of WRA1 are converted from single or double precision to integer. No rounding is performed. All registers are used.
; ; ; ; CONVERT SINGLE PRECISION VALUE TO INTEGER AND MOVE THE RESULT TO IVAL HL,4121H DE,VALUE BC,4 A,4 (40AFH),A 0A7FH A,(412lH) (IVAL),A A,(4122H) (IVAL+1),A ; ; ; ; ; ; ; ; ; ; ; ADDR OF LSB IN WRA1 ADDR OF LSB OF SP NO. NO OF BYTES TO MOVE MOVE VALUE TO WRAS TYPE CODE FOR SP SET TYPE TO SP CONVERT SP VALVE TO INTEGER LSB OF INTEGER EQUIVALENT SAVE IN INTEGER LOCATION MSB OF INTEGER EQUIVALENT SAVE IN INTEGER LOCATION

ASCII To Numeric Representation


The following entry points are used to convert between binary and ASCII. When converting from ASCII to binary the HL register pair is assumed to contain the address of the ASCII string. The result will be left in WRA1 or the DE register pair and the mode flag will be updated accordingly.

LD LD LD LDIR LD LD CALL LD LD LD LD . . . VALUE DEFB DEFB DEFB DEFB IVAL DEFB DEFB . .

CALL 1E5A

ASCII To Integer

0EH B6H 00H 88H 0 0

; ; ; ; ; ;

LSB OF 502.778 (SP) NLSB MSB EXPONENT WILL HOLD INTEGER EQUIVALENT OF SP 502.778

Converts the ASCII string pointed to by HL to its integer equivalent. The result is left in the DE register pair. Conversion will cease when the first non-numeric character is found.
; ; ;

CALL 0AB1

Integer To Single
AVAL BVAL

The contents of WRA1 are converted from integer or double precision to single precision. All registers are used.
; ; CONVERT INTEGER VALUE TO SINGLE PRECISION AND MOVE TO ; LOCAL AREA ; LD A,59H LD (4121H),A ; LSB OF INTEGER 26457 (10) LD A,67H LD (4122H),A ; MEN OF INTEGER 26457 (10) LD A,2 ; TYPE CODE FOR INTEGER LD (40AFH),A ; SET TYPE TO INTEGER CALL 0ADBH ; CONVERT INTEGER TO SP LD HL,VALUE ; ADDR. OF AREA FOR SP EQUIVALENT CALL O9CBH ; MOVE SP VALUE FROM WRA1 TO VALUE . . . VALUE DEFS 4 ; WILL HOLD 26457 IN SP FORMAT . .

LD CALL LD . . . DEFM DEFB DEFW . .

HL,AVAL 1E5AH (BVAL),DE

; HL = ADDR. OF ASCII NUMBER ; CONVERT IT TO BINARY ; SAVE BINARY VALUE

'26457' 0 2

; ASCII VALUE 26457 ; NON-NUMERIC STOP BYTE ; HOLDS BINARY VALUE 26457

CALL 0E6C

ASCII To Binary

Converts the ASCII string pointed to by HL to binary. If the value is less than 2**16 and does not contain a decimal point or an E or D descriptor (exponent), the string will be converted to its integer equivalent. If the string contains a decimal point or an E, or D descriptor or if it exceeds 2**16 it will be converted to single or double precision. The binary value will be left in WRA1 and the mode flag will be to the proper value.

19

; ; ; LD CALL . . . DEFM DEFB . . HL,AVAL 0E6CH ; ASCII NUMBER ; CONVERT ASCII TO BINARY

; ; ; LD LD LD LD CALL . . . DEFS . . HL,500 (4121H),HL BC,505H HL,BUFF 132FH ; ; ; ; ; 500 (10) TO WRA1 SUPPRESS COMMAS OR DEC. PTS. BUFFER ADDR FOR ASCII STRING CONVERT VALUE IN WRA1 TO ASCII AND STORE IN BUFF.

AVAL

'26457' 0

; ASCII VALUE TO BE CONVERTED ; NON-NUMERIC STOP BUFF

; BUFFER FOR ASCII VALUE

CALL 0E65

ASCII To Double

CALL 0FBE

Floating to ASCII

Converts the ASCII string pointed to by HL to its double precision equivalent. All registers are used. The result is left in WRA1.
; ; ; LD CALL LD LD LD LDIR . . . DEFM DEFB DEFS . . HL,AVAL 0E65H DE,BVAL HL,411DH BC,8 ; ; ; ; ; ; ADDR OF ASCII VALUE TO CONVERT CONVERT VALUE TO DP THEN MOVE VALUE FROM WRA1 TO A LOCAL AREA NO. OF BYTES TO MOVE MOVE DP VALUE TO LOCAL AREA

Converts the single or double precision number in WRA1 to its ASCII equivalent. The ASCII value is stored at the buffer pointed to by the HL register pair. As the value is converted from binary to ASCII, it is formatted as it would be if a PRINT USING statement had been invoked. The format modes that can be specified are selected by loading the following values into the A, B ,and C registers.
REGISTER REGISTER A = 0 ... Do not edit. Strictly binary to ASCII. A = X ... Where x is interpreted as: = BIT

AVAL BVAL

'26457' 0 8

; ; ; ;

ASCII VALUE TO BE CONVERTED NONNUMERIC STOP BYTE LOCAL AREA THAT HOLDS BINARY EQUIVALENT

7 6 5 4 3 2 1 0 x x x x x x x x

EXPONENTIAL NOTATION RESERVED SIGN FOLLOWS VALUE

Binary To ASCII Representation


The next set of entry points are used to convert from binary to ASCII.

INCLUDE SIGN PRINT LEADING $ SIGN INCLUDE LEADING ASTERISKS PRINT COMMAS EVERY 3RD DIGIT 0 - DO NOT PERFORM EDIT FUNCTIONS 1 - EDIT VALUE ACCORDING TO OPTIONS REGISTER REGISTER ; ; ; LD CALL LD LD CALL . . . AVAL1 DEFM DEFB AVAL2 DEFS . . HL,AVAL1 0E6CH HL,AVAL2 A,0 0FBEH ; ; ; ; ; ASCII VALUE TO CONVERT CONVERT ASCII TO BINARY BUFFER ADDR. FOR CONVERTED VALUE SIGNAL NO EDITING CONVERT SP VALUE BACK TO ASCII B = The number of digits to the left of the decimal point. C = The number of digits after the decimal point

CALL 0FAF

HL To ASCII

Converts the value in the HL register pair (assumed to be an integer) to ASCII and displays it at the current cursor position on the video. All registers are used.
; ; ; LD CALL . . HL,64B8H 0FAFH ; HL = 25784 (10) ; CONVERT TO ASCII AND DISPLAY

'1103.25' 0 7

; ORIGINAL ASCII VALUE ; NON-NUMERIC STOP BYTE ; WILL HOLD RECONVERTED VALUE

CALL 132F

Integer To ASCII

Converts the integer in WRA1 to ASCII and stores the ASCII string in the buffer pointed to by the HL register pair. On entry, both the B and C registers should contain a 5 to avoid any commas or decimal points in the ASCII string. All registers are preserved.

20

Arithmetic Routines
These subroutines perform arithmetic operations between two operands of the same type. They assume that the operands are loaded into the correct hardware or Working Register Area, and that the data type or mode is set to the correct value. Some of these routines may require the Divide Support Routine (See Chapter 1 for details.)

CALL 0BF2

Integer Multiplication

Multiplies HL by DE. The product is left in HL and DE is preserved. If overflow occurs, both values are converted to single precision and the operation is restarted. The product would be left in WRA1.
LD LD LD LD CALL LD CP JR . . . DEFW DEFW . . A,2 (40AFH),A HL,(VAL1) DE,(VAL2) 0BF2H A,(40AFH) 2 NZ,... ; ; ; ; ; ; ; ; TYPE CODE FOR INTEGER SET TYPE TO INTEGER LOAD FIRST VALUE LOAD SECOND VALUE HL = HL * DE GET MODE FLAG TEST FOR OVERFLOW NO IF VALUE HAS OVERFLOWED

Integer Routines
The following routines perform arithmetic operations between integer values in the DE and HL register pairs. The original contents of DE is always preserved and the result of the operations is always left in the HL register pair.
VAL1 VAL2

25 20

CALL 2490

Integer Division

CALL 0BD2

Integer Add

Adds the integer value in DE to the integer in HL. The sum is left in HL and the original contents of DE are preserved. If overflow occurs (sum exceeds 2**15), both values are converted to single precision and then added. The result would be left in WRA1 and the mode flag would be updated.
LD LD LD LD CALL LD CP JR . . . DEFW 25 DEFW 20 . . A,2 (40AFH),A HL,(VAL1) DE,(VAL2) 0BD2H A,(40AFH) 2 NZ,... ; ; ; ; ; ; ; ; ; TYPE CODE FOR INTEGER SET TYPE TO INTEGER LOAD FIRST VALUE LOAD SECOND VALUE ADD SO THAT HL = HL + DE TEST FOR OVERFLOW IF TYPE IS NOT INTEGER NZ IF SUM IS SINGLE PRECISION ELSE SUM IS INTEGER

Divides DE by HL. Both values are converted to single precision before the division is started. The quotient is left in WRA1; the mode flag is updated. The orginal contents of the DE and HL register sets are lost.
LD LD CALL . . . DEFW DEFW DE,(VAL1) HL,(VAL2) 2490H ; LOAD VALUE 1 ; LOAD VALUE 2 ; DIVIDE DE BY HL. QUOTIENT TO WRAl

VAL1 VAL2

50 2

CALL 0A39

Integer Comparison

VAL1 VAL2

Algebraically compares two integer values in DE and HL. The contents of DE and HL are left intact. The result of the comparison is left in the A register and status register as:
OPERATION --------DE > HL DE < HL DE = HL ; ; ; LD LD CALL JR JP . . DE,(VAL1) HL,(VAL2) 0A39H Z,... P,... ; ; ; ; ; DE AND HL ARE VALUES TO BE COMPARED COMPARE DE TO HL Z IF DE = HL POSITIVE IF DE < HL A REGISTER ---------A = -1 A = +1 A = 0

CALL 0BC7

Integer Subtraction

Subtracts the value in DE from the value in HL. The difference is left in the HL register pair. DE is preserved. In the event of underflow, both values are converted to single precision and the subtraction is repeated. The result is left in WRA1 and the mode flag is updated accordingly.
LD LD LD LD CALL LD CP JR . . . DEFW DEFW . . A,2 (40AFE),A HL,(VAL1) DE,(VAL2) 0BC7H A,(40AFH) 2 NZ,... ; ; ; ; ; ; ; ; TYPE CODE FOR INTEGER SET TYPE TO INTEGER VALUE 1 VALUE 2 SUBTRACT DE FROM HL GET MODE FLAG TEST FOR UNDERFLOW NZ IF UNDERFLOW

Single Precision Routines


The next set of entry points are used for single precision operations. These routines expect one argument in the BC/DE registers and the other argument in WRA1.

VAL1 VAL2

25 20

21

CALL 0716

Single Precision Add

CALL 0A0C

Add the single precision value in (BC/DE) to the single precision value in WRA1. The sum is left in WRA1
LD CALL LD CALL CALL . . . DEFS DEFS . . HL,VAL1 9B1H HL,VAL2 9C2H 716H ; ; ; ; ; ; ADDR. OF ONE SP VALUE MOVE IT TO WRA1 ADDR. OF 2ND SP VALUE LOAD IT INTO BC/DE REGISTER ADD VALUE 1 TO VALUE 2 SUM IN WRA1

Single Precision Comparison

Algebraically compares the single precision value in (BC/DE) to the single precision value WRA1. The result of the comparison is returned in the A and status as:
OPERATION (BC/DE) > WRA1 (BC/DE) < WRA1 (BC/DE) = WRA1 ; ; ; LD CALL LD CALL CALL JR JP . . . DEFS DEFS . . HL,VAL1 9B1H HL,VAL2 9C2H 0A0CH Z,... P,... ; ; ; ; ; ; ; ADDR OF ONE VALUE TO BE COMPARED MOVE IT TO WRA1 ADDR OF 2ND VALUE TO COMPARE LOAD 2ND VALUE INTO BC/DE COMPARE BC/DE TO WRA1 ZERO IF (BC/DE) = WRA1 POSITIVE IF (BC/DE) < WRA1 A REGISTER A = -1 A = +1 A = 0

VAL1 VAL2

4 4

; HOLDS A SP VALUE ; HOLDS A SP VALUE

CALL 0713

Single Precision Subtract

Subtracts the single precision value in (BC/DE) from the single precision value in WRA1. The difference is left in WRA1.
LD CALL LD CALL CALL . . . DEFS DEFS . . HL,VAL1 9B1H HL,VAL2 9C2H 713H ; ; ; ; ; ; ADDR OF ONE SP. VALUE MOVE IT TO WRA1 ADDR OF 2ND SP VALUE LOAD IT INTO BC/DE SUBTRACT DE FROM WRA1 DIFFERENCE LEFT IN WRA1

VAL1 VAL2

4 4

; HOLDS A SP VALUE ; HOLDS A SP VALUE

VAL1 VAL2

4 4

; HOLDS A SP VALUE ; HOLDS A SP VALUE

Double Precision Routines


The next set of routines perform operations between two double precision operands. One operand is assumed to be in WRA1 while the other is assumed to be in WRA2 (4127-412E). The result is always left in WRA1.

CALL 0847

Single Precision Multiply

Multiplies the current value in WRA1 by the value in (BC/DE). the product is left in WRA1.
LD CALL LD CALL CALL . . . DEFS DEFS . . HL,VAL1 9B1H HL,VAL2 9C2H 547H ; ; ; ; ; ; ADDR OF ONE SP VALUE MOVE IT TO WRA1 ADDR OF 2ND SP VALUE LOAD 2ND VALUE INTO BC/DE MULTIPLY PRODUCT LEFT IN WRA1

CALL 0C77

Double Precision Add

Adds the double precision value in WRA2 to the value in WRA1. Sum is left in WRA1.
LD LD LD LD CALL LD LD CALL CALL . . . DEFS DEFS . . A,8 (40AFH),A DE,VAL1 HL,411DH 9D3H DE,VAL2 HL,4127H 9D3H 0C77H ; ; ; ; ; ; ; ; ; TYPE CODE FOR DP SET TYPE TO DP ADDR OF 1ST DP VALUE ADDR OF WRA1 MOVE 1ST DP VALUE TO WRA1 ADDR OF 2ND DP VALUE ADDR OF WRA2 MOVE 2ND VALUE TO WRA2 ADD WRA2 TO WRA1. SUM IN WRA1

VAL1 VAL2

4 4

; HOLDS A SP VALUE ; HOLDS A SP VALUE

CALL 2490

Single Precision Divide


VAL1 VAL2

Divides the single precision value in (BC/DE) by the single precision value in WRA1. The quotient is left in WRA1.
LD CALL LD CALL CALL . . . DEFS 4 ; DEFS 4 . . HL,VAL1 9B1H HL,VAL2 9C2H 2490H ; ; ; ; ; ; ADDR OF DIVISOR MOVE IT TO WRA1 ADDR. OF DIVIDEND LOAD BC/DE WITH DIVIDEND DIVIDE BC/DE BY WRA1 QUOTIENT IN WRA1

8 8

; HOLDS A DP VALUE ; HOLDS A DP VALUE

VAL1 VAL2

HOLDS DIVISOR HOLDS DIVIDEND

22

CALL 0C70

Double Precision Subtraction


; ; ; LD LD LD LD CALL LD LD CALL CALL JR JP . .

Subtracts the double precision value in WRA2 from the value in WRA1. The difference is left in WRA1.
LD LD LD LD CALL LD LD CALL CALL . . . DEFS DEFS . . A,8 (40AFH),A DE,VAL1 HL,411DH 9D3H DE,VAL2 HL,4127H 9D3H 0C70H ; ; ; ; ; ; ; ; ; ; TYPE CODE FOR DP SET TYPE TO DP ADDR OF 1ST DP VALUE ADDR OF WRA1 MOVE 1ST DP VALUE TO WRA1 ADDR OF 2ND DP VALUE ADDR OF WRA2 MOVE 2ND VALUE TO WRA2 SUBTRACT WRA2 FROM WRA1 DIFFERENCE IN WRA1

OPERATION A REGISTER WRA1 > WRA2 A = -1 WRA1 < WRA2 A = +1 WRA1 = WRA2 A = 0

A,8 (40AFH),A DE,VAL1 HL,411DH 9D3H DE,VAL2 HL,4127H 9D3H 0A78H Z,... P,...

; ; ; ; ; ; ; ; ; ; ;

TYPE CODE FOR DP SET TYPE FLAG TO DP ADDR OF 1ST DP VALUE ADDR OF WRA1 MOVE 1ST VALUE TO WRA1 ADDR OF 2ND DP VALUE ADDR OF WRA2 MOVE 2ND VALUE TO WRA2 COMPARE WRA1 TO WRA2 ZERO IF THEY ARE EQUAL POSITIVE IF WRA1 < WRA2

VAL1 VAL2

8 8

; HOLDS A DP VALUE ; HOLDS A DP VALUE

Math Routines CALL 0DA1 Double Precision Multiply


Multiplies the double precision value in WRA1 by the value in WRA2. The product is left in WRA1.
LD LD LD LD CALL LD LD CALL CALL . . . DEFS DEFS . . A,8 (40AFH),A DE,VAL1 HL,411DH 9D3H DE,VAL2 HL,4127H 9D3H 0DA1H ; ; ; ; ; ; ; ; ; ; TYPE CODE FOR DP SET TYPE TO DP ADDR OF 1ST DP VALUE ADDR OF WRA1 MOVE 1ST DP VALUE TO WRA1 ADDR OF 2ND DP VALUE ADDR OF WRA2 MOVE 2ND VALUE TO WRA2 MULTIPLY WRA1 BY WRA2 PRODUCT IN WRA1

All of the following subroutines assume that location 40AF contains a code indicating the data type or mode of the variable e.g., integer, single precision, or double precision, and that the variable itself is in Working Register Area 1 (WRA1). Also, the floating point Division Support Routine must be loaded at 4080.

CALL 0977

Absolute Value ABS (N)

VAL1 VAL2

8 8

; HOLDS A OF VALUE ; HOLDS A OF VALUE

CALL 0DE5

Double Precision Divide

Converts the value in Working Register Area 1 (WRA1) to its positive equivalent. The result is left in WRA1. If a negative integer greater than 2**15 is encountered, it is converted to a single precision value. The data type or mode flag (40AF) will be updated to reflect any change in mode.
LD LD LD CALL CALL . . . DEFB DEFB DEFB DEFB . . A,4 (40AFH),A HL,VAL1 09B1H 0977H ; ; ; ; ; TYPE CODE FOR SP SET TYPE TO SP ADDR OF SP VALUE TO ABS MOVE SP VALUE TO WRA1 FIND ABS VALUE

Divides the double precision value in WRA1 by the value in WRA2. The quotient is left in WRA1.
LD LD LD LD CALL LD LD CALL CALL . . . DEFS DEFS . . A,8 (40AFH),A DE,VAL1 HL,411DH 9D3H DE,VAL2 HL,4127H 9D3H 0DE5H ; ; ; ; ; ; ; ; ; ; TYPE CODE FOR DP SET TYPE TO DP ADDR OF 1ST DP VALUE ADDR OF WRA1 MOVE 1ST DP VALUE TO WRA1 ADDR OF 2ND DP VALUE ADDR OF WRA2 MOVE 2ND VALUE TO WRA2 DIVIDE WRA1 BY WRA2 QUOTIENT LEFT IN WRA1

VAL1

58H 34H 23H 87H

; SP 81.6022(10)

VAL1 VAL2

8 8

HOLDS A OF VALUE HOLDS A OF VALUE

CALL 0B37

Return Integer INT (N)

CALL 0A78

Double Precision Compare

Compares the double precision value in WRA1 to the value in WRA2. Both register areas are left intact. The result of the comparison is left in the A and status registers as:

Returns the integer portion of a floating point number. If the value is positive, the integer portion is returned. If the value is negative with a fractional part, it is rounded up before truncation. The integer portion is left in WRA1. The mode flag is updated.

23

VALUE AREA

LD LD LD CALL CALL LD LD CALL . . . DEFB DEFB DEFB DEFB DEFS . . .

A,4 (40AFH),A HL,VAL1 09B1H 0B37H DE,4121H HL,VAL2 09D3H

; ; ; ; ; ;

TYPE CODE FOR SP SET TYPE TO SINGLE PREC. ADDR OF SP VALUE MOVE SP VALUE TO WRA1 ISOLATE INTEGER PART OF SP VALUE ADDR OF WRA1 (INTEGER PART OF SP

CALL 1439

Raise Natural Base EXP (N)

; LOCAL ADDR FOR INTEGERIZED VALUE ; MOVE INTEGERIZED SP VALUE TO LOCAL

Raises E (natural base) to the value in WRA1 which must be a single precision value. The result will be returned in WRA1 as a single precision number.
LD LD LD CALL CALL LD LD CALL . . . DEFB DEFB DEFB DEFB DEFS . . . A,4 (40AFH),A HL,EXP 09B1H 1439H DE,4121H HL,POW 09D3H ; ; ; ; ; ; ; ; TYPE CODE FOR SP SET TYPE TO SP ADDR OF EXPONENT MOVE EXPONENT TO WRA1 FIND E ** 1.5708 ADDR OF WRA1 ADDR OF LOCAL STORAGE MOVE POWER TO LOCAL AREA

VAL1

VAL2

0E0H 05DH 0A5H 086H 4

; SP -41.3418

; HOLDS INTEGER PORTION OF ; -41.3418

EXP

CALL 15BD

Arctangent ATN (N)

POW

0DBH 00FH 049H 081H 4

; SP

1.5708(10)

; HOLDS E**1.5708

Returns the angle in radians, for the floating point tangent value in WRA1. The angle will be left as a single precision value in WRA1.
LD LD LD CALL CALL LD LD CALL . . . DEFB DEFB DEFB DEFB DEFS A,4 (40AFH),A HL,TAN 09B1H 15BDH HL,ANGL DE,4121H 09D3H ; ; ; ; ; ; ; ; TYPE CODE FOR SP SET TYPE TO SP ADDR OF VALUE FOR TANGENT MOVE TAN TO WRA1 FIND ANGLE IN RADS ADDR OF LOCAL STORAGE FOR ANGLE ADDR OF WRA1 MOVE ANGLE FROM WRA1 TO LOCAL AREA

CALL 13F2

Raise X to the Y Power X**Y

Raises the single precision value which has been saved on the STACK to the power specified in WRA1. The result will be returned in WRA1.
; ; COMPUTE 16**2 ; LD BC,RETADD PUSH BC LD A,4 LD (40AFH),A LD HL,X CALL 09B1H CALL 09A4H LD HL,Y CALL 0931H JP 13F2H RA . . . X DEFW 0 DEFW 85H Y DEFW 0 DEFW 82H . .

TAN

ANGL

9AH 0C4H 13H 80H 4

; TANGENT OF 30 DEG. ; EXPONENT ; WILL HOLD

30 DEG. IN RADS (.5235)

CALL 1541

Cosine COS (N)

; ; ; ; ; ; ; ; ; ; ;

RTN ADDR FOLLOWING RAISING X TO Y TYPE CODE FOR SP SET TYPE TO SP FOR X ADDR OF VAL TO BE RAISED MOVE VAL TO WRA1 WRA1 TO STACK ADDR OF POWER MOVE POWER TO WRA1 WRA1 = COMPUTE X**Y RTN TO RA WHEN DONE

; SP FOR 16 (10) ; SP FOR 2 (10)

Computes the cosine for an angle given in radians. The angle must be a floating point value; the cosine will be returned in WRA1 as a floating point value.
LD LD LD CALL CALL LD LD CALL . . . ANGL DEFB DEFB DEFB DEFB CANGL DEFS . . A,4 (40AFH),A HL,ANGL 09B1H 1541H HL,CANGL DE,4121H 09D3H ; ; ; ; ; ; ; ; TYPE CODE FOR SP SET TYPE TO SP ADDR OF ANGLE VALUE MOVE ANGLE TO WRA1 COMPUTE COSINE LOCAL ADDR FOR COSINE ADDR OF WRA1 MOVE COSINE FROM WRA1 TO LOCAL AREA

18H 04H 06H 80H 4

; 30 DEG. IN RADS. (.5235) ; EXPONENT ; WILL HOLD COSINE OF 30 DEG.

24

CALL 0809

Natural Log LOG (N)

CALL 14C9

Random Number RND (N)

Computes the natural log (base E) of the single precision value in WRA1. The result is returned as a single precision value in WRA1.
LD LD LD CALL CALL LD LD CALL . . . DEFB DEFB DEFB DEFB DEFS . . . A,4 (40AFH),A HL,POW 09B1H 0809H DE,4121H HL,NLOG 09D3H ; ; ; ; ; ; ; ; TYPE CODE FOR SP SET TYPE TO SP ADDR OF POWER MOVE POWER TO WRA1 FIND NAT.LOG. OF POWER ADDR OF WRA1 ADDR OF LOCAL STORAGE AREA MOVE LOG FROM WRA1 TO LOCAL AREA

Generates a random number between 0 and 1, or 1 and n depending on the parameter passed in WRA1. The random value is returned in WRA1 as an integer with the mode flag set. The parameter passed will determine the range of the random number returned. A parameter of 0 will return an interger between 0 and 1. A parameter greater than 0 will have any fraction portion truncated and will cause a value between 1 and the integer portion of the parameter to be returned.
LD LD LD LD CALL LD LD . . . DEFW . . . A,2 (40AFH),A A,50 (4l21H),A 14C9H HL,(4121H) (RVAL),HL ; TYPE CODE FOR INTEGER ; SET TYPE TO INTEGER ; ; ; ; PUT AN INTEGER 50 INTO WRA1 GET A RANDOM NO. BETWEEN 1 AND 50 LOAD RANDOM NO. INTO HL AND MOVE IT TO LOCAL AREA

POW

NLOG

00 00 04H 82HH 4

; FLOATING POINT 3 (LSB) ; EXPONENT FOR 3.0 ; WILL HOLD NAT. LOG OF 3

RVAL

; HOLDS RANDOM NUMBER (INTEGER)

CALL 0B26

Floating To Integer FIX (N)

CALL 1547

Sine SIN (N)

Unconditionally truncates the fractional part of a floating point number in WRA1. The result is stored in WRA1 and the type flag is set to integer.
LD LD LD CALL CALL LD LD . . . DEFB DEFB DEFB DEFB DEFS . . . A,4 (40AFH),A HL,FLPT 09B1H 0B26H HL,(4121H) (INTG),HL ; ; ; ; ; ; ; TYPE CODE FOR SP SET TYPE TO SP ADDR OF FLOATING POINT VALUE MOVE FLT.PT. VALUE TO WRA1 TRUNCATE AND CONVERT TO INTEGER LOAD INTEGER PORTION FROM WRA1 AND STORE IN LOCAL AREA

Returns the sine as a single precision value in WRA1. The sine must be given in radians in WRA1.
LD LD LD CALL CALL LD LD CALL . . . ANGL DEFB DEFB DEFB DEFB SANGL DEFS . . . A,4 (40AFH),A HL,ANGL 09B1H 1547H DE,4121H HL,SANGL 09D3H ; ; ; ; ; ; ; ; TYPE CODE FOR INTEGER SET TYPE TO SP ADDR. OF ANGLE IN RADIANS MOVE ANGLE TO WRA1 COMPUTE SINE OF ANGLE ADDR OF SINE IN WRA1 ADDR OF LOCAL AREA FOR SIN MOVE SINE TO LOCAL AREA

FLPT

INTG

0BAH 0D7H 01EH 086H 2

; SP 39.7107(10)

18H 04H 06H 80H 4

; 30 DEGS. IN RADS. (.5235) ; EXPONENT ; WILL HOLD SINE OF 30 DEG.

; HOLDS INTEGER PORTION OF ; 39.7107

CALL 13E7

Square Root SQR (N)

CALL 01D3

Reseed Random Seed RANDOM

Computes the square root of any value in WRA1. The root is left in WRA1 as a single precision value.
LD LD LD CALL CALL LD LD CALL . . . DEFB DEFB DEFB DEFB DEFS . . . A,4 (40AFH),A HL,VAL1 09B1H 13E7H DE,4121H HL,ROOT 09D3H ; ; ; ; ; ; ; ; TYPE CODE FOR SP SET TYPE TO SP VALUE TO ROOT OF MUST BE IN WRA1 TAKE ROOT OF VALUE ADDR OF ROOT IN WRA1 ADDR OF LOCAL AREA MOVE ROOT TO LOCAL AREA

Reseeds the random number seed (location 40AB) with the current contents of the refresh register.
CALL . . . 01D3H ; RESEED RANDOM NUMBER SEED

VAL1

ROOT

00H 00H 00H 83H 4

; SP 4 ; EXPONENT OF FLOATING POINT 4 ; HOLDS ROOT OF 4

25

CALL 15A8

Tangent TAN (N)

Computes the tangent of an angle in radians. The angle must be specified as a single precision value in WRA1. The tangent will be left in WRA1.
LD LD LD CALL CALL LD LD CALL . . . ANGL DEFB DEFB DEFB DEFB TANGL DEFS . . . A,4 (40AFH),A HL,ANGL 0981H 15A8H DE,4121H HL,TANGL 09D3H ; ; ; ; ; ; ; ; TYPE CODE FOR SP SET TYPE TO SP ADDR OF ANGLE IN RADIANS MOVE ANGLE TO WRA1 FIND TAN OF ANGLE ADDR OF WRA1 ADDR OF LOCAL STORAGE FOR TAN WOVE TAN FROM WRA1 TO LOCAL AREA

18H 04H 06H 80H 4

; VALUE FOR 30 DEG IN RADS ; (.5235) ; EXPONENT ; WILL HOLD TANGENT OF 30 DEG.

Function Derivation

26

SYSTEM FUNCTIONS
System Functions are ROM entry points that can be entered at This means that on a disk based system, for example, an assembly language program which CALLS these entry points could be executed immediately after IPL before executing the BASIC utility program first. These entry points are different from the BASIC Functions because they do not require the Communications Region (CR) to be initialized in order to operate correctly. A Level II system without disks always has an initialized CR because of its IPL processing. Some of the routines mentioned here do use the Communications Region, but none of them require any particular locations to be initialized. The System Error routine however, which may be called in the event of an error detected by these routines, will assume some words contain meaningful data, and will return control to the BASIC Interpreter Input Phase.

; ; ; ; ; ; ;

THE CURRENT STRING POINTED TO BY HL IS ASSUMED TO BE PART OF AN ASSIGNMENT STATEMENT CONTAINING AN OPTIONAL SIGN FOLLOWED BY A CONSTANT OR A VARIABLE NAME. MAKE THE NECESSARY TESTS TO DETERMINE IF A CONSTANT OR A VARIABLE IS USED. RST DEFB RST JR CALL JR CP JR CP JR CALL 08 3DH 10H NC,VAR 1E5AH SKIP 2BH Z,NEXT 20H Z,NEXT 260DH ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; TEST FOR HEX VALUE FOR = GET SYMBOL FOLLOWING = NC IF VARIABLE NAME GET VALUE OF CONSTANT JOIN COMMON CODE NOT NUMERIC, TEST FOR +,-, OR ALPHA SKIP + SIGNS NOT A +, TEST FOR A SKIP - SIGNS ASSUME IT'S A GOOD ALPHA AND SEARCH FOR A VARIABLE NAME (SEE SECTION 2.6 FOR A DESCRIPTION OF 260D)

NEXT

VAR

SKIP

. . .

RST 18

Compare DE:HL

Numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status register as:
CARRY SET NO CARRY NZ Z HL < DE HL > DE UNEQUAL EQUAL

RST 08

Compare Symbol

Compares the symbol in the input string pointed to by HL register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in the A-register and HL incremented by one. If the two characters do not match, a syntax error message is given and control returns to the Input Phase.
; ; TEST THE STRING POINTED TO BY HL TO SEE IF IT ; CONTAINS THE STRING 'A=B=C'. ; RST 08 ; TEST FOR A DEFB 41H ; HEX VALUE FOR A RST 08 ; FOUND A, NOW TEST DEFB 3DH ; HEX VALUE FOR = RET 08 ; FOUND =, NOW TEST DEFB 42H ; HEX VALUE FOR B RST 08 ; FOUND B, TEST FOR DEFB 3DH ; HEX VALUE FOR = RST 08 ; FOUND =, TEST FOR DEFB 43H ; HEX VALUE FOR C . ;FOUND STRING A=B-C . .

;
; THIS EXAMPLE TESTS THE MAGNITUDE OF THE VALUE ; FOLLOWING THE - IN THE STRING POINTED TO BY HL ; TO MAKE SURE IT FALLS BETWEEN 100 AND 500 ; RST 08 ; TEST FOR = DB 3DH ; HEX VALUE FOR = RST 10H ; FOUND =, TEST NEXT CHAR JR NC,ERR ; NC IF NOT NUMERIC CALL 1E5AH ; GET BINARY VALUE LD HL,500 ; UPPER LIMIT VALUE RST 18H ; COMPARE VALUE TO UPPER LIMIT JR C,ERR ; CARRY IF VALUE > 500 LD HL,100 ; LOWER LIMIT VALUE RST 18H ; COMPARE VALUE TO LOWER LIMIT JR NC,ERR ; NO CARRY IF VALUE < 100 . . .

FOR = FOR B = C

RST 20

Test Data Mode

RST 10

Examine Next Symbol

Loads the next character from the string pointed to by the HL register set into the A-register and clears the CARRY flag if it is alphabetic, or sets it if is alphanumeric. Blanks and control codes 09 and 0B are ignored causing the following character to be loaded and tested. The HL register will be incremented before loading any character therefore on the first call the HL register should contain the string address minus one. The string must be terminated by a byte of zeros.

Returns a combination of STATUS flags and unique numeric values in the A-register according to the data mode flag (40AF). This CALL is usually made to determine the type of the current value in WRA1. It should be used with caution, however since the mode flag and WRA1 can get out of phase particularly if some of the CALLS described here are used to load WRA1.
TYPE 02 03 04 08 (INTEGER) (STRING) (SINGLE PREC.) (DOUBLE PREC.) STATUS NZ/C/M/E Z/C/P/E NZ/C/P/O NZ/NC/P/E A-REGISTER -1 0 1 5

27

; ; TEST DATA TYPE AFTER INTEGER ADDITION TO ; DETERMINE IF OVERFLOW OCCURRED (RESULT WOULD ; BE CONVERTED TO SINGLE PRECISION ; LD A,2 ; TYPE CODE FOR INTEGER LD (40AFH),02 ; SET TYPE TO INTEGER LD BC,(VAL1) ; FIRST QUANTITY LD HL,(VAL2) ; SECOND QUANTITY CALL 0B2DH ; DO INTEGER ADDITION RST 20H ; TEST FOR OVERFLOW JP M,OK ; RESULT IS INTEGER . ; RESULT IS NOT INTEGER . ; TEST FOR OTHER TYPES OK LD (SUM),HL ; SAVE INTEGER RESULT . . . VAL1 DEFW 125 ; 16 BIT INTEGER VALUE VAL2 DEFW 4235 ; 16 BIT INTEGER VALUE SUM DEFW 0 ; HOLDS 16 BIT VALUE

jump to an interrupt processor in SYS0 if it is a DOS system. For DOS systems the interrupt handler consists of a task scheduler, where the exact cause of the interrupt is determined (usually a clock interrupt) and the next task from the task control block is executed. After task completion, control returns to the point of interrupt.
; ; ; ; ; ; INTERCEPT ALL CLOCK INTERRUPTS AND TEST THE WIDGET ON PORT AB. IF THE READY LINE (BIT 8) IS TRUE (HIGH OR A 1) TURN OH THE COFFEE POT ON PORT DE. THEN JUMP TO THE NORMAL DOS INTERRUPT HANDLER ORG JP ORG DI PUSH IN OR JP POP JP TOCP LD OUT POP JP . . . 4012H HERE 0FD00H AF A,(0ABH) A M,TOCP AF 4518H A,21H (0DEH),A AF 4518H ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; REPLACE THE JUMP TO THE DOS INTERRUPT PROCESSOR WITH A JUMP TO OUR OWN. OUR INTERRUPT HANDLER DISABLE FURTHER INTERRUPTS WE'LL NEED AF REGS GET WIDGET STATUS SET STATUS FOR BIT 8 WIDGET ON IF MINUS WIDGET OFF, RST REGS GO TO DOS INTERRUPT HANDLER CODE TO TURN ON COFFEE POT SEND COMMAND TO POT THEN RST REGS AND GO TO DOS INTERRUPT HANDLER

HERE

RST 28

DOS Function CALL

Passes request code in A-register to DOS for processing. Returns for non-disk system. For disk systems, the Aregister must contain a legitimate DOS function code. If the code is positive, the CALL is ignored and control returns to the caller. Note that the DOS routine discards the return address stored on the stack by the RST instruction. After processing control will be returned to the previous address on the stack. The calling sequence is:
; ; LOAD AND EXECUTE DEBUG ; LD A,87H CALL DOS . . DOS RST 28H . .

CALL 09B4

Move SP Value In BC/DC Into WRA1

; DOS CODE FOR LOADING DEBUG ; RETURN HERE ; MAKE DOS CALL (WILL RET TO CALLER)

Moves the single precision value in BC/DE into WRA1. HL is destroyed BC/DE is left intact. Note - the mode flag is not updated!
. . LD LD BC,(PART1) DE,(PART2) ; ; ; ; ; ; ; ; ; GET FIRST ARGUMENT REMAINDER OF ARGUMENT NOTE - WE HAVE ASSUMED THAT WRA1 CURRENTLY CONTAINS A SINGLE PRECISION VALUE !!! MOVE PART1 TO WRA1 GET VALUE TO BE ADDED REST OF VAL MOVE RESULT (SUM) TO WRAS

RST 30

Load DEBUG
PART2 PART1 PART4 PART3

CALL LD LD CALL . . DEFW DEFW DEFW DEFW . . .

09B4H BC,(PART3) DE,(PART4) 0716H

This CALL loads the DEBUG program and transfers control to it. When DEBUG processing is complete, control is returned to the original caller. For non-disk systems control is returned immediately.
; ; IF ILLOGICAL CONDITION ARISES LOAD AND EXECUTE DEBUG. . ; TEST FOR LEGITIMATE CONDITIONS . . JR Z,OK ; JMP IF CONDITIONS ARE CORRECT RST 30H ; ELSE LOAD AND EXECUTE DEBUG OK . ; CONTINUE . .

0000H 8140H 0000H 0000H

; ; ; ;

LSB OF SP 1.5 EXPONENT AND MSB OF SP 1.5 LSB OF SP XX EXPONENT/MSB OF SP XX

CALL 09B1

Moves A SP Value Pointed To By HL To WRA1

Loads a single precision value pointed to by HL into BC/DE and then moves it to WRA1. Destroys HL/BC/DE.

RST 38

Interrupt Entry Point

This is the system entry point for all interrupts. It contains a jump to section of code in the Communications Region designed to field interrupts. That section of code consists of a DI (disables further interrupts) followed by a RET (returns to the point of interrupt) for non-disk systems, or a

VAL

. . LD CALL . . . DEFW DEFW . . .

HL,VAL 09B1H

; GET ADDR OF VALUE TO MOVE ; MOVE VALUE TO WRA1

8140H 0000H

; SINGLE PREC 1.5 ; REMAINDER OF 1.5

28

CALL 09C2

Load A SP Value Into BC/DE

Loads a single precision value pointed to by HL into BC/DE. Uses all registers.
; ; COMPUTE THE PRODUCT OF TWO SP NUMBERS AND MOVE THE ; PRODUCT TO BC/DE. ; LD HL,VAL1 ; ADDR OF VALUE 1 CALL 09B1H ; MOVE IT TO WRA1 LD HL,VAL2 ; ADDR OF VALUE 2 CALL 09C2H ; LOAD IT INTO BC/DE LD BC,(4121H) ; LOAD EXPONENT/MSB LD DE,(4123H) ; LOAD LSB . . . VAL1 DEFW XXXX DEFW XXXX VAL2 DEFW XXXX DEFW XXXX . . . NSUB

VAL1 VAL2 VAL3

LD CALL LD CALL CALL CALL CALL . . . . POP LD LD CALL POP POP CALL LD JP DEFW DEFW DEFW DEFW DEFW DEFW . .

HL,VAL1 09B1H HL,VAL2 09C2H 0716H 09A4H NSUB

; ; ; ; ; ; ;

ADDR OF VALUE TO MOVE TO WRA1 MOVE VAL1 TO WRA1 ADDR OF VALUE TO BE ADDED LOAD VALUE TO BE ADDED TO BC/DE DO SINGLE PRECISION ADD SAVE SUM ON STACK CALL NEXT SUBROUTINE

; RETURN WITH NEW VALUE IN ; IN WRA1. HL (RET),HL HL,VAL3 09B1H BC DE 0716H HL,(RET) (HL) 0000H 8200H 00000 8320H 0AA6CH 7FAAH ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; GET RETURN ADDR MOVE IT TO A SAFE PLACE ADDR OF QUANTITY TO ADD MOVE VAL3 TO WRA1 GET EXPONENT/MSB GET LSB ADD TO VALUE PASSED GET RETURN ADDR AND RET TO CALLER LSB OF S.P 2.0 EXPONENT/MSB OF S.P 2.0 LSB OF S.P. 5.0 EXPONENT/MSB OF S.P. 5.0 LSB OF S.P. -.333333 EXPONENT/MSB OF S.P. -.33333

CALL 09BF

Loads A SP Value From WRA1 Into BC/DE

CALL 09D7

General Purpose Move

Loads a single precision value from WRA1 into BC/DE. Note, the mode flag is not tested by the move routine. It is up to the caller to insure that WRA1 actually contains a single precision value.
. . LD CALL LD CALL CALL CALL LD LD . . . DEFW DEFW DEFW DEFW DEFW DEFW . . .

Moves contents of B-register bytes from the address in DE to the address given in HL. Uses all registers except C.
; ; BLANK FILL A DCB THEN MOVE A NAME INTO IT ; LD A,20H ; HEX VALUE FOR BLANK LD B,32 ; NO. OF BYTES TO BLANK LD DE,IDCB ; DE = ADDR OF DCB LOOP LD (DE),A ; STORE A BLANK INTO DCB INC DE ; BUMP STORE ADDR DJNZ LOOP ; LOOP TILL DCB BLANKED LD DE,NAME ; NOW, MOVE FILE NAME TO IDCB LD HL,IDCB ; DE = NAME ADDR, HL = DCB ADDR LD B,LNG ; NO. OF CHARS IN NAME TO MOVE CALL 09D7H ; MOVE NAME TO DCB . . . IDCB DEFS 32 ; EMPTY DCB LNG EQU ENDX-$ ; LET ASSEMBLER COMPUTE LNG OF ; FILE NAME NAME DEFM 'FILE1/TXT' ; NAME TO BE MOVED TO DCB ENDX EQU $ ; SIGNAL END OF NAME . .

HL,VAL1 09B1H HL,VAL2 09C2H 0716H 09BFH (SUM1),DE (SUM2),BC

; ; ; ;

ADDR MOVE ADDR LOAD

OF VALUE TO MOVE TO WRA1 VAL1 TO WRA1 OF VALUE TO BE ADDED VALUE TO BE ADDED TO BC/DE

; DO SINGLE PRECISION ADD ; LOAD RESULT INTO BC/DE ; SAVE LSB ; SAVE EXPONENT/MSB

SUM1 SUM2 VAL1 VAL2

0 0 0000H 8200H 00000 8320H

; ; ; ; ; ;

HOLDS LSB OF SINGLE PRECISION HOLDS EXPONENT/MSB LSB OF S.P 2.0 EXPONENT/MSB OF S.P 2.0 LSB OF S.P. 5.0 EXPONENT/MSB OF S.P. 5.0

CALL 0982

Variable Move Routine

CALL 09A4

Move WRA1 To Stack

Moves the number of bytes specified in the type flag (40AF) from the address in DE to the address in HL, uses registers A, DE, HL.
; ; LOCATE THE ADDRESS OF A DOUBLE PRECISION VARIABLE ; THEN MOVE IT TO A LOCAL STORAGE AREA. ; LD HL,NAME1 ; NAME OF VARIABLE TO LOCATE CALL 260DH ; GET ADDR OF STRING X RST 20H ; MARE SURE IT'S DBL PREC. JR NC,OK ; JMP IF DBL PREC. JP ERR ; ELSE ERROR OK LD HL,LOCAL ; HL - LOCAL ADDR ; DE - VARIABLE ADDR CALL 0982H ; MOVE VALUE FROM VLT TO LOCAL ; AREA. . . . ERR . . NAME1 DEFM 'X' ; NAME OF VARIABLE TO LOCATE DEFB 0 ; MUST TERM WITH A ZERO LOCAL DEFS 8 ; ENOUGH ROOM FOR DBL PREC. VALUE . . .

Moves the single precision value in WRA1 to the stack. It is stored in LSB/MSB/Exponent order. All registers are left intact. Note, the mode flag is not tested by the move routine, it is simply assumed that WRA1 contains a single precision value.
; ; ; ; ; ;

ADD TWO SINGLE PRECISION VALUES TOGETHER AND SAVE THE SUM ON THE STACK. CALL A SUBROUTINE WHICH WILL LOAD THE VALUE FROM THE STACK, PERFORM IT'S OWN OPERATION AND RETURN.

29

CALL 29C8

String Move

On entry, HL points to the string control block for the string to be moved, and DE contains the destination address. All registers are used. The string length and address are not moved. String control blocks have the format:
DEFB DEFW X ADDR STRING LENGTH STRING ADDRESS

; ; ; ; ; ; ;

LOCATE THE ADDRESS OF BASIC STATEMENT NUMBER 750 IN THE PST. IF THE LINE DOES NOT EXIST RETURN A STATUS OF -1 IF IT IS LARGER THAN ANY CURRENT LINE NUMBER, OR A -2 IF IT THERE ARE LINES GREATER THAN 750. IF THE LINE IS FOUND RETURN A STATUS OF ZERO. . LD CALL JR LD ADD DE,750 1B2CH NC,NO HL,3 HL,BC ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; LINE NUMBER TO SEARCH FOR SEEK LINE IN PST NC SET IF LINE NOT THERE INCREMENT TO STEP OVER POINTER TO NEXT LINE/LINE NO. RST BELOW WILL INCREMENT BEFORE LOADING FETCH FIRST CHAR OF STATEMENT. SIGNAL LINE FOUND RETURN TO CALLER JMP IF LINE NO. TOO BIG SIGNAL LINE NOT THERE RETURN TO CALLER SIGNAL LINE NOT THERE TOO BIG RETURN TO CALLER

RST ; ; LOCATE THE ADDRESS OF A STRING VARIABLE CALLED F$. ; MOVE THE STRING F$ TO A LOCAL STORAGE AREA CALLED DCB. ; LD HL,NAME ; NAME OF VARIABLE TO LOCATE CALL 260DH ; FIND ADDR OF STRING F$ RST 20H ; MAKE SURE IT'S A STRING JR Z,OK ; JMP IF STRING JP ERR ; ELSE ERROR OK LD A,(DE) ; GET LENGTH OF STRING CF 33 ; WHICH MUST BE < 33 JP P,ERR ; ERR, STRING LNG > 32 PUSH DE ; SHORTCUT FOR MOVING DE TO BL POP HL ; ADDE OF STRING TO HL LD DE,LOCAL ; DE - LOCAL ADDR CALL 29C8H ; MOVE STRING VARIABLE TO ; LOCAL AREA . ERR . . NAME DEFM 'F$' ; NAME OF VARIABLE TO FIND DEFB 0 ; REQUIRED TO TERM NAME LOCAL DEFS 32 ; LOCAL STORAGE AREA . . . . . LD RET JR LD RET LD RET

10H

A,0 NC,M2 A,0FFH A,0FEH

NO M2

CALL 260D

Find Address Of Variable

Basic Functions
Basic Functions differ from System Functions because they deal mainly with tables in the Communications Region (CR). Because of this, these entry points assume that the CR has been initialized and properly maintained. This means that the BASIC Interpreter must have been entered prior to calling any of these routines, and the BASIC utility in RAM must be intact. The assembly program making the CALL must be running as a subroutine called by a BASIC program. For a complete description of the tables and storage areas in the Communication Region see chapter 4.

This entry point searches the Variable List Table (VLT) for a variable name which matches the name in the string pointed to by HL. If the variable exists, its address is returned in DE. If it is not defined, then it is created with an initial value of zero and its address is returned in DE. Dimensioned and non-dimensioned variables may be located, and suffixes for data mode may be included in the name string. A byte of machine zeros must terminate the name string. All registers are used.
; ; LOCATE THE ADDRESS OF THE VARIABLE A3 ; LD HL,STRNG ; NAME OF VARIABLE TO LOCATE CALL 260DH ; FIND IT'S ADDRESS IN VLT LD (ADDR),DE ; SAVE FOR FUTURE REFERENCE . . STRNG DEFM 'A3' ; VARIABLE NAME IS A3 DEFB 0 STRNG DEFM 'A(25)' ; VARIABLE NAME IS A(25) DEFB 0 STRNG DEFM 'A%' ; VARIABLE NAME IS A% DEFB 0

CALL 1B2C

Search For Line Number

Searches the Program Statement Table (PST) for a BASIC statement with the line number specified in the DE register pair. All registers are used. The exit conditions are:
STATUS C/Z NC/Z NC/NZ CONDITION REGISTERS LINE FOUND. BC = STARTING ADDRESS OF LINE IN PST. HL = ADDRESS OF FOLLOWING LINE IN PST. LINE DOES NOT EXIST. LINE NUMBER TOO LARGE HL/BC = ADDRESS OF NEXT AVAILABLE LOCATION IN LINE DOES NOT EXIST. BC = ADDRESS OF FIRST LINE NUMBER GREATER THAN THE ONE SPECIFIED. HL - ADDRESS OF FOLLOWING LINE.

30

CALL 1EB1

GOSUB
300 GOSUB 1500 310 GOSUB 1510 320 . . . 1500 Z=USR1(0) 1510 Z=USR2(0) 1530 . . . CALL BASIC SUBROUTINE RETURN HERE FROM SUBROUTINE CALL

Can be used to execute the equivalent of a GOSUB statement from an assembly program. It allows a BASIC subroutine to be called from an assembly subroutine. After the BASIC subroutine executes, control returns to the next statement in the assembly program. All registers are used. On entry, the HL must contain an ASCII string with the starting line number of the subroutine.
; ; SIMULATE A GOSUB STATEMENT FROM AN ASSEMBLY LANGUAGE PROGRAM ; LD HL,STRNG ; ADDRESS OF BASIC LINE NUMBER TO GOSUB TO CALL 1EB1H ; EQUIVALENT OF A GOSUB 1020 . . ; WILL RETURN HERE WHEN BASIC PROGRAM . ; EXECUTES A RETURN . STRNG DEFM '1020' ; LINE NO. OF BASIC SUBROUTINE DEFB 0

CALL ASSEMBLY SUBROUTINE & RETURN CALL ANOTHER SUBROUTINE & RETURN

; ; ENTRY POINT FOR USR1 SUBROUTINE ; . ; DO WHATEVER PROCESSING IS . ; REQUIRED . POP AF ; CLEAR RETURN ADDR TO 1510 ; FROM STACK JP 1EDFH ; RETURN DIRECTLY TO 310 ; ; ENTRY POINT FOR USR2 SUBROUTINE ; . ; PERFORM NECESSARY PROCESSING . ; FOR USR2 CALL POP AF ; CLEAR RETURN ADDR TO 1520 JP 1EDFH ; RETURN DIRECTLY TO 320

CALL 1DF7

TRON CALL 28A7 Write Message

Turns TRON feature on. Causes line numbers for each BASIC statement executed to be displayed. Uses Aregister.
; ; TURN TRACE ON THEN EXECUTE A BASIC SUBROUTINE ; CALL 1DF7H ; TURN TRACE ON LD HL,LN ; LINE NO. TO GOSUB CALL lEB1H ; DO A GOSUB 1500 . . . LN DEFM '1500' ; LINE NO. OF BASIC SUBROUTINE DEFB 0

Displays message pointed to by HL on current system output device (usually video). The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D. If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0 (JP 5B99). This subroutine uses the literal string pool table and the String area. It should not be called if the communications region and the string area are not properly maintained.
; ; WRITE THE MESSAGE IN MLIST TO ; OUTPUT DEVICE. ; LD HL,MLIST ; CALL 28A7H ; . . . MLIST DEFM 'THIS IS A TEST' DEFB 0DH ; . . .

THE CURRENT SYSTEM HL - ADDR OF MESSAGE SEND TO SYSTEM OUTPUT DEVICE

CALL 1DF8
Disables tracing feature. Uses A register.
; ; ENABLE TRACE. EXECUTE BASIC ; RETURN DISABLE TRACING. ; CALL 1DF7H ; LD HL,LN ; CALL 1EB1H ; CALL 1DF8H ; RET ; LN DEFM '2000' ; DEFB 0 SUBROUTINE. UPON

TROFF

THIS TERMINATOR REQUIRED

TURN TRACE ON LINE NO. OF BASIC SUBROUTINE DO A GOSUB 2000 TURN OFF TRACING RETURN TO CALLER LINE NO. OF BASIC SUBROUTINE

CALL 27C9 JP 1EDF RETURN

Return Amount Of Free Memory

Returns control to the BASIC statement following the last GOSUB call. An assembly program called by a BASIC subroutine may wish to return directly to the original caller without returning through the subroutine entry point. This exit can be used for that return. The return address on the stack for the call to the assembly program must be cleared before returning via 1EDF.

Computes the amount of memory remaining between the end of the variable list and the end of the stack. The result is returned as a single precision number in WRA1 (4121 4124).
; ; TAKE ALL AVAILABLE MEMORY BETWEEN THE STACK AND ; THE END OF THE VLT AND DIVIDE IT INTO REGIONS FOR ; USE IN A TOURNAMENT SORT ; . .

31

DI CALL CALL LD LD RST JR LD LD LD ADD LD . . . 27C9H 0A7FH DE,(4121H) HL,500 18H C,ERR HL,(40D1H) (EVLT),HL HL,0 HL,SP (ECSP),HL

; ; ; ; ; ; ; ; ; ; ; ; ; ;

MUST GO INHIBITED BECAUSE THERE WILL BE NO STACK SPACE FOR INTERRUPT PROCESSING GET AMT OF FREE SPACE CONVERT IT TO INTEGER GET IT INTO DE MAKE SURE IT'S AT LEAST 500 BYTES ERR - INSUFFICIENT SPACE START OF AREA SAVE FOR RESTORATION SO WE CAN LOAD CSP END OF AREA SAVE FOR RESTORATION

BASIC supports two forms of floating point numbers. One type is single precision and the other is double precision. Both types have a signed seven bit exponent. Single precision numbers have a signed 24 bit mantissa while double precision values have a signed 56 bit mantissa. Both types have the following format
Bit --> 31 24 23 16 15 8 7 0

CALL 2B75

Print Message

Sign of exponent: 0 = positive, move binary point to the right. 1 = negative, move binary point to the left.

Magnitude of the exponent. Number of bit positions to move binary point. Sign of mantissa: 0 = value positive 1 = value negative

Mantissa (value) is left justified (normalized) so that MS bit is on position # 23. If positive then bit 23 will be set to 1 during arithmetic operations. Negative values stored as positive, but with bit 23 on.

Writes string pointed to by HL to the current output device. String must be terminated by a byte of zeros. This call is different from 28A7 because it does not use the literal string pool area, but it does use the same display routine and it takes the same DOS Exit at 41Cl. Uses all registers. This routine can be called without loading the BASIC utility, if a C9 (RET) is stored in 41C1.
; ; WRITE MESSAGE TO CURRENT OUTPUT DEVICE ; LD HL,MLIST ; ADDRESS OF MESSAGE CALL 2B75H ; SEND MEG TO SYSTEM DEVICE . . MLIST DEFM 'THIS IS A TEST' DEFB 0 ; REQUIRED TERMINATOR . . .

The only difference between single and double precision is in the number of bits in the mantissa. The maximum number of significant bits representable in a positive single precision value is 2 ** 24-1 or 8 388 607 decimal or 7F FF FF hex. Double precision numbers have an extended mantissa so positive values up to 2 ** 56-1, or 3.578 X 10 ** 16 can be represented accurately. These numbers 8 388 607 and 3.578 X 10 ** 16 are not the largest numbers that can be represented in a single or double precision number, but they are the largest that can be represented without some loss of accuracy. This is due to the fact that the exponent for either type of number ranges between 2 ** -128 and 2 ** 127. This means that theoretically the binary point can be extended 127 places to the right for positive values and 128 to the left for negative values even though there are only 24 or 56 bits of significance in the mantissa. Depending of the type of data being used (the number of significant digits) this may be all right. For example Planck's constant which is 6.625 X 10 ** -34 J-SEC could be represented as a single precision value without any loss of accuracy because it has only four significant digits. However if we were totaling a money value of the same magnitude it would have to be a double precision value because all digits would be significant.

Internal Number Representation


BASIC represents integers as signed 16 bit quantities. Bit 15 contains the sign bit while bits 0-14 hold the magnitude. The largest possible positive value that can be represented is 32767 (dec.) or 7FFF (hex). The smallest possible negative value that can be represented is -32768 (dec.) or 8000 (hex).
Bit --> 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Sign: 0 = Positive 1 = Negative

Magnitude

positive values 0000 - 7FFF (hex.) : 0 to 32767 (dec.) Negative values FFFF - 8000 (hex.) : -l to -32768 (dec.) Note - negative values are represented as the one's complement of the positive equivalent.

32

Chapter 3

Cassette & Disk


This chapter contains an introductory description of physical I/O operations for the cassette and disk. The sample programs are for purposes of illustration only and are not recommended for adaptation to general applications. There may be special situations, however when a simple READ/WRITE function is needed and for limited applications they will serve the purpose. The distance between points A, B, C, and D is measured in units of time. Because time can be measured in machine cycles the value given for distances will be in machine cycles where one instruction (any instruction regardless of how long it is) equals one cycle and one cycle equals one microsecond. This is crude but workable. The sum of A B is supposed to be 2 milliseconds for Level II. Using the crudity described above and counting instructions used in the Level II software gives the following values.

Cassette I/O
Cassette I/O is unusual from several aspects. First, each byte is transmitted on a bit-by-bit basis under software control. This is radically different from all other forms of I/O where an entire byte is transferred at one time. For most I/O operations, referencing memory or executing an IN or OUT instruction, is all that is required to transfer an entire byte between the CPU and an external device. However, If the device is a cassette, each bit (of a byte to be transferred) must be transferred individually by the software. The second unusual aspect is the procedure used for transmitting these bits. Exact timing must be adhered to and the program must use different code depending on whether a binary zero or one is to be written. Each bit recorded consists of a clock pulse (CP) followed by a fixed amount of erased tape followed by either another CP if a binary one is represented, or a stretch of erased tape if a binary zero is being represented. A binary one and zero would appear as:

A B 1.4 millisec per half bit 2.8 millisec per bit. C .20 millisec * 2 per CP .40 millisec D 1.0 millisec Before discussing programming for cassette I/O in any detail we should review the fundamentals. Drive selection is accomplished by storing either a 01 (drive 1) or 02 (drive 2) in 37E4. Motor start and loading or clearing the data latch is achieved by sending a command value to the cassette controller on port FF. The command value is shown below.
7 6 5 4 3 2 1 0 x x x x x x x x Not used for cassette operations

: 00 - erase tape outsig 1 : 01 - positive signal outsig 2 : 10 - negative signal 1 = motor on 0 motor off 1 = 32 char/line 0 = 64 char/line

<-----Clock Pulse--------><-------Data Pulse-------> <---C---> <----D--->

<-------------A-----------><-------------B--------------> Binary One

33

Be careful to preserve the current video character size when sending commands to the cassette. The system maintains a copy of the last command sent to the video controller in 403D. Bit 3 of that word should be merged with any commands issued to the cassette. A write operation of one bit (called a bit cell) can be divided into two steps. First a clock pulse (CP) is written to signal the start of a bit. It is followed by a strip of erased tape which is considered part of the CP. Next, another CP is written if the bit is a one, or more blank tape is written if the bit is a zero. Read operations begin by searching for the clock pulse and skipping to the data pulse area. The data pulse area is then read returning a zero if blank tape was encountered or a one if non-blank tape was found. Below are examples of code that could be used for cassette operations. The code used by Level II can be found around the area 01D9 - 02A8 in the Level II listing.

SELECT UNIT AND TURN ON MOTOR LD A,01 ; LD (37E4H),A ; LD A,04 ; OUT (0FFH),A ;

CODE FOR UNIT 1 SELECT UNIT 1 COMMAND VALUE: TURN ON MOTOR START MOTOR, CLEAR DATA LATCH

Assembler Object Code Format


DOS loads disk object files with a utility program called LOAD. They can also be loaded under DOS by entering the name of a file that has an extension of CMD. The format of a disk object file is shown below. It is more complex than a cassette file because it has control codes embedded in the object code. The loader reads the file into a buffer before moving the object code to its designated address. The control codes are used to indicated to the loader where the code is to be loaded, how many bytes are to be loaded, and where execution is to begin.
Control Code: Count : Load Address: Load Data : 01 XX XX XX XX XX . 02 XX XX XX (data to be loaded follows) (count of bytes to load, 0 = 256) (load address in LSB/MSB order)

WRITE BYTE CONTAINED IN THE A REGISTER PUSH AF PUSH BC PUSH DE PUSH HL ; SAVE CALLERS REGISTERS LD L,8 ; NUMBER OF BITS TO WRITE LD H,A ; H = DATA BYTE LOOP CALL CP ; WRITE CLOCK PULSE FIRST LD A,H ; GET DATA BYTE RLCA ; HIGH ORDER BIT TO CARRY LD H,A ; SAVE REPOSITIONED BYTE JR NC,WR ; BIT WAS ZERO. WRITE BLANK TAPE CALL CP ; BIT WAS ONE. WRITE A ONE DATA PULSE TEST DEC L ; ALL BITS FROM DATA BYTES WRITTEN ? JR NZ,LOOP ; NO! JUMP TO LOOP POP HL ; YES! RESTORE CALLERS REGISTERS POP DE POP BC POP AF RET ; RETURN TO CALLER WR LD B,135 ; DELAY FOR 135 CYCLES (988 USEC) WHILE WR1 DJNZ WR1 ; BLANK TAPE IS BEING WRITTEN JR TEST ; GO TEST FOR MORE BITS TO WRITE CP LD A,05 ; COMMAND VALUE MOTOR ONE, OUTSIG 1 OUT (0FFH),A ; START OF CLOCK PULSE LD B,57 ; DELAY FOR 57 (417 USEC) CYCLES CP1 DJNZ CP1 ; GIVES PART OF CP LD A,06 ; COMMAND VALUE: MOTOR ON, OUTSIG 2 OUT (0FFH),A ; 2ND PART OF CLOCK PULSE LD B,57 ; DELAY FOR 57 CYCLES (417 USEC) CP2 DJNZ CP2 ; GIVES PART OF CP LD A,4 ; COMMAND VALUE: MOTOR ON, NO OUTSIG OUT (0FFH),A ; START ERASING TAPE LD B,136 ; DELAY FOR 136 CYCLES (995 USEC) CP3 DJNZ CP3 ; GIVES TAIL OF CLOCK PULSE RET ; RETURN TO CALLER READ NEXT BYTE XOR PUSH PUSH PUSH LOOP LD CALL POP HL DJNZ POP POP RET RB RB1 PUSH PUSH IN RLA JR LD DJNZ LD OUT LD DJNZ IN LD POP RL RLA PUSH LD OUT LD DJNZ POP POP RET FROM CASSETTE INTO A REGISTER A ; CLEAR DESTINATION REGISTER BC DR HL ; SAVE CALLERS REGISTERS B,8 ; NUMBER OF BITS TO READ RB ; READ NEXT BIT. ASSEMBLE INTO ; BYTE BUILT THUS FAR. LOOP DE BC ; LOOP UNTIL 8 BITS USED ; RESTORE CALLERS REGISTERS ; RETURN TO CALLER

BC AF (0FFH),A NC,RB1 B,57 RB2 A,04 (0FFH),A B,193 RB3 A,(0FFH) B,A AF B AF A,4 (0FFH),A B,240 RB4 BC AF

Control Code: Address :

(beginning execution address follows) (this byte is to be discarded) (execution address in (LSB/MSB order) RB2

Control Code: Count : Skip Data :

03 - 05 (following data is to be skipped) XX (count of bytes to skip) XX (this data is to be skipped) XX .

RB3

Cassette Recording Format


The recording format used by Level II is as follows:
1: BASIC Data Files 0 0 0 0 . . . 0 A5 ( 256 zeros ) Synch Bytes 2: BASIC Programs 0 0 0 0 . . . 0 A5 D3 D3 D3 Y X X X X . . X 00 00 00 Synch Bytes File Header Name 3: Absolute Assembler Programs 55 N N N N N N 3C Y ZZ X X X X . . . X C 78 TA Synch File name Start of binary file Transfer address Program or Data Transfer Checksum address follows Load address Number of bytes to load BASIC Program EOF Marker X X X X . . . X

Data Bytes RB4

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

READ DATA LATCH TEST FOR BLANK/NON-BLANK TAPE BLANK, SCAN TILL NON-BLANK IT WILL BE ASSUMED TO BE START OF A CLOCK PULSE. DELAY FOR 57 CYCLES WHILE SKIPPING OVER FIRST PART OF CP COMMAND VALUE: MOTOR ON, CLEAR DATA LATCHES DELAY FOR 193 CYCLES WHILE PASSING OVER END OF CP WE SHOULD BE POSITIONED INTO THE DATA PULSE AREA. READ THE DATA PULSE. SAVE DATA PULSE ACCUMULATED BYTE THUS FAR DATA PULSE TO CARRY WILL BE A ZERO IF BLANK TAPE, 1 IF NON-BLANK COMBINE NEW DATA PULSE (1 BIT) WITH REST OF BYTE AND SAVE COMMAND VALUE: MOTOR ON, CLEAR OUTSIG CLEAR DATA LATCHES DELAY LONG ENOUGH TO SKIP TO END OF DATA PULSE

; A = DATA BYTE

TURN OFF MOTOR LD A,00 OUT (0FFH),A RET

; COMMAND VALUE: MOTOR OFF ; TURN MOTOR OFF

34

Disk I/O
The disk operations discussed in this section are elementary in as much as there is no consideration given to disk space management or other functions normally associated with disk I/O. What is presented are the fundamental steps necessary to position, read, and write any area of the disk without going through DOS. It will be assumed that the reader is familiar with the I/O facility provided by DOS and is aware of the pitfalls of writing a diskette without going through DOS. Disks which normally come with a Model I system are single sided, 35 track 5 1/4' mini-drives. It is possible to substitute other drives with a higher track capacity such as 40, 77, or 80 tracks, but then a modified version of DOS must be used. Dual sided mini-drives are becoming available and eventually they should replace the single sided drives. Dual density drives are another type of minidrive that are available, but like the dual sided drives they require a modified version of DOS. The type of programming used in this example is called programmed I/O. It is called that because the program must constantly monitor the controller status in order to determine if it is ready to send or receive the next data byte. Thus each byte is transferred individually under program control. An alternative to programmed I/O is DMA or Direct Memory Access. Using this method the controller is told the number of bytes to transfer and the starting transfer address and it controls the transfer of data leaving the CPU free to perform other tasks. On the Model I systems there is no DMA facility so programmed I/O must be used. This example will assume that a DOS formatted diskette is being used. New diskettes are magnetically erased. Before they can be used they must be formatted. That is each sector and track must be uniquely identified by recording its track and sector number in front of the data area of each sector. There is some variability in the coded information which precedes each sector so it is not always possible to read any mini-diskette unless it originated on the same type of machine. Like most of the I/O devices on the Model I the disk is memory mapped. There are five memory locations dedicated to the disk. They are: 37E1 37EC 37ED 37EE 37EF Unit Select Register Command/Status Register Track Update Register Sector Register Data Register

Because of that, a request for status (load 37EC) cannot occur for 50 microseconds following the issuing a command (store 37EC). Unit selection is accomplished by storing a unit mask value into location 37E1. That mask has the format:
BIT Not Used 7 X 6 X 5 X 4 X 3 X 2 X 1 X 0 X 1 1 1 1 = = = = SELECT SELECT SELECT SELECT UNIT UNIT UNIT UNIT 0 1 2 3

More than one unit can be selected at a time. For example a mask of 3 would select units 0 and 1. When any unit is selected the motor on all units are automatically turned on. This function is performed automatically by the expansion interface.

Controller Commands
The Model I uses a Western Digital FD 1771B-01 floppy disk controller chip. It supports twelve 8-bit commands. They are: Restore: Positions the head to track 0
7 0 6 0 5 0 4 0 3 X 2 X 1 X 0 X Stepping rate: 00 = 6 mS / step 01 = 6 mS / step 10 = 10 mS / step 11 = 20 mS / step <-- Bit

00 01 10 11

= = = =

Mode No verify bead position Verify head position Not used Verify head position

Seek: Positions the head to the track specified in the data register (37EF).
7 0 Mode 6 0 5 0 4 1 3 X 2 X 1 X 0 X Stepping rate <-- Bit

Step: Moves the head one step in the same direction as last head motion.
7 0 6 0 5 1 4 X 3 X 2 X 1 X 0 X <-- Bit

All disk commands except for unit selection are sent to 37EC. If the command being issued will require additional information such as a track or sector number, then that data should be stored in the appropriate register before the command is issued. You may have noticed that the command and status register have the same address.

Track update 0 = No track register update 1 = Track register update

Stepping rate Mode

35

Step Head In: Moves the head in towards the innermost track one position.

Write Track: Writes a full track starting at the index mark and continuing until the next index mark is encountered.

Track update

Stepping rate Mode

Step Head Out: Moves the head out towards the outermost track one position

Force Interrupt: Terminates the current operation and / or generates an interrupt if one of the following four conditions is true:

1 0 1 1 X X X X X

X Terminate conditions: 00 = None 01 = Interrupt on ready 02 = Interrupt on not ready 04 = Interrupt on index pulse 10 = Hone

Track update

Stepping rate Mode

Read Data: Transmits the next byte of data from the sector specified by the value in the sector register.

Read Status: The status of the Floppy Controller is returned whenever location 37EC is read. The status word has the following format:

0 X X X X X X X X Read / Write Busy DRQ Lost Data CRC Error Missing Record 0 0 Not Ready Seek Busy DRQ Missing Address 0 0 0 Write Protect Not Ready

Multi-sector 0 = Read 1 Sect 1 = Multi-sector

Head settle: 0 = No delay 1 = 10 mS delay Format: 0 = Non IBM 1 = IBM

Write Data: Sends the byte of data in the data register to the next position in the sector specified by the value in the sector register.

Multi-sector 0 = Write 1 1 = Multi-sector Format 0 = Non IBM 1 = IBM

Address mark: 00 = FB, 01 = FA 10 = F9, 11 = F8 Head settle: 0 = Non 1 = 10 mS delay

Read Track: Reads an entire track beginning with the index mark.

Read Address: Reads the address field from the next sector to pass under the head.

36

Disk Programming Details


Disk programming can be broken down into several easily managed steps. They are:
1. Select the unit and wait for ready. 2. Position the head over the desired track. 3. Issue the Read/Write command for the required sector 4. Transfer a Sectors worth of data, on a byte at a time basis. Each transfer must be preceded by a test to see if the controller either has the next data byte, or is ready to accept the next data byte.

The term DOS Exit really has two different meanings. DOS Exits are calls from ROM BASIC to Disk BASIC while in the Input Phase, while executing a system level command, or while executing a verb action routine. These exits allow extensions to be made to the routines in ROM. The exits are not strategically located so that an entire ROM routine could be usurped, but they are conveniently placed for intercepting the majority of the ROM routine processing. Another type of DOS Exit is the Disk BASIC Exit. These exits are radically different from the other ones, they are only entered on demand when a Disk BASIC token is encountered during the Execution Phase. All of the processing associated with these tokens is contained in the Disk BASIC program. There is no code in ROM for executing these tokens. The following descriptions are for DOS Exits as opposed to Disk BASIC Exits. The calling sequence for each of the DOS Exits vary. Before writing a program to replace any of these Exits study the code around the CALL, paying particular attention to register usage. What happens at the exits is not discussed here. If it is important, disassemble the Disk BASIC utility program and examine the code at the BASIC address assigned to the exit. An example of how both types of Exits can be intercepted can be found in chapter 6. All these addresses are for NEWDOS 2.1, TRSDOS addresses will differ.
Level II ADDRESS DOS Exits BASIC ADDRESS ADDRESS 41A6 41A9 41AC 41AF 41B2 41B5 41B8 41BB 41BE 41C1 41C4 41C7 41CA 41CD 41D0 41D3 41D6 41DC 41DF 41E2 5679 5FFC 598E 6033 5BD7 5B8C 60A1 577C 59CD 59CD 5F78 51A5 5B9A 5B99 5B65 5784 5E63 579C 5B51

This program demonstrates a single sector read from track 25 (decimal), sector 3.
ORG LD PUSH LD LD LD LD LD LD 7000H BC,256 BC HL,BUFF A,1 (37E1H),A D,25 E,3 (37EEH),DE

LD LD LD DELAY DJNZ WAIT LD BIT JR LD LD LD DELAY1 DJNZ WAIT1 LD BIT JR LD LD INC DEC LD OR JR . . .

A,1BH (37ECH),A B,6 DELAY A,(37ECH) 0,A NZ,WAIT A,88H (37ECH),A B,6 DELAY1 A,(37ECH) 1,A Z,WAIT1 A,(37EFH) (HL),A HL BC A,B C NZ,WAIT

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

BYTE COUNT B = 1 C = 0 BUFFER ADDRESS UNIT SELECT MASK (DRIVE 0) SELECT DRIVE 0, START MOTOR TRACK NUMBER SECTOR NUMBER SPECIFY TRACK AND SECTOR TRACK NO. TO DATA REGISTER (37EFH) SECTOR NO. TO SECTOR REGISTER. SEEK OP CODE. NO VERIFY (FOR VERIFY 17H) SEEK REQ. TO COMMAND REGISTER. GIVE CONTROLLER A CHANCE TO DIGEST COMMAND BEFORE ASKING STATUS GET STATUS OF SEEK OF TEST IF CONTROLLER BUSY IF YES, THEN SEEK NOT DONE SEEK FINISHED. LOAD READ COMMAND AND SEND TO CONTROLLER GIVE CONTROLLER A CHANCE TO DIGEST COMMAND BEFORE REQUESTING A STATUS NOW, ASK FOR STATUS IS THERE A DATA BYTE PRESENT ? NO, WAIT TILL ONE COMES IN YES, LOAD DATA BYTE STORE IN BUFFER BUMP TO NEXT BUFF ADDR TEST FOR 256 BYTES TRANSFERRED COMBINE B AND C TO TEST BOTH REGISTERS GO GET NEXT BYTE

DESCRIPTION

DOS Exits
DOS Exits were discussed in general terms in chapter 1. They are used as a means of passing control between Level II BASIC and Disk BASIC. The Exit itself is a CALL instruction in the ROM portion of the system to a fixed address in the Communications Region. Contained at that CALL'd address will be either a RETURN instruction or a JUMP to another address in Disk BASIC. On a Level II system without disks these CALL'd locations are set to RETURNS during IPL processing. On disk based systems they are not initialized until the BASIC command is executed. At that time JUMPS to specific addresses within Disk BASIC are stored at the CALL locations.

19EC ..... Call to load DISK BASIC error ...... processing. Error number most be in B-register. 27FE ..... Start of USR processing ............ 1A1C ..... BASIC start up. Just before ........ BASIC's 'READY' message. 0368 ..... At start of keyboard input ......... 1AA1 ..... Input scanner after tokenizing ..... current statement. 1AEC ..... Input scanner after updating ....... program statement table. 1AF2 ..... Input scanner after reinitial- ..... izing BASIC. 1B8C/1DB0 Initializing BASIC for ............. new routine. During END processing. 2174 ..... During initializing of syatena ..... output device. 032C ..... During writing to system output .... device. 0358 ..... When scanning keyboard. Called ..... from INKEY$, at end of execution of each BASIC statement. 1EA6 ..... At start of RUN NNN ................ processing. 206F ..... At beginning of PRINT .............. processing. 20C6 ..... During PRINT # or PRINT ............ item processing. 2103 ..... When skipping to next line on ...... video during a BASIC output operation. 2108/2141 At start of PRINT on cassette ...... and during PRINT TAB processing. 219E ..... At beginning of INPUT processing ... 222D ..... During READ processing when a ...... variable has been read. 2278/2278 At end of READ processing .......... 2B44/2B44 From LIST processing 02B2 ..... During SYSTEM command operation ....

37

Disk BASIC Exits


These exits are made from Level II during the Execution Phase whenever a token in the range of BC - FA is encountered. Tokens with those values are assigned to statements which are executed entirely by Disk BASIC. When a token in the given range is found control is passed indirectly through the Verb Action Routine List (see chapter 4) to the appropriate Disk BASIC Exit in the Communications Region. Control is returned to Level II at the end of the verb routine's processing.
TOKEN VERB CR ADDRESS 4152 4155 4158 415B 415E 4161 4164 4167 416A 4160 4170 4173 4176 4179 417C 417F 4182 4185 4188 418B 418E 4191 4194 4197 419A 4190 41A0 41AD 41A9 DISK BASIC ADDRESS 5E46 558E 5E49 5655 5E4C 61E8 6231 6242 5E20 5E30 5E33 56C4 5714 6349 60AB 627C 627B 606F 5F7B 60DB 6346 63C0 5887 60E6 60E5 582F 6044 5756 5679

Eight inch drives are essentially the same as 5 1/4' drives except they usually only come in one track size (77 tracks). As with the smaller units they come in both single and dual density. Since their radius is larger they have more sectors per track. Track capacities for 8' drives are typically: 26 - 128 byte sectors / track; 15 - 256 byte sectors / track; 8 - 512 byte sectors / track; 4 - 1024 byte sectors / track. Track capacities for 5 1/4' single density are: 20 - 128 byte sectors / track; 10 - 256 byte sectors / track; 5 - 512 byte sectors / track; and 2 - 1024 byte sectors / track. Dual density 5 1/4' drives have capacities of: 32 - 128 byte sectors / track; 18 - 256 byte sectors / track; 08 - 512 byte sectors / track; and 4 - 1024 byte sectors / track. Hard disks are too varied to classify. Basically a hard disk has more capacity, faster access time, higher transfer rates, but the disk itself may not be removable. Without a removable disk file backup can be a serious problem, a second hard disk is an expensive solution. Shown below is a diagram of a 5 1/4' 35 track diskette.

E6 .......... BE .......... E7 .......... B0 .......... E8 .......... E9 .......... EA .......... EB .......... EC .......... ED .......... EE .......... 85 .......... C7 .......... A2 .......... A3 .......... A4 .......... A5 .......... A6 .......... A7 .......... A8 .......... A9 .......... AA .......... NONE ........ AB .......... AC .......... C5 .......... AD .......... 9C .......... C1 ..........

CVI .......... FN ........... CVS .......... DEF .......... CVD .......... EOF .......... LOC .......... LOF .......... MKI$ ......... MKS$ ......... MKD$ ......... CMD .......... TIME$ ........ OPEN ......... FIELD ........ GET .......... PUT .......... CLOSE ........ LOAD ......... MERGE ........ NAME ......... KILL ......... & ............ LSET ......... RSET ......... INSTR ........ SAVE ......... LINE ......... USR ..........

.......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... .......... ..........

Disk Tables
The most frequently used disks on the Model I series are 5 1/4' single sided single density mini-floppy drives. A variety of other units are available and could be used, however some hardware and software modifications would be necessary. Examples of other units would be: 5 1/4' dual headed and dual density drives; 8' single and dual headed plus single and dual density units; and various hard disks with capacities up to 20 Mbytes. The terms single and dual headed refer to the number of read/write heads in a unit. Most microcomputer systems use single headed drives but dual headed drives are now becoming more commonplace. A dual headed drive has twice the capacity of a single headed unit because two disk surfaces can be accessed rather than one. Dual density describes the recording method used. In single density mode each bit cell consists of a clock pulse followed by a data pulse while in dual density recording clock pulses may be omitted if the data pulse is repetitious. Using this method more sectors can be written on a track than in single density format. The recording method used is dictated by the controller and the software, but with dual density drives clock pulses may be omitted and the timing is more critical, hence not all drives can be used for dual density.

Each diskette has 35, 40, 77, or 80 tracks depending on the drive used. Each track has 10 sectors of 256 bytes. Sector sizes can vary from 2 to 1024 bytes per sector. But the software must be modified to handle anything other than 256, because that is the size assumed by DOS. The Model I uses a semi IBM compatible sector format. It is not 100% compatible because track and sector numbers on IBM diskettes are numbered from 1 not 0 as in TRSDOS. DOS uses a file directory to keep a record of file names and their assigned tracks and sectors. The directory occupies all 10 sectors of track number 11. It is composed of three parts: a disk map showing available sectors (track 11, sector 1); a file name in use index that allows the

38

directory to be searched from an advanced starting point (called the Hash Index Table track 11, sector 2); and the directory sectors themselves (track 11 sector 3 thru track 11 sector 10).
Track 11H Sector 0 GAT Sector

disk space on an as-needed basis. Conversely, it must be possible to reuse space which has been released and is no longer needed. The basic vehicle used for keeping track of assigned and available disk space is the Granule Allocation Table (GAT). Obviously, GAT data must be stored outside the machine if a permanent record is to be maintained. The GAT sector is used for this storage. With the disk description there was a definition for a track and sector. These terms will now be re-defined into the DOS term granule. A granule is 5 sectors or half of a track. It is the minimum unit of disk space that is allocated or deallocated. Granules are numbered from 0 to N, where N is a function of the number of tracks on a diskette. A record of all granules assigned is maintained in the GAT sector. Recalling the disk dimensions mentioned earlier we can compute the number of granules on a diskette as:
Granule = (Number of tracks * 10) / 5

Sector 1

HIT Sector

Sector 2 . . Sector 9

Directory Sector

Directory Sector

As well as the directory track there is one other special area on a diskette. Track 0 sector 0 contains a system loader used during the disk IPL sequence to load DOS. The loader is read into RAM locations 4200 - 4300 by the ROM IPL code which then passes control to it so that the DOS can be loaded.

Using a 35 track drive with the default DOS disk values of 10 sectors per track and 5 sectors per granule this gives 70 granules per diskette. The GAT sector is divided into three parts. The first part is the actual GAT table where a record of GAT's assigned is maintained. Part two contains a track lock out table, and part three system initialization information.
Relative Byte 0

Disk Track Format


Before any diskette can be used it must be initialized using either the FORMAT or COPY (BACKUP if using TRSDOS) utility programs. Formatting initializes the diskette which is originally magnetically erased. The formatting operation writes the sector addresses for every addressable sector plus synch bytes which will be used by the controller to aid it locating specific addresses. In addition the formatting operation specifies the sector size, the number of sectors per track, and the physical order of the sectors Mini-floppies are usually formatted with 128,256,512, or 1024 byte sectors although other sizes may be formatted. DOS uses the following track format:
Position Index Number of Bytes 14 6 1 1 1 1 1 Contents FF 00 FE (Address marker) Track Number Head Number Sector Number Sector Length Code 00 = 128 bytes 01 = 256 bytes 02 = 512 bytes 03 = 1024 bytes CRC FF : Sector 0 only, 12 A0 : bytes of FF all others FA (Data Field Mark) Data CRC FF : Except the last (9) 00 : which is followed by 130 bytes of FF

-->

Granule Byte track 0 . . Granule byte track 95

60 -->

Lockout byte for track 0 . . Lockout byte for track 95

CE --> D0 --> D8 --> E0 --> F0 --> Password (2 bytes) Disk Name (8 bytes) Creation Date (8 bytes) AUTO procedure (32 bytes) Not used

One Sector Ten per track. Sector order is 0,5,1,6, 2,7,3,8, 4,9.

Track available 1 1 1 1 1 1 0 0 Locked out 1 1 1 1 1 1 1 1 Lockout byte (1 per track) Granule 1 1 1 1 1 1 X X Allocation .... Sectors 0 - 4 Byte (1 per track) :..... Sectors 5 - 9 0 = Assigned 1 = Available

2 11 1 1 256 2 12 6 FE

Hash Index Table

(Track 11 Sector 2)

GAT Sector

(Track 11 Sector 1)

Previously we mentioned the file directory system used by DOS. It is based in part on the ability to dynamically assign

The Hash Index is a method used to rapidly locate a file without searching all of the directory sectors until it is found. Each file has a unique value computed from its name. This value is called the Hash Code. A special sector in the directory contains the Hash Codes for all active files

39

on a diskette. When a file is created, its Hash Code is stored in the hash sector in a position that corresponds to the directory for that file. Note, the hash position does not give the file position, just its directory sector position. When a file is KILL'd it code is removed from the hash sector. Files are located by first computing their hash value, the Hash Index Sector is then searched for this value. If it is not found then the file does not exist. If the code is found then its position in the Hash Index Sector is used to compute the address for the directory sector containing the file name entry. Hash code values range from 01 to FF. They are computed from an 11 character file name that has been left justified, blank filled. Any file name extension is the last three characters of the name. The code used for computing a hash value is shown below:
LD LD LD INC XOR RLCA LD DJNZ LD OR JMP INC . B,11 C,0 A,(DE) DE C C,A LOOP A,C A DONE A ; ; ; ; ; ; ; ; ; ; ; ; ; NO. OF CHARS TO NASH ZERO HASH REGISTER GET ONE CHAR OF NAME BUMP TO NEXT CHAR HASH REG. XOR. NEXT CHAR 2*(NR. XOR. NC) NEW HR HASH ALL CHARS GET HASH VALUE DON'T ALLOW ZERO EXIT, HASH IN A FORCE HASH TO 1 EXIT, HASH IN A

Disk DCB
Each disk file has associated with it a 32 byte DCB which is defined in the user's memory space. When the file is opened the DCB must contain the file name, a name extension if any, and an optional drive specification. As part of the OPEN processing the DCB is initialized for READ and WRITE operations by copying portions of the directory entry into the DCB. After initialization the DCB appears as shown.

LOOP

DONE

Space for codes in the Hash Sector is assigned sequentially beginning at an arbitrary point. If the hash sector is full a DOS error code of 1A is given otherwise the sector is scanned in a circular manner until the first available (zero) entry is found. Not all words in the Hash Sector are used. Addresses in the range 10 - 1F, 30 - 3F, 50 - 5F are excluded. Only those addresses ending in the digits 00-07, 20-27 etc are assigned. This speeds the computation of the directory sector number from the hash code value address. The Hash Sector is shown below.
Relative Byte 00 --> 01 --> 02 --> 07 --> 10 --> 1F --> 20 --> 27 --> 30 --> 37 --> Not Used . . HASH codes for files in sector 3 of directory track Zero or Hash code . . . . Not Used HASH codes for files in sector 2 of directory track

Relative Byte 0 1 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F

Open flag Access flags Reserved Sector buffer addr Next record addr Drive number Overflow pointer EOF address Record size Next record # Number of records 1st GAP Total granules thru 1st GAP 2nd GAP Total granules thru 2nd GAP 3rd GAP Total granules thru 3rd GAP 4th GAP Total granules thru 4th GAP End of GAP Flag

where

BYTE

bits 0-6 : reserved bit 7 : 0 = file not opened 1 = file opened bits 0-2 : access permission flag. bit 3 : reserved bit 4 : 0 = sector buffer available 1 = flush sector buffer before using bit 5 : 0 = look for record in current buffer 1 = unconditionally read next sector bit 6 : reserved bit 7 : 0 = sector I/O 1 = logical record I/O reserved sector buffer address in LSB/MSB order pointer to next record in buffer drive number bits 0-3 sector number - 2 of overflow entry bits 3-4 reserved bits 5-7 offset/16 to primary entry in directory pointer to end of file in last sector record size next record number in LSB/MSB format number of records in file first GAP total granules assigned thru first second GAP total granules assigned thru second GAP third GAP total granules assigned thru third GAP fourth GAP total granules assigned thru fourth GAP end of GAP string flag (FFFF)

BYTE

BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE

2 3 - 4 5 6 7 8 9 10 12 14 16 18 20 22 24 26 28 30

F0 --> Not Used FF -->

Sector 4

11 13 15 17 19 21 23 25 27 29 31

40

Directory Sector

(Track 11 Sector 3 Track 11 Sector 9)

BYTE 0

Directory sectors contain file descriptions used when accessing a disk file. These descriptions contain among other things the file name, passwords, and a list of the disk addresses occupied by the file. The directory sectors are divided into eight fixed-length partitions of thirty two bytes each. Each partition contains one file description. Empty partitions are indicated by a flag in the first byte of the partition. Space in the directory is assigned when a file is initially created using a DOS OPEN or INIT call. There is no particular order in the way space is assigned because the directory sector number used is determined by a hash code derived from the file name. Partition space in the sector is assigned in sequential order.

bits 000 001 010 011 100 101 110 111 bit3 bit4 bit5 bit6 bit7

0-2 = file access control flags unrestricted access KILL/RENAME/WRITE/READ/EXECUTE access RENAME/WRITE/READ/EXECUTE access reserved WRITE/READ/EXECUTE access READ/EXECUTE access EXECUTE access only restricted file no access 0, file is displayable. 1, file is invisible. 0, this entry is available. 1, entry is used. reserved 0, user file. 1, SYSTEM file. 0, primary entry. 1, overflow entry.

= = = = =

BYTE

BYTE BYTE BYTE BYTES BYTES BYTES BYTES BYTES BYTES

used for overflow entries only. Bits 0 - 3 byte offset/10 in primary sector to the entry for this file Bits 4 - 7 sector number - 2 of primary entry. 2 Reserved 3 Bits 0 - 7 byte offset to end of file in last sector. 4 Bits 0 - 7 record length. 12 15 17 19 21 31 File name in ASCII, left justified, blank filled. File name extension in ASCII left justified, blank filled. Update password (encoded). Access password (encoded). Last sector number in file. LSB/MSB order. Five two-byte entries called Granule Assignment Pairs (GAPs). Each GAP consists of a starting track number (byte 1) and a count of the number of consecutively assigned granules (byte 2). A string of these GAP's in proper order define the disk addresses assigned to a file. The end of a GAP string will be signaled by a FF in bytes 1 and 2 if there are no more than five GAP assigned, or an FE followed by the disk address of another directory sector containing the remainder of the GAP's. The directory entry containing the overflow GAP's is called an overflow entry and contains only the continuation of the GAP string. There is no limit to the number of overflow entries that may be assigned. GAP bytes are formatted as shown below

5 13 16 18 20 22

Relative Byte

0 20

Entry # 1 ------------Entry # 2 ------------------------Entry # 8

E0

1st Byte: Bits 0 - 7 contain one of the following: a) If the contents of 1st byte is less than FE it is assumed to be a track number. b) An FF if there are no more GAP's. This is the end of a GAP string c) An FE if there are more GAP entries in an overflow sector. The next byte contains the overflow sector address. 2nd Byte: The interpretation of this byte depends on the contents of the preceding byte. If = FF, then this byte is not contains an FF. If preceding byte = FE, then: holds in bits 0 - 3 the sector number - 2 of overflow sector. bits 4 - 7 the byte offset/10 in the overflow sector to the entry with the remainder of the GAPs'. If preceding byte < FE, then this byte has in bits 0 - 3 the number of consecutive granules minus 1. This value varies from 0 up to 1F. Bit 4 = a flag indicating whether the first or second granule in the starting track has been assigned. If bit 4 = 0, then the first granule was assigned. if bit 4 = 1, then the second granule starts with sector. 5) was assigned.

Relative Byte 0 1 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F

Access control Overflow Reserved EOF byte offset Record length File name . . . . . . . Name Extension . . Update password . Access password EOF sector Track Number of GAP1 Granules . GAP2 . . . . . . . . . . GAP5 .

Following is an example of a GAP string:


byte 22: byte 23: 23 06 file starts on track there are 7 granules TRK (23) S(0-9), TRK TRK (25) S(0-9), TRK 23 assigned (24) S(0-9) (26) S(0-4)

----------------------------------------------------------byte 24: 15 file continues on track 15 byte 25: 23 for 4 granules TRK (15) S(5-9), TRK (16) S(0-9) TRK (17) S(0-4) ----------------------------------------------------------byte 26: FF end of GAP string byte 27: FF end of GAP string

41

Chapter 4

Addresses & Tables Reserved Word List


Address (Hex) 0000 --> Level II ROM (Internal Tables) 3C00 --> 4000 --> - - - - - - - - - - - I/O Addresses - - - - - - - - - - - Communications Region (External Tables) 4200 5200 6700 ----------------------DOS Nucleus ----------------------Disk BASIC ----------------------Program Statement Table ----------------------Variables List Table Simple Variables - - - - - - - - - - - Subscripted Variables ----------------------Free Space

(1650 - 1821)

This table contains all of the word reserved for use by the BASIC interpreter. Each entry contains a reserved word with bit 8 turned on. During the Input Phase the incoming line is scanned for words in this list. Any occurrence of one is replaced by a token representing it. The token is computed as 80 plus the index into the table where the word was found. A list of those words and their token values follows:
Word Token Word Token Word Token

----------------------Stack ----------------------String Area

Level II Internal Tables


Internal tables are those lists and tables that are resident in the Level II system. Since they are ROM resident their contents and address are fixed. They are used by BASIC for syntax analysis, during expression evaluation, for data conversions, and while executing such statements as FOR and IF.

END..........80 SET..........83 RANDOM.......86 INPUT........89 LET..........8C IF...........8F RETURN.......92 ELSE.........95 DEFSTR.......98 DEFDBL.......9B ERROR........9E ON...........A1 *GET..........A4 *LOAD.........A7 *KILL.........AA *SAVE.........AD *DEF..........B0 CONT.........B3 DELETE.......B6 CLOAD........B9 TAB(.........BC USING........BF ERL..........C2 INSTR........C5 MEM..........C8 NOT..........CB -............CE UP ARROW.....D1 >............D4 SGN..........D7 FRE..........DA SQR..........DD EXP..........E0 TAN..........E3 *CVI..........E6 *EOF..........E9 *MKI$.........EC CSNG.........F0 LEN..........F3 ASC..........F6 RIGHT$.......F9 * Disk BASIC tokens

FOR.......81 CLS.......84 NEXT......87 DIM.......8A GOTO......8D RESTORE...90 REM.......93 TRON......96 DEFINT....99 *LINE......9C RESUM.....9F *OPEN......A2 *PUT.......A5 *MERGE.....A8 *LSET......AB SYSTEM....AE POKE......B1 LIST......B4 AUTO......B7 CSAVE.....BA TO........BD VARPTR....C0 ERR.......C3 POINT.....C6 INKEY$....C9 STEP......CC *.........CF AND.......D2 =.........D5 INT.......D8 INP.......DB RND.......DE COS.......E1 ATN.......E4 *CVS.......E7 *LOC.......EA *MKS$......ED CDBL......F1 STR$......F4 CHR$......F7 *MID$......FA

RESET.....82 *CMD.......85 DATA......88 READ......8B RUN.......8E GOSUB.....91 STOP......94 TROFF.....97 DEFSNG....9A EDIT......9D OUT.......A0 *FIELD.....A3 *CLOSE.....A6 *NAME......A9 *RSET......AC LPRINT....AF PRINT.....B2 LLIST.....B5 CLEAR.....B8 NEW.......BB *FN........BE USR.......C1 STRING$...C4 *TIMES.....C7 THEN......CA +.........CD /.........D0 OR........D3 <.........D6 ABS.......D9 POS.......DC LOG.......DF SIN.......E2 PEEK......E5 *CVD.......E8 *LOF.......EB CINT......EF FIX.......F2 VAL.......F5 LEFT$.....F8 '.........FB

42

Precedence Operator Values

(189A - 18A0)

Verb Action Routines

(1822 - 1899)

This table contains numeric values used to determine the order of arithmetic operations when evaluating an expression. As the expression is scanned each operator/ operand pair plus the precedence value for the previous operand is stored on the stack. When an operator of higher precedence than the preceding one is found the current operation is performed giving an intermediate value that is carried forward on the stack. The values shown for relational operations are computed rather than being derived from a table look-up.

Operator UP ARROW * / + ANY AND OR <= <> >= < = >

Function (Exponent) (Multiplication) (Division) (Addition) (Subtraction) (Relational) (Logical) (Logical) (Relational) (Relational) (Relational) (Relational) (Relational) (Relational)

Precedence Value 7F 7C 7C 79 79 64 50 46 06 05 03 04 02 01

There are two Verb Action Address Lists. The first one is used by the execution driver when beginning execution of a new statement. It contains address of verb routines for the tokens 80 - BB. The first token of the statement is used as an index in the range of 0 - 60 into the table at 1822 - 1899 to find the address of the verb routine to be executed. If the statement does not begin with a token control goes to assignment statement processing. The second table contains the addresses of verb routines which can only occur on the right side of an equals sign. If during the expression evaluation stage a token in the range of D7 - FA is encountered it is used as an index into the table at 1608 164F, where the address of the verb routine to be executed is found. There is no address list for the tokens BC - D6 because they are associated with and follow other tokens that expect and process them.
Table Address Token 1B22 - 1B99) Verb Address Token Verb Address

Arithmetic Routines

(18AB - 18C8)

There are really three tables back-to-back here. They are used during expression evaluation to compute intermediate values when a higher precedence operator is found.
Arithmetic Routine Addresses Integer Addition Subtraction Multiplication Division Comparison 0BD2 0BC7 0BF2 2490 0A39 Single Precision 0716 0713 0847 08A2 0A0C Double Precision 0C77 0C70 0DA1 0DE5 0A78 String 298F NONE NONE NONE NONE

80....END.......1DAE 82....RESET.....0138 84....CLS.......01C9 86....RANDOM....01D3 88....DATA......1F05 8A....DIM.......2608 8C....LET.......1F21 8E....RUN.......1EA3 90....RESTORE...1D91 92....RETURN....1EDE 94....STOP......1DA9 96....TRON......1DF7 98....DEFSTR....1E00 9A....DEFSNG....1E06 9C....LINE......41A3 9E....ERROR.....1FF4 A0....OUT.......2AFB A2....OPEN......4179 A4....GET.......417F A6....CLOSE.....4185 A8....MERGE.....418B AA....KILL......4191 AC....RSET......419A AE....SYSTEM....02B2 B0....DEF.......41B5 B2....PRINT.....206F B4....LIST......2B2E B6....DELETE....2BC6 B8....CLEAR.....1E7A BA....CSAVE.....2BF5

81....FOR........1CA1 83....SET........0135 85....CMD........4135 87....NEXT.......22B6 89....INPUT......219A 8B....READ.......21EF 8D....GOTO.......1EC2 8F....IF.........2039 91....GOSUB......1EB1 93....REM........1F07 95....ELSE.......1F07 97....TROFF......1DF8 99....DEFINT.....1E03 9B....DEFDBL.....1E09 9D....EDIT.......2E60 9F....RESUME.....1FAF A1....ON.........1FC6 A3....FIELD......417C A5....PUT........4182 A7....LOAD.......4188 A9....NAME.......418E AB....LSET.......4197 AD....SAVE.......41A0 AF....LPRINT.....2067 B1....POKE.......2CB1 B3....CONT.......1DE4 B5....LLIST......2B29 B7....AUTO.......2008 B9....CLOAD......2C1F BB....NEW........1B49

Data Conversion Routines

(18A1 - 18AA)

(Table Address TOKEN

16DB - 164F) Address TOKEN VERB Address

VERB

These routines convert the value in WRA1 from one mode to another. They are called by the expression evaluator when an intermediate computation has been made, and the result needs to be make compatible with the rest of the expression.
Conversion Routine Addresses Destination Mode String Integer Single Precision Double Precision Verb Action Addresses Address 0AF4 0A7F 0AB1 0ADB

D7....SGN.......098A D9....ABS.......0977 DB....INP.......2AEF DD....SQR.......13E7 DF....LOG.......0809 E1....COS.......1541 E3....TAN.......15A8 ES....PEEK......2CAA E7....CVS.......4158 E9....EOF.......4161 EB....LOF.......4167 ED....MKS$......416D EF....CINT......0A7F F1....CDBL......0DAB F3....LEN.......2A03 F5....VAL.......2AC5 F7....CHR$......2A1F F9....RIGHT$....2A91

D8....INT........0B37 DA....FRE........27D4 DC....POS........27A5 DE....RND........14C9 E0....EXP........1439 E2....SIN........1547 E4....ATN........15BD E6....CVI........4152 E8....CVD........415E EA....LOC........4164 EC....MKI$.......416A EE....MKD$.......4170 F0....CSNG.......0AB1 F2....FIX........0B26 F4....STR$.......2836 F6....ASC........2A0F F8....LEFT$......2A61 FA....MID$.......2A9A

43

Error Code Table

(18C9- 18F6)

Address

Letter

Type

Address

Letter

Type

Error codes printed under Level II are interpreted by using the error number as in index into a table of two letter error abbreviations. The format of the error code table is as follows:
Error Number 0 2 Code Cause Originating Address 22C2 DA,2C7,EEF 1C9E,1D32,1E0E 1E66,2022,235B 2615,2AE9,2DE2 1EEC 2214,22A2 1E4C 7B2 197C 1EDB 273F 2735 8A5,DE9,1401 AF8 28DD 29A5 1DEB

4101.......A........04 4103.......C........04 4105.......E........04 4107.......G........04 4109.......I........04 410B.......K........04 410D.......N........04 410F.......0........04 4111.......Q........04 4113.......S........D4 4115.......U........04 4117.......W........04 4119.......Y........04

4102........B........04 4104........D........04 4106........F........04 4108........H........04 410A........J........04 410C........L........04 410E........N........04 4110........P........04 4112........K........04 4114........T........04 4116........V........04 4118........X........04 411A........Z........04

NF SN

NEXT WITHOUT FOR SYNTAX ERROR (NUMEROUS CAUSES) RETURN WITHOUT GOSUB OUT OF DATA (READ) NUMEROUS NUMERIC OVERFLOW OUT OF MEMORY MISSING LINE NUMBER INDEX TOO LARGE DOUBLY DEFINED SYMBOL DIVISION BY 0 INPUT USE INCORRECT 2833 VARIABLE NOT A STRING OUT OF STRING SPACE STRING TOO LONG LITERAL STRING POOL 28A3 TABLE FULL CONTINUE NOT ALLOWED RESUME NOT ALLOWED 198C INVALID ERROR CODE 2005 INVALID ERROR CODE 2005 OPERAND MISSING DATA ERROR ON CASSETTE DISK BASIC STATEMENT ATTEMPTED UNDER LEVEL II

Program Statement Table (PST)


The Program Statement Table contains BASIC statements entered as a program. Since it is RAM resident and its origin may change from system to system there is a pointer to it in the Communications Region at address 40A4. As each line is entered it is tokenized and stored in the PST. Statements are stored in ascending order by line number regardless of the order in which they are entered. Each entry begins with a two byte pointer to the next line followed by a two byte integer equivalent of the line number then the text of the BASIC statement. The body of the statement is terminated with a single byte of zeros called the End Of Statement or EOS flag. The ending address of the PST is contained in 40F9. It is terminated by two bytes of zeros.
Program Statement Table (PST) 40A4 --> 2 Byte addr of next statement 2 byte line number in integer form BASIC statement in Tokenized form EOS Flag 2 byte addr of next statement

4 6 8 A C E 10 12 14 16 18 1A 1C 1E 20 22 24 26 28 2A 2C

RG OD FC OV OM UL BS DD 0/ ID TM OS LS ST CN NR UE UE MO FD L3

24A2 218C 12DF

Level II External Tables


External tables used by Level II are those which are kept in RAM. They are kept there because their contents and size, as well as their address, may change. A pointer to each of the External tables is maintained in the Communications Region.

Mode Table

(4101-411A)

2 byte line number in integer form BASIC statement in Tokenized form EOS Flag 2 byte addr of next statement

This table is used by the BASIC interpreter to determine the data type mode (integer, string, single or double precision) for each variable. Although it never moves its contents may change when a DEF declaration is encountered, and therefore it must be in RAM. It is the only RAM table with a fixed address and consequently there is no pointer to it in the Communications Region. The table is 26 decimal words long and is indexed by using the first character of a variable name as an index. Each entry in the table contains a code indicating the variable type e.g. 02 - integer, 03 string, 04 - single precision, 08 - double precision. The mode table is initialized during the IPL sequence to 04 for all variables. It appears as:

Shown below are two statements and their representation in the PST:

100 A = COS (1.6) 110 IF A>.5 THEN 500

44

Section two contains all dimensioned arrays. These entries have the same three byte header followed by a another header which defines the extents of the array. The array is stored after the second header in column-major order. Variables are assigned space in the VLT as they are encountered (in a DIM statement or in any part of an assignment statement). There is no alphabetical ordering. Because space is assigned on demand it is possible for previously defined variables to be moved down. For example, if A, B, and C(5) were defined followed by D, C(5) would be moved down because section one would be increased for D. This would force section two to be moved.
(40F9) --> Simple & String Variables Dimensioned Variables

(40FB) -->

Variable List Table (VLT)


This table contains all variables assigned to a BASIC program. Internally the table is divided into two sections. Section one contains entries for all non-subscripted and string variables while section two contains the values for all subscripted variables. Like the PST the VLT is RAM resident and it has two pointers in the Communications Region. Location 40F9 contains the address of the first section, and 40FB contains the address of section two. The starting address of the VLT is considered as the end of the PST. Regardless of which section a variable is defined in, the first three bytes of each entry have the same format. Byte one has a type code (2,3,4 or 8), which doubles as the length of the entry. Bytes two and three contain the variable name in last/first character order. Following this is the value itself in LSB/MSB order, or if it as a string variable a pointer to the string in the String Area.

Arrays are stored in column-major order. In that order the left most index varies the fastest. For example the array A(2,3) would be stored in memory as: A(0,0) A(1,0) A(2,0) . . . A(0,3) A(1,3) A(2,3) An index for any element can be computed using the formula:
INDEX = (((LRI*0)+URI)*LMI)+UMI)*LLI)+ULI where LRI = limit of right index LMI = limit of middle index LLI = limit of left index URI = user's current right index UMI = user's current middle index ULI = user's current left index

The code used to compute these indexes may be found at address 2595 to 27C8.

45

Literal String Pool

(40D2)

Communications Region 4000 --> 4015 --> 4040 --> RST Vectors ---------------------------DCB's ---------------------------Used By DOS ---------------------------Division Support Routine ---------------------------Used by Level II ---------------------------Mode Table ---------------------------Used by Level II ---------------------------System Print Buffer ---------------------------Used by Level II ---------------------------Disk BASIC Vectors ---------------------------DOS Exit Vectors ----------------------------

This table is used by BASIC to keep track of intermediate strings which result from operations such as string addition or some print operations. The table has eleven three byte entries which are assigned sequentially. The start of the table has a two byte pointer to the next available entry. It is initialized during IPL to point to the head of the list. Each entry contains the length and the address of a string which is usually (although not necessarily) in the PST. Entries are assigned in a top down fashion and released in a bottom up manner. A pointer to the next available entry is kept in 40B3. If the table overflows an ST error is given.

4080 --> 408E --> 4101 --> 411B --> 4130 --> 414A --> 4152 --> 41A3 --> 41E5 --> 4200 -->

Address Level II Contents (40B3) --> Address of next available entry String length Address of String 4000 4003 4006 4009 400C 400F 4012 4015 401D 4025 402D 4030 4032 4033 4036 . 403D 403E 403F 4040 4041 4042 4043 4044 4045 4046 4047 4049 404A 4048 404C 404D 404F 4051 4053 4055 4057 4059 4058 4050 4070 407E 407F 4080

DOS Contents

Description

FFCC -->

Literal String Pool

JP 1C96 .... JP 1D78 .... JP 1C90 .... JP 25D9 .... RET JP 4BA2 RET JP 44B4 DI/RET CALL 4518 ..................... ..................... ..................... JP 5000 JP 4400 RST 0 LD A,A3 LD A,0 RST 28 RET JP 44BB ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... 45F7 4560 ..................... ..................... ..................... ..................... .....................

Communications Region

(4000 - 4200)

The Communications Region has been defined as RAM locations 4000 to 4200. These addresses give the definition an air of precision that is not warranted. In reality only a portion of the area is used in the sense given to the term Communications Region. Those boundaries were chosen because they represent the end of ROM and the approximate starting address of DOS in RAM. In a Level II system without disk there would be no DOS and the RAM tables such as the PST, VLT, etc. would begin at a much lower address. But they would still be above 4200 so it is safe to think of that region as reserved. The Communications Region has many uses other than those mentioned so far. The following diagram shows the major areas discussed up to this point. Following it is a description of all bytes in the Communications Region and their known use.

RST 8 VECTOR RST 10 VECTOR RST 18 VECTOR RST 20 VECTOR RST 28 DOS REQUEST PROCESSING LOAD DEBUG (LD A,XX/RST 28) RST 38 INTERRUPT SERVICE CALL KEYBOARD DCB (8 BYTES) VIDEO DCB (8 BYTES) PRINTER DCB (8 BYTES) MAKE SYS1 (10) DOS REQUEST DOS REQUEST CODE FOR SYS1 WRITE 'DOS READY' MSG CALL DEVICE DRIVER ALA DOS KEYBOARD WORK AREA USED BY SYS0 AND KEYBOARD DRIVER DISPLAY CONTROL WORD (U/L CASE) USED BY DOS USED BY DOS SYSTEM BST'S SECONDS MINUTES HOURS YEAR DAY MONTH LOAD ADDRESS FOR SYSTEM UTILITIES 2 BYTES, INITIALIZED TO 5200 BY SYS0/SYS MEMORY SIZE. COMPUTED BY SYS0/SYS RESERVED CURRENT INTERRUPT STATUS WORD INTERRUPT SUBROUTINE MASK RESERVED (INTERRUPT BIT 0) RESERVED (INTERRUPT BIT 1) COMMUNICATIONS INTERRUPT SUBROUTINE RESERVED (INTERRUPT BIT 3) RESERVED (INTERRUPT BIT 4) RESERVED (INTERRUPT BIT 5) ADDR OF DISK INTERRUPT ROUTINE ADDR OF CLOCK INTERRUPT ROUTINE STACK DURING IPL START OF STACK DURING ROM IPL RESERVED RESERVED SUBTRACTION ROUTINE USED BY DIVISION CODE. CODE IS MOVED FROM '18F7' - '1904' DURING NON-DISK IPL OR BY BASIC UTILITY FOR DISK SYSTEMS

46

408E 4090 4093 4096 4099 409A 409B 409D 409D 409E 409F 40A0 40A1 40A4 40A5 40A7 40A9 40AA 40AB 40AC 40AE 40AF

..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... .....................

40B0 40B1 40B2 40B3 40B5 40D2 4003 40D6 40D8 40DA 40DC 40DD 40DE

..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... .....................

40DF 40E1 40E2 40E4 40E6

..................... ..................... ..................... ..................... .....................

40E8 40EA 40EC 40ED 40EF 40F0 40F2 40F3 40F5 40F7 40F9 40FB 40FD 40FF 4101

..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... ..................... .....................

411A 411B

..................... .....................

CONTAINS ADDRESS OF USER SUBROUTINE RANDOM NUMBER SEED IN A,00 OUT A,00 HOLDS LAST CHAR TYPED AFTER BREAK FLAG (SIGNALS RESUME ENTERED) NO. OF CHARS. IN CURRENT PRINT LINE OUTPUT DEVICE CODE (1-PRINTER 0-VIDEO, MINUS 1-CASSETTE) SIZE OF DISPLAY LINE (VIDEO) SIZE OF PRINT LINE RESERVED ADDR OF STRING AREA BOUNDARY CURRENT LINE NUMBER ADDR OF PST CURSOR POSITION ADDR OF KEYBOARD BUFFER. 0 IF CASSETTE INPUT, ELSE NON-ZERO RANDOM NUMBER SEED VALUE FROM REFRESH REGISTER LAST RANDOM NUMBER (2 BYTES) FLAG: 0 - LOCATE NAMED VARIABLE -1 - CREATE ENTRY FOR NAMED VARIABLE TYPE FLAG FOR VALUE IN WRA1. 2 - INTEGER 3 - STRING 4 - SINGLE PRECISION 8 DOUBLE PRECISION HOLDS INTERMEDIATE VALUE DURING EXPRESSION EVA MEMORY SIZE RESERVED ADDR OF NEXT AVAILABLE LOC. IN LSPT. LSPT (LITERAL STRING POOL TABLE) END OF LSPT THE NEXT 3 BYTES ARE USED TO HOLD THE LENGTH AND ADDR OF A STRING WHEN IT IS MOVED TO THE STRING AREA. POINTER TO NEXT AVAILABLE LOC. IN STRING AREA 1: INDEX OF LAST BYTE EXECUTED IN CURRENT STATEMENT. 2: EDIT FLAG DURING PRINT USING LINE NO. OF LAST DATA STATEMENT FOR FLAG (1 = FOR IN PROGRESS 0 = NO FOR IN PROGRESS) 0 DURING INPUT PHASE, ZERO OTHERWISE READ FLAG: 0 = READ STATEMENT ACTIVE 1 = INPUT STATEMENT ACTIVE ALSO USED IN PRINT USING TO HOLD SEPARATOR BETWEEN STRING AND VARIABLE HOLDS EXECUTION ADDR FOR PGM LOADED WITH DOS REQUEST AUTO INCREMENT FLAG 0 = NO AUTO MODE NON-ZERO HOLDS NEXT LINE CURRENT LINE NUMBER IN BINARY (DURING INPUT PHASE) AUTO LINE INCREMENT DURING INPUT: ADDR OF CODE STRING FOR CURRENT STATEMENT. DURING EXECUTION: LINE NO. FOR CURRENT STATEMENT DURING EXECUTION: HOLDS STACK POINTER VALUE WHEN STATEMENT EXECUTION BEGINS LINE NO. IN WHICH ERROR OCCURRED LINE NO. IN WHICH ERROR OCCURRED LAST BYTE EXECUTED IN CURRENT STATEMENT ADDR OF POSITION IN ERROR LINE ON ERROR ADDRESS FLAG. FF DURING ON ERROR PROCESSING CLEARED BY RESUME ROUTINE ADDR OF DECIMAL POINT IN PBUFF LAST LINE NUMBER EXECUTED SAVED BY STOP/END ADDR OF LAST BYTE EXECUTED DURING ERROR ADDR OF SIMPLE VARIABLES ADDR OF DIMENSIONED VARIABLES STARTING ADDRESS OF FREE SPACE LIST POINTS TO BYTE FOLLOWING LAST CHAR READ DURING READ STMNT PROCESSING VARIABLE DECLARATION LIST. THERE ARE 26 ENTRIES ( 1 FOR EACH LETTER OF THE ALPHABET) EACH ENTRY CONTAINS A CODE INDICATING DEFAULT MODE FOR VARIABLES STARTING WITH THAT LETTER END OF DECLARATION LIST TRACE FLAG (0 = NO TRACE, NON-ZERO = TRACE)

411C

411D 411E 415F 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 412A 422B 412C 412D 412E 412F 4130 4149 414A

4151 * * LOCATIONS 4152 THRU 41E2 CONTAIN DOS EXITS AND DISK BASIC EXITS. ON * NON-DISK SYSTEMS THESE LOCATIONS ARE INITIALIZED TO RETURNS (RET'S) * WHILE ON DISK BASED SYSTEMS THEY WILL BE INITIALIZED AS SHOWN. * 4152 ...RET..JP 5E46 ..... DISK BASIC EXIT (CVI) 4155 ...RET..JP 558E ..... DISK BASIC EXIT (FN) 4158 ...RET..JP 5E49 ..... DISK BASIC EXIT (CVS) 415E ...RET..JP 5655 ..... DISK BASIC EXIT (DEF) 415K ...RET..JP 5E4C ..... DISK BASIC EXIT (CVD) 4161 .. RET..JP 61EB ..... DISK BASIC EXIT (EOF) 4164 ...RET..JP 6231 ..... DISK BASIC EXIT (LOC) 4167 ...RET..JP 6242 ..... DISK BASIC EXIT (LOF) 416A ...RET..JP 5E20 ..... DISK BASIC EXIT (MKI$) 4160 ...RET..JP 5E30 ..... DISK BASIC EXIT (MKS$) 4170 ...RET..JP 5E33 ..... DISK BASIC EXIT (MKD$) 4173 ...RET..JP 56C4 ..... DISK BASIC EXIT (CMD) 4176 ...RET..JP 5714 ..... DISK BASIC EXIT (TIME$) 4179 ...RET..JP 6349 ..... DISK BASIC EXIT (OPEN) 417C ...RET..JP 60AB ..... DISK BASIC EXIT (FIELD) 417F ...RET..JP 627C ..... DISK BASIC EXIT (GET) 4182 ...RET..JP 627B ..... DISK BASIC EXIT (PUT) 4185 ...RET..JP 606F ..... DISK BASIC EXIT (CLOSE) 4188 ...RET..JP 5F7B ..... DISK BASIC EXIT (LOAD) 418B ...RET..JP 600B ..... DISK BASIC EXIT (MERGE) 418E ...RET..JP 6346 ..... DISK BASIC EXIT (NAME) 4191 ...RET..JP 63C0 ..... DISK BASIC EXIT (KILL) 4194 ...RET..JP 58B7 ..... DISK BASIC EXIT (&) 4197 ...RET..JP 60E6 ..... DISK BASIC EXIT (LIST) 419A ...RET..JP 60E5 ..... DISK BASIC EXIT (RSET) 419D ...RET..JP 582F ..... DISK BASIC EXIT (INSTR) 41A0 ...RET..JP 6044 ..... DISK BASIC EXIT (SAVE) 41A3 ...RET..JP 5756 ..... DISK BASIC EXIT (LINE) 41A6 ...RET..JP 5679 ..... DISK BASIC EXIT (USR) * * THE FOLLOWING ADDRESSES ARE THE DOS EXIT ADDRESSES. * * 41A9 ...RET..JP XXXX ..... DOS EXIT FROM 41AC ...RET..JP 5FFC ..... DOS EXIT FROM 1A1C 41AF ...RET..JP 598E ..... DOS EXIT FROM 0368 41B2 ...RET..JP 6033 ..... DOS EXIT FROM ROM address 1AA1 41B5 ...RET..JP 5BD7 ..... DOS EXIT FROM ROM address 1AEC 41B8 ...RET..JP 5B8C ..... DOS EXIT FROM ROM address 1AF2 41BB ...RET..JP 60A1 ..... DOS EXIT FROM ROM address 1B8C 41BE .. RET..JP 577C ..... DOS EXIT FROM ROM address 2174 41C1 .. RET..JP 59CD ..... DOS EXIT FROM ROM address 032C 41C4 .. RET..JP XXXX ..... DOS EXIT FROM ROM address 0358 41C7 ...RET..JP 5F78 ..... DOS EXIT FROM ROM address 1EA6 41CA ...RET..JP 5A15 ..... DOS EXIT FROM ROM address 206F 41CD ...RET..JP 5B9A ..... DOS EXIT FROM ROM address 2103 41D0 ...RET..JP 5B99 ..... DOS EXIT FROM ROM address 2103 41D3 ...RET. JP 5B65 ..... DOS EXIT FROM ROM address 2108 41D6 ...RET..JP 5784 ..... DOS EXIT FROM ROM address 219E 41DC ...RET..JP 5E63 ..... DOS EXIT FROM ROM address 222D 41DF ...RET..JP 579C ..... DOS EXIT FROM ROM address 2278 41E2 ...RET..JP 5B51 ..... DOS EXIT FROM ROM address 0282

..................... TEMP STORAGE USED BY NUMERIC ROUTINES WHEN UNPACKING A FLOATING POINT NUMBER. USUALLY IT HOLDS THE LAST BYTE SHIFTED OUT OF THE LSB POSITION ..................... WRA1 - LSB OF DBL PREC. VALUE ..................... WRA1 - DBL PREC. VALUE ..................... WRA1 - DBL PREC VALUE ..................... WRA1 - DBL PREC VALUE ..................... WRA1 - LSB OF INTEGER SINGLE PREC ..................... WRA1 ..................... WRA1 - MSB FOR SINGLE PREC ..................... WRA1 - EXPONENT FOR SINGLE PREC ..................... SIGN OF RESULT DURING MATH & ARITHMETIC OPERATIONS ..................... BIT BUCKET USED DURING DP ADDITION ..................... WRA2 - LSB ..................... WRA2 ..................... WRA2 ..................... WRA2 ..................... WRA2 ..................... WRA2 ..................... WRA2 - MSB ..................... WRA2 - EXPONENT ..................... NOT USED ..................... START OF INTERNAL PRINT BUFFER USED DURING PRINT PROCESSING ..................... LAST BYTE OF PRINT BUFFER ..................... TEMP. STORAGE USED BY DBL PRECISION DIVISION ROUTINE. HOLDS DIVISOR ..................... END OF TEMP AREA

47

DCB Descriptions
The keyboard, video, and printer DCB'S (Device Control Blocks) are defined in ROM at locations 06E7 - 06FF. They are moved to the address show in the Communications Region during the IPL sequence.

Video DCB (Address 401D)


Relative Byte 0 1 2 3 4 5 6 7 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 1 1 0 1 0 1 0 1 1 1 0 0 0 0 0 0 1 1 0 1 0 0 0 0 1 Device type (7) Driver address (0458) Next character address 3C00 =< X < 3FFF 0/value 0 = Suppress cursor value = last char under cursor RAM buffer addr (4F44)

In order for interrupts to occur the system must be primed to accept them. When the system is primed it is ENABLED which is shorthand for the instruction used to enable the interrupt system (EI-Enable Interrupts). A system that is not enabled is DISABLED and again that is shorthand for the disable instruction (DI-Disable Interrupts). Besides priming the system for interrupts there must be some outside event to stimulate the interrupt. On Level II systems that could be a clock or a disk. Actually both of them generate interrupts - the clock gives one every 25 milliseconds, and the disk on demand for certain operations. When running a Level II system without disks the interrupts are disabled. It is only when DOS is loaded that interrupts are enabled and service routines to support those interrupts are loaded. Interrupts are disabled at the start of the IPL sequence that is common to Level II and DOS. For Level II they will remain off, but on a DOS system they will be enabled at the end of the initialization in SYS0/SYS. When an interrupt occurs two things happen. First a bit indicating the exact cause of the interrupt is set in byte 37E0. Second an RST 38H instruction is executed. As a result of the RST (which is like a CALL) the address of the next instruction to be executed is saved on the stack (PUSH'd) and control is passed to location 0038. Stored at 0038 is a JP 4012. During the IPL sequence 4012 was initialized to:
4012 DI 4013 RET Disable further interrupts Return to point of interrupt

Keyboard DCB (Address 4015)


Relative Byte 0 1 2 3 4 5 6 7 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0 0 0_ 1 1 Device type (1) Driver address (03E3) Not Used RAM buffer address (494B)

Printer DCB (Address 4025)


Relative Byte 0 1 2 3 4 5 6 7 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 1 0 0 0 0 Device type (6) Driver address (058D) Lines/page (43H = 67) Lines printed so far Not Used RAM buffer address (5250)

for non-disk systems or:


4012 CALL 4518 Service Interrupt

for disk systems

Interrupt Vectors
Interrupts are a means of allowing an external event to interrupt the CPU and redirect it to execute some specific portion of code. The signal that causes this to happen is called an interrupt and the code executed in response to that interrupt is called a service routine. After the service routine executes it returns control of the CPU to the point where the interrupt occurred and normal processing continues.

The service routine at 4518 examines the contents of 37E0 and executes a subroutine for each bit that is turned on and for which DOS has a subroutine. The format of the interrupt status word at 37E0 is:
7 X 6 X 5 4 3 2 X Not used Communications Interrupt Not used Disk Controller Interrupt Clock Interrupt 1 0 <-- Bits

48

Memory Mapped I/O


DOS maintains an interrupt service mask at 404C that it uses to decide if there is a subroutine to be executed for each of the interrupt status. As released 404C contains a C0 which indicates subroutines for clock and disk interrupts. The service routine at 4518 combines the status byte and the mask byte by AND'ing them together. The result is used as a bit index into a table of subroutine addresses stored at 404D - 405C. Each entry is a two byte address of an interrupt subroutine. Bit 0 of the index corresponds to the address at 404D/404E, bit 1 404F/4050, etc. The service routine runs disabled. It scans the interrupt status from left to right jumping to a subroutine whenever a bit is found on. All registers are saved before subroutine entry and a return address in the service routine is PUSH'd onto the stack so a RET instruction can be used to exit the subroutine. When all bits in the status have been tested control returns to the point of interrupt with interrupts enabled.

FOR Statement Stack Frame


All variable addresses associated with a FOR loop are carried on the stack until the loop completes. When a NEXT statement is processed, it searches the stack looking for a FOR frame with the same index address as the current one. The routine that searches the stack is at location 1936. Its only parameter is the address of the current index which is passed in the DE register set. The stack is searched backwards from its current position to the beginning of the stack. If a FOR frame with a matching index address is not found an NF error is generated. The stack frame searched for is given below.
Low Memory ........................ ........................ ........................ ........................ ........................ ........................ ........................ FOR Token Addr of FOR Index LSB / MSB order Sign of increment Type (-1 Integer, +1 SP) STEP value LSB / MSB order TO value LSB / MSB order Binary line # of FOR statement Address of 1st loop statement FOR Token

Stack Frame Configurations


High Memory

........................ ........................

Level II usually uses the Communications Region for temporary storage. There are special cases, however where that is not possible because a routine may call itself (called recursion) and each call would destroy the values saved by the previous call. In those cases the stack is used to save some of the variables. Of course an indexed table could be used, but in these cases the stack serves the purpose.

49

GOSUB Stack Configuration


Low Memory ...................... ...................... High Memory ...................... Return address in Execution Driver GOSUB Token Binary value of GOSUB line # Address of GOSUB line in PST (current position)

Expression Evaluation
Expression evaluation involves scanning an expression and breaking it into separate operations which can be executed in their proper order according to the hierarchy of operators. This means a statement must be scanned and the operations with the highest hierarchical value (called precedence value) must be performed first. Any new terms which result from those operations must be carried forward and combined with the rest of the expression. The method used for evaluation is an operator precedence parse. An expression is scanned from left to right. Scanning stops as soon as an operator token or EOS is found. The variable to the left of the operator (called the current variable), and the operator (any arithmetic token for - * / or exp) are called a 'set', and are either: a) pushed onto the stack as a set or, b) if a precedence break is detected the operation between the previous set pushed onto the stack and the current variable is performed. The result of that operation then becomes the current variable and the previous set is removed from the stack. After the computation another attempt is made to push the new current variable and operator onto the stack as a set. This step is repeated until the new set is pushed or there are no more sets on the stack with which to combine the current value. In that case the expression has been evaluated. The variable/operator sets that are pushed on the stack have the following format:

performed automatically by POPing the last set. When this occurs control is transferred to a routine (usually at 2406 ) which will perform the operation specified in the set between that value (the one from the set on the stack), and the current variable. The result then becomes the current variable. When the computation is finished control returns to a point where the precedence break test is repeated. This time the set which caused the last break is not there, so the test will be between the same operator as before and the operator in the previous set. If there is no previous set then the current variable and operator are pushed as the next set. Note, an EOS or a non-arithmetic token are treated as precedence breaks. Assuming no break occurs the current variable and operator are pushed on the stack as the next set, and the scan of the expression continues from the point where it left off. Let's take an example. Assume we have the expression, A equals B plus C * D / E 5 Scanning begins with the first character to the right of the equals sign and will stop at the first token (plus). B plus would be pushed as the first set because: a) there was no prior set so there could not have been a precedence break, and b) the scan stopped on an arithmetic token (plus). The next scan would stop at the *. Again the variable / operator pair of C * would be pushed this time as set 2 although for slightly different reasons than before. The * precedence value is higher than the plus precedence value already pushed so there is no break. At this time the stack contains,
Set 2 00 2346 B value 04 00 Token for + after B

2406 Set 1 Precedence value for + in Set 1 79 2346 C value 04 02 Token for * after C

Precedence value for --> operator value in prior set zero for 1st Continuation addr after --> precedence break computation. Usually 2346 <-Value for this variable for operator this variable 1=-, 2=*, 4=[ 5=AND

2406

Type code (length) for this variable Address of precedence computation routine. 2406 for +, -, * and /

-->

-->

<-- Token after 0=+, 3=/ 6=0R

The test for precedence break is simple. If the operator (the token where the scan stopped) has the same or a lower precedence value as the precedence value for the last set pushed on the stack then a break has occurred, and an intermediate computation is required. The computation is

Scan three would stop on the / following D. This time there would be a precedence break because * and / have the same values. Consequently set 2 would be POP'd from the stack and control passes to the precedence break routine at 2406 (other routines may be used depending on the operation to be performed - check the listing for details). Here the operation between set 2 (C*) and the current value (D) would be performed. This would result in a new current value that will be called M. M equals C * D After the multiplication control goes back to 2346 (continuation after break processing) where the rules from above are used. This time the current value is pushed as set

50

2 because it has a higher precedence value (/) than that in set 1 (plus). Now the stack contains
00 --------2346 ----------------04 00 --------2406 Set 1 Precedence value 79 --------2346 ----------------04 03 --------2406 Set 2 C * D value Token for / after C * D

B value Token for + after B

DOS functions may be executed by loading a DOS request code into the A register and executing a RST 28 instruction. Because of the way DOS processes these request codes the push on the stack that resulted from the RST instruction is lost, and control will be returned to the next address found on the stack - rather than to the address following the RST instruction. For example,
LD RST . . . . A,VAL 28 LOAD DOS FUNCTION CODE EXECUTE DOS FUNCTION THIS IS WHERE WE WANT TO RETURN TO BUT WILL NOT BECAUSE OF THE WAY THE STACK IS MANAGED BY DOS

After pushing set 2 the scan continues, stopping at the operator. It has a higher precedence value than the (/) in set 2 so a third set is added to the stack giving:
----------------------------Set 1 ----------------------------Set 2

This will not work because the return address (stored on the stack by the RST 28) has been lost during processing. Instead the following sequence should be used:
LD CALL . . . RST A,VAL DOS LOAD REQUEST CODE PUT RETURN ADDR ON STACK

Precedence for / in set 2

7C --------2346 ----------------04 04 --------2406 E value Token for / after E

DOS

28

EXECUTE DOS FUNCTION ALL REGISTERS ARE PRESERVED WE WILL AUTOMATICALLY RET TO CALLER OF DOS

The next scan is made and an EOS is found following the 5 (which is now the current value). As mentioned earlier an EOS or non-arithmetic token is an automatic precedence break, so set 3 is POP'd from the stack and E 5 is computed and becomes the current value. Control passes to 2346 where the rules for pushing the next set are applied and set 2 get's POP'd because the current operator is an EOS. Set 2 (M/) and the current value are operated on giving a current value of M / E 5 or C*D/E5 Again control goes to 2346 which forces set 1 to be POP'd because the current operator is an EOS. When the set is POP'd control goes to the computation routine where the current value and set 1 are operated on. This yields a current value of B plus C * D / E 5 Now control goes to 2346 and this time the stack is empty causing control to be returned to the caller. The expression has been evaluated and its value is left in WRA1.

The request code value loaded into the A-register must contain the sector number minus 2 of the directory sector for the overlay to be loaded and a code specifying the exact operation to be performed. The format of the request code is:
7 1 6 X 5 X 4 X 3 X 2 X 1 X 0 X Sector number -2, of directory entry for DOS module to be loaded Must be a 1, otherwise request will be ignored <-- Bits

Function code to be passed to DOS module

As it is presently implemented the file pointed to by the first entry in the specified directory sector will be loaded. There is no way for example, to load the file associated with the 3rd or 4th entry. A list of the system overlay modules and their functions follows. These descriptions are incomplete. See the individual modules for a complete description.
MODULE SYS1 DIRECTORY SECTOR MINUS 2 1 REQUEST CODE 93 AC BC C3 D3 E3 F3 SYS2 2 94 A4 B4 C4 D4 E4 F4 SYS3 3 95 A5 B5 C5 D5 E5 F5 SUB-FUNCTIONS 10 20 30 40 write 'DOS READY' write 'DOS READY' scan input string move input string to DCB 50 - scan and move input string 60 - append extension to DCB 70 - reserved 10 - OPEN file processing 20 - INST file processing 30 - create directory overflow entry 40 50 - reserved 60 70 10 20 30 40 50 60 70 CLOSE file processing KILL file processing reserved load SYS3/SYS format diskette -

DOS Request Codes


DOS request codes provide a mechanism for executing system level commands from within a program. The way they work is to cause the DOS overlay module SYSX/SYS associated with the request to be loaded into 4200 - 5200 and executed. When the request has been satisfied control is returned to the caller as though a subroutine call had been made.

SYS4 SYS5

51

Chapter 5

A BASIC SORT Verb

Contained in this chapter is a sample assembly program that demonstrates the use of the ROM calls and tables described in the previous chapters. In this example DOS Exits and Disk BASIC Exits are used to add a SORT verb to BASIC. In this case a SORT verb will be added so that the statement 100 SORT I$, O$, K1$ be used to read and sort a file specified by the string I$, O$ and K1$ are strings which specify the output file name and the sort key descriptors. The procedure for doing this is simple. First we must modify the Input Phase to recognize the word SORT and replace it with a token. This can be accomplished by using one of the DOS Exits. A DOS Exit is taken during the Input Phase immediately after the scan for reserved words. We will intercept this exit to make a further test for the word SORT and replace it with a token. Processing will then continue as before. Before using any DOS Exit study the surrounding code to determine exact register usage. In this case it is important to note that the length of the incoming line is in the BC register when the exit is taken. If the subroutine compresses the line (by replacing the word SORT with a token) then its length will have changed and the new length must replace the original contents of BC. A second modification must be made to the Execution Driver, or somewhere in its chain, to recognize the new token value and branch to the SORT action routine. This presents a slight problem because there are no DOS Exits in the execution driver before calling the verb routine, and since the driver code and its tables are in ROM they cannot be changed. In short there is no easy way to incorporate new tokens into the Execution Phase.

The solution is to borrow a Disk BASIC token and piggyback another token behind it. Then any calls to the verb routine associated with the borrowed token must be intercepted and a test make for the piggy-backed token. If one is found control goes to the SORT verb routine otherwise it passes to the assigned verb routine. In this example the token FA will be borrowed and another FA will be tacked behind it giving a token FAFA. This example is incomplete because the LIST function has not been modified to recognize the sort token. If a LIST command is issued the verb MID$MID$ will be given for the SORT verb. There is one more detail that needs attention before discussing the verb routine. Using the memory layout figure in Chapter 1 we can see that there is no obvious place to load an assembly language program without interfering somehow with one of BASIC's areas. Depending on where we loaded our verb routine it could overlay the String Area, or the Stack, or maybe even reach as low as the PST or VLT. Of course we might get lucky and find an area in the middle of the Free Space List that never gets used but that's too risky. BASIC has a facility for setting the upper limit of the memory space it will use. By using this feature we can reserve a region in high memory where our verb routine can be loaded without disturbing any of BASIC's tables. Now for the details of verb routine. Because a sort can be a lengthy piece of code only the details that pertain to DOS Exits, Disk BASIC, and some of the ROM calls from Chapter 2 will be illustrated. The verb routine has two sections. The first section will be called once to modify the DOS and Disk BASIC exit addresses (also called vectors) in the Communications Region to point to locations within the verb routine. The vector addresses must be modified after BASIC has been entered on a DOS system because they are

52

initialized by the BASIC command. The second section has two parts. Part one is the DOS Exit code called from the Input Scanner. Part two is the verb action routine for the SORT verb. It is entered when a FA token is encountered during the Execution Phase. The system being used will be assumed to have 48K of RAM, at least 1 disk, and NEWDOS 2.1. The verb routine will occupy locations E000 - FFFF. The entry point for initializing the vectors will be at E000. All buffers used will be assigned dynamically in the stack portion of the Free Space List. The verb routine will be loaded before exiting DOS and entering Level II BASIC. Although it could be loaded from the BASIC program by using the CMD'LOAD..' feature of NEWDOS.
1. IPL 2. LOAD,SORT 3. BASIC,57344

:(load verb into E000 - FFFF :(protect verb area)

1)

100 DEF USR1(0) = &HE000 : initialization entry point 110 A = USR1(0) : initialize vectors RUN 100 I$="SORTIN/PAY:1" 110 O$-"SORTOUT/PAY:1" 120 KS-"A,A,100-120" 130 SORT I$,O$,K$ RUN 00100 00110 00120 00130 00140 00150 00160 00170 00180 00190 00200 00210 00220 00230 00240 00250 00260 00270 00280 00290 00300 00310 00320 00330 00340 00350 00360 00370 00380 00390 00400 00410 00420 00430 00440 00450 00460 00470 00480 00490 00500 00510 00520 00530 ORG 0E000H ; INITIAL ENTRY POINT TO INITIALIZE DOS EXIT AND ; DISK BASIC ADDRESSES. LD HL,(41B3H) ; ORIGINAL DOS EXIT VALUE LD (ADR1+1),HL ; IS STILL USED AFTER OUR ; PROCESSING LD HL,(41DAH) ; ORIGINAL DISK BASIC ADDR FOR ; MID$ TOKEN (FA) LD (ADR2+1),HL ; SAVE IN CASE FA TOKEN FOUND LD HL,NDX LD (41B3H),HL LD HL,NDB ; ; OUR ADDR LD (41DAH),HL ; ; FA TOKEN W/OUR ADDR RET ; RET TO EXECUTION DRIVER ;* GET ADDRESS OF VARIABLE ;* THIS SECTION OF CODE IS ENTERED AS A DOS EXIT DURING THE ;* INPUT PHASE. IT WILL TEST FOR A 'SORT' COMMAND AND REPLACE ;* IT WITH A 'FAFA' TOKEN. THE ORGINAL DOS EXIT ADDR HAS BEEN ;* SAVED AND WILL BE TAKEN AT ADR1. ;* NDX CALL SAV ; SAVE ALL REGISTERS LD IX,SORT-1 ; TEST STRING LD B,3 ; NO. OF CHARS TO MATCH NDX1 INC HL ; START OF LOOP INC IX ; BUMP TO NEXT TEST CHAR LD A,(IX+0) ; GET A TEST CHAR CP (HL) ; COMPARE W/INPUT STRING JR NZ,OUT ; STOP WHEN FIRST MIS-MATCH DJNZ NDX1 ; ALL 4 CHARS MUST MATCH ;* ;* WE HAVE A MATCH. NOW REPLACE THE WORD 'SORT' WITH A TOKEN ;* 'FAFA' AND COMPRESS THE STRING ;* INC HL ; FIRST CHAR AFTER 'SORT' PUSH HL ; SAVE FOR COMPRESSION CODE LD BC,-3 ; BACKSPACE INPUT STRING ADD HL,BC ; START OF WORD 'SORT' LD (HL),0FAH ; TOKEN REPLACES 'S' INC HL ; NEXT LOC IN INPUT STRING LD (HL),0FAH ; TOKEN REPLACES '0' INC HL ; NEXT LOC IN INPUT STRING POP DE ; STRING ADDR AFTER SORT : initialize the sort : (sort in : (Sort out : (sort key: ascending order ASCII key, sort field is 10 : (sort file)

00540 00550 00560 00570 00580 00590 00600 00610 00620 00630 00640 00650 00660 00670 00680 00690 00700 00710 00720 00730 00740 00750 00760 00770 00780 00790 00800 00810 00820 00830 00840 00850 00860 00870 00880 00890 00900 00910 00920 00930 00940 00950 00960 00970 00980 00990 01000 01010 01020 01030 01040 01050 01060 01070 01080 01090 01100 01110 01120 01130 01140 01150 01160 01170 01180 01190 01200 01210 01220 02230 01240 01250 01260 01270 01280 01290 01300 01310 01320 01330 01340 01350 01360 01370 01380 01390 01400 01410 01420 01430 01440 01450

EX DE,HL ; SO WE CAN USE RST 10 ;* ; TO FETCH NEXT CHAR ;* NOW COMPRESS THE INPUT STRING ;* LD BC,3 ; SET COUNT OF CHARS IN ;* ; EQUAL TO NO SKIPPED OVER NDX2 RST 10H ; GET NEXT CHAR, DISCARD ;* ; BLANKS LD (DE),A ; MOVE IT DOWN INC DE ; BUMP SOURCE ADDR INC C ; COUNT 1 CHAR IN LINE OR A ; TEST FOR END OF STRING JR NZ,NDX2 ; NOT END, LOOP LD (DE),A ; EACH LINE MUST END WITH ;* ; 3 BYTES OF ZEROS INC DE ; BUMP TO LAST BYTE LD (DE),A ; STORE 3 RD ZERO INC C ; THEN SET BC - LENGTH OF INC C ; LINE + 1 INC C ; SO BASIC CAN MOVE IT LD (TEMP),BC ; SAVE NEW LINE LENGTH CALL RES ; RESTORE REGISTERS LD BC,(TEMP) ; NEW LINE LENGTH TO BC JR ADR1 ; EXIT OUT CALL RES ; RESTORE REGISTERS ADR1 JP 0 ; CONTINUE ON TO ORIGINAL ;* ; DOS EXIT ;* DISK BASIC EXIT FOR FA TOKEN. TEST FOR SORT TOKEN FAFA ;* NDB CALL SAV ; SAVE ALL REGISTERS INC HL ; SKIP TO CHAR AFTER TOKEN LD A,(HL) ; TEST FOR SECOND 'FA' CP 0FAH ; IS FOLLOWING CHAR A FA JR Z,NDB1 ; Z IF SORT TOKEN CALL RES ; RESTORE REGISTERS ADR2 JP 0 ; CONTINUE WITH MID$ PROCESSING ;* ;* WE HAVE A SORT TOKEN ;* NDB1 INC HL ; SKIP OVER REST OF TOKEN CALL GADR ; GET ADDR OF 1ST PARAM LD (PARM1),DE ; SAV ADDR OF INPUT FILE NAME RST 08 ; LOOK FOR COMMA DEFM ',' ; SYMBOL TO LOOK FOR CALL GADR ; GET ADDR OF 2ND PARAM LD (PARM2),DE ; SAV ADDR OF OUTPUT FILE NAME RST 08 ; LOOK FOR COMMA DEFM ',' ; SYMBOL TO LOOK FOR CALL GADR ; GET ADDR OF SORT KEYS LD (PARM3),DE ; SAV ADDR OF SORT KEY LD (TEMP),HL ; SAVE ENDING POSITION ;* ; IN CURRENT STATEMENT ;* ;* NOW, BLANK FILL I/O DCBS ;* LD IX,DCBL ; LIST OF DCB ADDRS LD C,2 ; NO OF DCBS TO BLANK LD A,20H ; ASCII BLANK L1 LD L,(IX+0) ; LSB OF DCB ADDR LD H,(IX+1) ; MSB OF DCB ADDR LD B,32 ; NO OF BYTES TO BLANK L2 LD (HL),A ; BLANK LOOP INC HL DJNZ L2 ; LOOP TILL BLANKED INC IX ; BUMP TO NXT DCB ADDR INC IX ; BUMP AGAIN DEC C ; ALL DCBS BLANKED JR NZ,L1 ; NO ;* ; YES, MOVE FILE NAMES TO DCB AREAS ;* LD HL,(PARM1) ; ADDR OF INPUT FILE NAME STRNG LD DE,DCBI ; INPUT DCB CALL 29C8H ; MOVE NAME TO DCB LD HL,(PARM2) ; ADDR OF OUTPUT FILE NAME LD DE,DCBO ; OUTPUT DCB CALL 29C8H ; MOVE NAME TO DCB LD HL,(PARM3) ; GET ADDR OF KEY STRING INC HL ; SKIP OVER BYTE COUNT LD C,(HL) ; GET LSB OF STRNG ADDR INC HL ; BUMP TO REST OF ADDR LD H,(HL) ; GET MSB OF STRNG ADDR LD L,C ; NOW HL = STRNG ADDR CALL 1E3DH ; MUST BE ALPHA JR NC,YA1 ; OK JP ERROR ; INCORRECT SORT ORDER YA1 LD (ORDER),A ; SAVE SORT ORDER (A/D) INC HL ; SKIP TO TERMINAL CHAR RST 08 ; TEST FOR COMMA DEFM ',' CALL 1E3DH ; MUST BE ALPHA JR NC,YA5 ; OK

53

01460 01470 YA5 01480 01490 01500 01510 01520 01530 01540 01550 01560 01570 YA10 01580 01590 01600 01610 01620 01630 01640 01650 01660 01680 01690 01700 01710 01720 01730 01740 01750 01760 01770 01780 01790 01800 01810 01820 01830 01840 01850 01860 01870 01880 01890 01900 01910 01920 01930 01940 ;*

JP ERROR LD (TYPE),A INC HL RST 8 DEFM ',' CALL 0E6CH LD DE,(4121H) LD (SIZE),DE RST 20H JP M,YA10 JP ERROR RST 08 DEFM ',' CALL 0E6CH LD DE,(4121H) LD (START),DE RST 08 DEFM '-' CALL 0E6CH LD DE,(4121H) LD (END),DE HL,(TEMP) CALL LD RET RES HL,(TEMP)

; SAVE TYPE (A/B) ; SKIP TO TERMINAL CHAR ; TEST FOR COMMA ; ; ; ; ; GET RECORD SIZE GET SIZE FROM WRA1 SAVE IT MUST BE AS INTEGER MINUS IF INTEGER

; LOOK FOR COMMA ; ; ; ; ; ; ; ; ; ; ; ; ; GET STARTING POSITION GET POS FROM WRA1 SAVE IT LOOK FOR CHAR TO TEST FOR GET ENDING POS OF KEY GET VALUE FROM WRA1 SAVE ENDING S01670 LD RESTORE CURRENT LIME ADDR TO EOS ON RETURN RESTORE REGISTERS RESTORE EOS ADDR RETURN TO BASIC

;* ;* ;* SORT ;* ;* ;* SAV

DEFM DEFB DEFM

'S' 0D3H 'T'

; S OF SORT ; TOKEN FOR OR OF SORT ; T OF SORT

SAVE ALL REGISTERS EX EX PUSH PUSH PUSH PUSH EX PUSH RET DE,HL (SP),HL BC AF IX DE DE,HL DE ; SAV DE/RTN ADDR TO HL

; ; ; ;

SAVE ORIGINAL HL RESTORE HL RET ADDR TO DE RET ADDR TO STK RET TO CALLER

;* ;* ;* RES

RESTORE ALL REGISTERS POP POP HL DE ; RTN ADDR TO HL ; REAL HL

01950 01960 01970 01980 01990 02000 02010 02020 02030 02040 02050 02060 02070 02080 02090 02100 02110 02120 02130 02140 02150 02160 02170 02180 02190 02200 02210 02220 02230 02240 02250 02260 02270 02280 02290 02300 02310 02320 02330 02340 02350 02360 02370 02380 02390 02400 02410 02420 02430

(HL) ;* ;* GET THE ADDRESS OF THE NEXT ;* GADR LD A,(HL) ;* CP 22H ;* JR NZ,GADR2 CALL 2866H JR GADR5 GADR2 CALL 2540H GADR5 RET 20H LD DE,(4121H) RET Z POP HL POP HL LD A,2 JP 1997H ;* ;* ERROR EXIT ;* ERROR CALL RES POP HL LD A,2 JP 1997H ;* ;* ;* DCBL DEFW DCBI DEFW DCBO PARM1 DEFW 0 PARM2 DEFW 0 PARM3 DEFW 0 TYPE DEFB 0 ORDER DEFB 0 SIZE DEFW 0 START DEFW 0 END DEFW 0 TEMP DEFW 0 DCBI DEFS 32 DCBO DEFS 32 END

POP POP POP EX EX RET JP

IX AF BC (SP),HL DE,HL

; RTN ADDR TO STK ; RTN TO CALLER VARIABLE INTO DE ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; GET NEXT CHAR FROM INPUT STRNG, TST FOR LITERAL IS IT A QUOTE -START OF A LITERALNO, GO FIND ADDR OF VAR YES, GO BUILD A LSPT ENTRY THEN JOIN COMMON CODE GET ADDR OF NEXT VARIABLE IS IT A STRING ADDR OF NEXT VAR RET IF STRING VAR CLEAR STACK CLEAR STACK ERROR CODE FOR SYNTAX ERR GO TO ERROR ROUTINE

; ; ; ;

RESTORE REGISTERS CLEAR STACK SYNTAX ERROR CODE PRINT ERROR MESSAGE

; ; ; ; ; ; ; ; ; ; ;

INPUT FILE NAME STRING ADDR OUTPUT FILE NAME STRING ADDR KEY STRING ADDR RECORD TYPE (A/B/C) SORT ORDER (A/D) RECORD SIZE STARTING POSITION OF KEY ENDING POSITION OF KEY HOLDS EOS ADDR INPUT DCB OUTPUT DCB

54

Chapter 6

BASIC Overlay Routine


This example shows how the tables in the Communications Region can be manipulated so that a BASIC program can load and execute overlays. The overlay program will add statements to an executing BASIC program while preserving all the current variables. The calling sequence to be used is:
100 DEF USRl=&HE000 : Address of overlay program . : Main body of application program . . 300 F$="FILE1/BAS" : File containing overlay 310 Z=USR1(500) : Replace lines 500 thru the end . : of the program with the . : statement from FILE1/BAS.) 320 GOSUB 500 : Execute the overlay . . . 500 REM START OF OVERLAY AREA . .

Level II ROM ---------------Communications Region ---------------DOS Nucleus ---------------Disk BASIC ---------------PST ---------------VLT ---------------FSL ---------------String Area ---------------Overlay Program

<--- this table needs to be modified <--- this table needs to remain intact

end of memory --->

The operating assumptions for this example will be the same as those in chapter 5. Note, overlay files containing the ASCII file must have been saved in the A mode. The program itself will be considerably different, how-ever. For instance, there will be no use of DOS Exits. This means that the CR will not need modification so there will be no need for an initial entry point. One parameter will be passed in the calling sequence while the other one will have an agreed name so that it can be located in the VLT. When a BASIC program is executing there are three major tables that it uses. First is the PST where the BASIC statements to be executed have been stored. Second is the VLT where the variables assigned to the program are stored, and the third table is the FSL which represents available memory. All of these tables occur in the order mentioned. The problem we need to overcome in order to support overlays is to find a way to change the first table while maintaining the contents of the second one. A diagram of memory showing the tables follows.

Fortunately this can be accomplished quite easily. By moving the VLT to the high end of FSL we can separate it from the PST. Then the overlay statements can be read from disk and added to the PST. Obviously the PST would either grow or shrink during this step unless the overlay being loaded was exactly the same size as the one before it. After the overlay statements have been added the VLT is moved back so it is adjacent to the PST. Then the pointers to the tables moved are updated and control is returned to the BASIC Execution Driver. The overlay loader used in this example assumes that the file containing the overlay statements is in ASCII format. This means that each incoming line must be tokenized before being moved to the PST. To speed up processing the loader could be modified to accept tokenized files. There is no limit to the number of overlays that can be loaded. The program will exit with an error if a line number less than the starting number is detected. The loader does not test for a higher level overlay destroying a lower one, this would be disastrous - as the return path would be destroyed. A sample program to load three separate overlays is given as an example.

55

100 110 120 130 140 150 160 170 180 190

A = 1.2345 B = 1 IF B = 1 THEN IF B = 2 THEN IF B = 3 THEN Z = USR1(500) GOSUB 500 B = B + 1 IF B > 3 THEN GOTO 120

F$ = "FILE1" F$ = "FILE2" F$ = "FILE3"

110

500 510 520 530 540 550 560 570 580

PRINT"OVERLAY #1 ENTERED" PRINT A C = 25 D = 30 E = C+D+A PRINT "C = ";C PRINT "D = ";D PRINT "E = ";E RETURN

Contents of File 1

500 510 520 530 540 550 560 570 580 590 600 500 510 520 530

PRINT "OVERLAY #2 ENTERED" PRINT A C = C + 1 D = D + 1 E = E + 1 REM REM REM REM PRINT "C, D, E =";C,D,E RETURN PRINT "OVERLAY #3 ENTERED" A = A + 1 PRINT "A = ";A RETURN

Contents of File 2

Contents of File 3

00100 00110 00120 00130 00140 00150 00160 00170 00180 00190 00200 00210 00220 00230 00240 00250 00260 00270 00280 00290 00300 00310 00320 00330 00340 00350 00360 00370 00380 00390 00400 00410 00420 00430 00440 00450 00460 00470 00481 00490 00500 00510 00520 00530 00540 00550 00560

ORG 0F000H OPEN EQU 4424H ; DOS ADDRESS READ EQU 4436H ; DOS ADDRESS ERN EQU 12 ; DISK DCB ADDRESS NRN EQU 10 ; DISK DCB ADDRESS EOF EQU 8 ; DISK DCB ADDRESS ;* ;* ENTRY POINT FOR OVERLAY LOADING OF BASIC PROGRAMS ;* PUSH AF ; SAVE ALL REGISTERS PUSH BC PUSH DE PUSH HL LD HL,-1 ; INITIALIZE SECTOR COUNT LD (RCOUNT),HL ; TO MINUS 1 LD HL,00 ; SO WE CAN LOAD CSP ADD HL,SP ; LOAD CSP LD (CSP),HL ; SAVE FOR RESTORATION LD DE,(4121H) ; LINE NO TO START OVERLAY LD (LINE),DE ; SAVE FOR FUTURE REF LD A,(40AFH) ; FUNCTION VALUE TYPE LD (TYPE),A ; MUST BE RESTORED AT END ;* ;* BLANK FILL DCB BEFORE MOVING NAME INTO IT ;* LD B,32 ; NO. OF BYTES TO BLANK LD HL,DCB ; DCB ADDR LD A,20H ; ASCII BLANK BFL LD (HL),A ; MOVE ONE BLANK INC HL ; BUMP TO NEXT WORD DJNZ BFL ; LOOP TILL DCB FILLED ;* ;* GET OVERLAY FILE NAME FROM VARIABLE F$ ;* MOVE IT INTO THE BLANKED DCB ;* LD HL,LFN ; STRING FOR COMMON VAR NAME CALL 2540H ; GET ADDR OF F$ RST 20H ; MAKE SURE IT'S A STRING JR Z,OK ; ZERO IF STRING JP ERR ; WRONG TYPE OF VARIABLE OK LD HL,(4121H) ; GET ADDR OF F$ INTO HL LD DE,DCB ; DCB ADDR CALL 29C8H ; MOVE F$ NAME TO DCB ;* ;* INITIALIZE ALL LOCAL VARIABLES ;* LD A,0 ; SET PASS FLAG TO ZERO

00570 00580 00590 00600 00610 00620 00630 00640 00650 00660 00670 00680 00690 00700 00710 00720 00730 00740 00750 00760 00770 00780 00790 00800 00810 00820 00830 00840 00850 00860 00870 00880 00890 00900 00910 00920 00930 00940 00950 00960 00970 00980 00990 01000 01010 01020 01030 01040 01050 01060 01070 01080 01090 01100 01110 01120 01130 01140 01150 01160 01170 01180 01190 01200 01210 01220 01230 01240 01250 01260 01270 01280 01290 01300 01310 01320 01330 01340 01350 01360 01370 01380 01390 01400 01410 01420 01430 01440 01450 01460 01470 01480

LD LD ;* ;* ;* ;* ;* ;* ;*

(PF),A (FI),A

; PASS FLAG ; SECTOR BUFFER INDEX

LOCATE ADDR OF VARIABLE ASSIGNED TO FUNCTION CALL. IT MUST BE RECOMPUTED AFTER THE OVERLAY HAS BEEN LOADED BECAUSE THE VLT WILL NAVE BEEN MOVED. NEXT, ALLOCATE SPACE IN THE FSL FOR THE SECTOR BUFFER USED FOR READING THE OVERLAY FILE. LD ADD PUSH LD ADD LD POP LD ADD LD LD PUSH LD LD LD XOR SBC HL,00 HL,SP HL BC,20 HL,BC (VARADR),HL HL BC,-256 HL,BC (BADDR),HL SP,HL HL DE,(40F9H) (CEPST),DE HL,(40FBH) A HL,DE (LSVLT),HL ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; SO WE CAN LOAD CSP HL = CSP SAVE CSP AMT TO BACKSPACE CSP GIVES CSP - 20 OR ADDR OF FUNCTION VARIABLE SAVE STK ADDR OF VAR RESTORE CSP TO HL AMT OF SPACE TO ALLOCATE IN FSL FOR SECTOR BUFFER COMPUTE NEW CSP START OF SECTOR BUFFER IS ALSO NEW CSP CURRENT END OF PST SAVE FOR COMPUTATIONS START OF ARRAYS CLEAR CARRY COMPUTE OFFSET FROM START OF VLT TO START OF ARRAYS SAVE OFFSET

;*

;*

;* ;* ;* ;*

LD

LD CALL LD ;* ;* ;*

DE,(LINE) 1B2CH (40F9H),BC

; FIND ADUR OF LINE WHERE ; OVERLAY STARTS IN PST ; MAKE IT TEMP END OF PST

COMPUTE LENGTH OF VLT LD LD XOR SBC INC LD POP LD ADD LD XOR SBC LD PUSH POP LD LD LDIR DE,(CEPST) HL,(40FDH) A HL,DE HL (LVLT),HL HL BC,-50 HL,BC BC,(LVLT) A HL,BC (SNVLT),HL HL DE HL,(CEPST) BC,(LVLT) ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ORGINAL END OF PST START OF FSL CLEAR CARRY GIVES LNG -1 OF VLT CORRECT FOR -1 SAVE LENGTH OF VLT RESTORE CSP TO HL ASSUMED STK LENG NEEDED GIVE END OF TEMP VLT NOW, SUBTRACT LENGTH OF VLT FROM END TO GET START ADDRESS SAVE END OF TEMP VLT SO WE CAN LOAD IT INTO DE START OF OLD PST SIZE OF VLT MOVE VLT TO TEMP LOC.

;* ;* ;*

BEGIN OVERLAY LOADING LD LD LD CALL CALL JR CALL JR DE,DCB HL,(BADDR) BC,0 OPEN GNL Z,OUT ATOB LOOP ; ; ; ; ; ; ; ; ; DCB FOR OVERLAY FILE SECTOR BUFF ADDR SPECIFY SECTOR I/O OPEN OVERLAY FILE GET NEXT LINE FROM FILE ZERO IF NO MORE LINES IN OVERLAY FILE ADD LINE TO PST LOOP TILL FILE EXHAUSTED

LOOP ;* ;* ;* ;* ;* OUT

OVERLAY STATEMENTS HAVE BEEN ADDED. RESET POINTERS TO VLT AFTER MOVING IT DOWN (ADJACENT TO PST). LD LD INC INC LD LD LDIR INC PUSH LD LD ADD LD POP LD HL,(SNVLT) DE,(40F9H) DE DE (40F9H),DE BC,(LVLT) DE DE HL,(40F9H) BC,(LSVLT) HL,BC (40FBH),HL HL (40FDH),HL ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; START OF TEMP VLT CURRENT END OF PST LEAVE TWO BYTES OF ZEROS AT END OF PST SAVE START ADDR OF NEW VLT LENGTH OF VLT MOVE VLT TO END OF PST GIVES ADDR OF FLS SAVE FSL ADDR START OF VLT PLUS LNG OF SIMP VAR GIVES ADDR OF ARRAYS PTR SAVE NEW ARRAYS POINTER HL = NEW FSL ADDR UPDATE FSL

;* ;* ;* ;*

COMPUTE DISTANCE VLT HAS MOVED AND UPDATE THE ADDR OF THE FUNCTION VARIABLE BEING CARRIED ON THE STACK.

56

01490 01500 01510 01520 01530 01540 01550 01560 01570 01580 01590 01600 01610 01620 01630 01640 01650 01660 01670 01680 01690 01700 01710 01720 01730 01740 01750 01760 01770 01780 01790 01800 01810 01820 01830 01840 01850 01860 01870 01880 01890 01900 01910 01920 01930 01940 01950 01960 01970 01980 01990 02000 02010 02020 02030 02040 02050 02060 02070 02080 02090 02100 02110 02120 02130 02140 02150 02160 02170 02180 02190 02200 02210 02220 02230 02240 02250 02260 02270 02280 02290 02300 02310 02320 02330 02340 02350 02360 02370 02380 02390 02400

UP UP1

LD LD RST JR PUSH PUSH XOR POP POP JR XOR SBC PUSH LD LD INC LD POP ADD PUSH POP LD LD INC LD

DE,(CEPST) HL,(40F9H) 18H NC,UP HL DE A HL DE UP1 A HL,DE HL HL,(VARADR) C,(HL) HL B, (HL) HL HL,BC HL DE HL,(VARADR) (HL),E HL (HL),D

; ; ; ; ;

ORIGINAL START OF VLT CURRENT START OF VLT COMPARE THE ADDRESSES NEW VLT WAS MOVED UP REVERSE OPERANDS

; CLEAR CARRY ; RESTORE OPERANDS ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; GO COMPUTE DISTANCE CLEAR CARRY FOR SUB COMPUTE ANT VLT HAS MOVED SAVE DISTANCE THEN ADDR IT TO ADDR CARRIED ON STK BUMP TO MSB OF ADDR BC = ADDR OF VAR THAT WAS CARRIED ON STK GET DISPLACEMENT GET NEW ADDR (BECAUSE VLT HAS BEEN MOVED SO WE CAN LOAD IT INTO LOAD NEW ADDR INTO DE REFETCH STK ADDR LSB OF FUNCTION VAR ADDR NEXT BYTE ADDR ON STK MSB OF FUNCTION VAR ADDR

;* ;*

;* ;* ;*

RESET TYPE TO IT'S ORGINAL VALUE LD LD LD LD POP POP POP POP RET A,(TYPE) (40AFH),A HL,(CSP) SP,HL HL DE BC AF ; ; ; ; ; GET MODE FLAG WHEN ENTERED RESTORE MODE TO ORIGINAL RESET CSP TO IT'S ORIGINAL VALUE RESTORE REGISTERS

; RETURN TO BASIC ;* ;* GNL - GETS NEXT LINE OF BASIC PROGRAM PROM A FILE ;* MOVES IT TO BASIC LINE BUFFER AREA AND THEN ;* TOKENIZES IT. ;* FILE IS ASSUMED TO BE IN ASCII FORMAT. LINES ARE ;* TERMINATED BY A CARRIAGE RET. (0D). ;* GNL LD A,(PF) ; GET PASS FLAG OR A ; IS IT TIME TO READ SECTOR JR NZ,GNL5 ; NO IF NON-ZERO GNL3 LD A,0 ; RESET SECTOR BUFF INDEX LD (FI),A ; TO ZERO LD HL,(RCOUNT) ; PREPARE TO TEST FOR INC HL ; END OF FILE. BUMP COUNT LD (RCOUNT),HL ; OF SECTORS READ LD BC,0 ; READ NEXT SECTOR LD DE,DCB ; OVERLAY DCB ADDR LD HL,(BADDR) ; SECTOR BUFF ADDR CALL READ ; READ NEXT SECTOR LD A,1 ; RESET PASS FLAG LD (PF),A ; TO DATA IN BUFFER GNL5 LD DE,(RCOUNT) ; NOW TEST POE END OF FILE LD HL,(DCB+ERN) ; LAST SECTOR NO FROM DCB XOR A ; CLEAR CARRY FOR SUB SBC HL,DE ; HAS LAST SECTOR BEEN READ JR NZ,GNL10 ; NON-ZERO IF NOT LAST SECT LD A,(DCB+EOF) ; IN LAST SECTOR. END OF D LD B,A ; DATA REACHED YET? LD A,(FI) ; CURRENT SECTOR INDEX SUB B ; MUST BE LE TO EOD INDEX JR C,GNL10 ; CARRY IF NOT END OF DATA XOR A ; SIGNAL END OF FILE RET ; RET TO MAIN PGM GNL10 LD HL,(BADDR) ; SECTOR BUFF ADDR LD A,(FI) ; CURRENT BUFF INDEX LD C,A ; FOR 16 BIT ARITH LD B,0 ; DITTO ADD HL,BC ; CURRENT LINE ADDR IN BUFF LD DE,(40A7H) ; BA LINE BUFF ADDR GNL15 LD A,(HL) ; MOVE LINE FROM SECT BUFF LD (DE),A ; TO BASIC LINE BUFF INC DE ; BUMP DEST ADDR INC C ; COUNT 1 CHAR MOVED JR C,GNL3 ; JMP IF LINE OVERFLOWS ;* ; SECTOR INC HL ; NO OVERFLOW, BUMP FETCH SUB 0DH ; ADDR. TEST FOR END OF LINE JR NZ,GNL15 ; LOOP TILL END OF LINE DEC DE ; BKSPC 1 CHAR IN LINE BUFF LD (DE),A ; AND TERM IT WITH A ZERO LD A,C ; SAVE ENDING BUFF INDEX LD (FI),A ; FOR NEXT LINE OR A ; SIGNAL MORE DATA

02410 02420 02430 02440 02450 02460 02470 02480 02490 02500 02510 02520 02530 02540 02550 02560 02570 02580 02590 02600 02610 02620 02630 02640 02650 02660 02670 02680 02690 02700 02710 02720 02730 02740 02750 02760 02770 02780 02790 02800 02810 02820 02830 02840 02850 02860 02870 02880 02890 02900 02910 02920 02930 02940 02950 02960 02970 02980 02990 03000 03010 03020 03030 03040 03050 03060 03070 03080 03090 03100 03110 03120 03130 03140 03150 03160 03170 03180 03190 03200 03210 03220 03230 03240 03250 03260

RET ; RET TO CALLER ;* ;* TOKENIZE LINE IN BUFFER. THEN ADD IT TO PST ;* ATOB LD HL,(40A7H) ; LINE BUFFER ADDR CALL 1E5AH ; GET BINARY LINE NO PUSH DE ; SAVE IT PUSH HL ; SAVE LINE BUFF ADDR LD HL,(LINE) ; BEG OVERLAY LINE NO RST 18H ; COMPARED W/CURRENT LINE JR Z,ATOB5 ; OK IF EQUAL JR NC,ERR ; ERR IF INCOMING LESS ;* ; THAN OVERLAY LINE NO ATOB5 POP HL ; RESTORE LINE ADDR CALL 1BC0H ; TOKENIZE LINE LD HL,(40F9H) ; CURRENT END OF PST PUSH HL ; SAVE ADDR OF THIS LINE ADD HL,BC ; ADD LNG OF NEW LINE LD (40F9H),HL ; START OF NEXT LINE PUSH HL ; SO WE CAN POP DE ; LOAD IT INTO DE ;* ;* UPDATE POINTER TO NEXT LINE IN NEW LINE BEING ADDED. ;* THEN MOVE BINARY LINE NO. FOR THIS LINE TO PST. ;* POP HL ; ADDR OF THIS LINE IN PST LD (HL),E ; LSB OF ADDR NEXT LINE INC HL LD (HL),D ; MSB OF ADDR NEXT LINE INC HL ; START OF BIN LINE NO POP DE ; BINARY LINE NO LD (HL),E ; LSB OF LINE NO INC HL LD (HL),D ; MSB OF LINE NO INC HL ; BUMP TO FIRST CHAR IN LINE EX DE,HL ; DE = PST FOR LINE LD HL,(40A7H) ; TOKENIZED LINE ADDR DEC HL DEC HL ATOB10 LD A,(HL) ; GET A TOKENIZED BYTE LD (DE),A ; MOVE IT TO PST INC HL INC DE OR A ; TEST OF EOS JR NZ,ATOB10 ; JMP IF NOT END OF STAT. LD (DE),A ; OF MACHINE ZEROS INC DE LD (DE),A RET ; RET TO CALLER ;* ;* ERROR PROCESSING - RECOVER STACK SPACE ;* ERR POP AF ; CLEAR STACK POP AF ; CLEAR STACK POP AF ; CLEAR STACK LD HL,0 ; DEALLOCATE SECTOR BUFFER ADD HL,SP ; CSP LD BC,256 ; SIZE OF SECTOR BUFF ADD HL,BC ; COMPUTE NEW CSP LD SP,HL ; SETUP NEW CSP ERR10 POP AF ; CLEAR STACK POP AF ; CLEAR STACK POP AF ; CLEAR STACK POP AF ; CLEAR STACK POP AF ; CLEAR STACK LD A,2 ; CODE FOR SYNTAX ERROR JP 1997H ; GIVE ERR, RTN TO BASIC ;* ;* CONSTANTS AND COUNTERS ;* LINE DEFW 0 ; OVERLAY LINE NO CSP DEFW 0 ; HOLDS CSP ON ENTRY TYPE DEFB 0 ; ORIGINAL DATA TYPE LFN DEFM 'F$' ; COMMON VARIABLE NAME DEFB 0 DCB DEFS 32 ; OVERLAY DCB BADDR DEFW 0 ; SECTOR BUFF ADDR ON STK VARADR DEFW 0 ; VARIABLE ADDR ON STK CEPST DEFW 0 ; CURRENT END OF PST LVLT DEFW 0 ; LENGTH OF VLT SNVLT DEFW 0 ; START ADDR OF NEW VLT LSVLT DEFW 0 ; LENGTH OF SIMP VAR VLT PF DEFB 0 ; PASS FLAG FI DEFB 0 ; SECTOR BUFF INDEX RCOUNT DEFW -1 ; COUNT OF SECTORS READ END

57

Chapter 7 !!!!!!!!!!!!

BASIC Decoded: New ROMs

The comments in chapter 8 are based on the original three chip ROM set, if you have a 2 chip ROM configuration your dissassembly will probably be slightly different. Differences between the latest 'MEM SIZE?' ROMs and the old ROMs are given below. Locations with an asterisk next to them have different contents than the next chapter.

When running a Disassembler be careful to check the page sequence where differences occur. This comment chapter was designed to be used in conjunction with a disassembler that produces 62 lines per page. The Apparat NEWDOS plus Disassembler was used during the books production.

0050 0D 0051 0D 0052 1F 0053 1F 0054 01015B 0057 1B 0058 0A 0059 *00 005A 08 005B 1809 005D 19 005E 2020

DEC DEC RRA RRA LD DEC LD NOP EX JR ADD JR

-------------------------

Enter no shift 0D) * ASCII values Enter shift (0D) Clear no shift (1F) Clear shift (1F) BREAK ns (01) / BREAK shift (01) / up arrow ns (5B) Up arrow shift (1B) Down arrow no shift (0A) Down arrow shift (00) Left arrow no shift (08) Left arrow shift (18) / right arrow no shift (09) Right arrow shift (19) Space no shift (20) / space shift (20)

00FC *210E01 LD 0105 0106 0107 0108 010A 010B 010C 4D 45 4D *2053 *49 *5A *45 LD LD LD JR LD LD LD

--- Address of 'R/S L2 BASIC' message --------------M E M Space, S I Z E * MEM SIZE

58

010D 010E 010F 0110 0111 0113 0116 0117 0118 0119 011A 011B 011C 011D 0120 0123 0124 0125 0126 0127 0128 0129 012A

*00 *52 *2F *53 *204C *322042 *41 53 *49 *43 *0D *00 *C5 *010005 *CD6000 *C1 *0A *A3 *C8 *7A *07 *07 *C3FE03

NOP LD CPL LD JR LD LD LD LD LD DEC NOP PUSH LD CALL POP LD AND RET LD RLCA RLCA JP LD LD JR INC

-----------------------------------------------

Message terminator R * R/S L2 BASIC / S Space, L 2, space, B A C I C Carriage return Message terminator Save active row address Delay count value Delay for 7.33 milliseconds * Debounce routine Restore row address And reload original flags from active row Then combine current flag lists with original flag bits Rtn to caller if zero because row was not active on 2nd test Otherwise we have a legitimately active row Row index * 2 Row index * 4 Return to rest of keyboard driver routine

0248 *0660 024F *0685 02E2 *20ED 02E4 *23

--- Now, delay for 476/703 microseconds --- Then delay for 865/975 microseconds --- If no match, skip to next program on cassette --- We have a character match. Bump to next char of typed in name. --- Go to debounce routine. If legitimate char rtn to 3FE, else rtn to

03FB *C31C01 JP caller. 0683 *20F1 1225 E7 1226 *300B 124D *E7 JR RST JR OR

--- Loop thru block move routine 128 times --- Double precision or string --- Jmp if double precision --- Set status flags --- No change in this comment --- A = device code for printer --- Set current system device to printer ------------------------------------* LPRINT routine

1265 *F24312 JP 2067 2069 206C 206E 2072 2074 2076 2079 207C 207D 207E 2081 2084 2086 2088 208A 208D 208E 2092 2093 2096 3E01 329C40 *C37C20 CDCA41 *FE23 *2006 *CD8402 *329C40 *2B *D7 *CCFE20 *CA6921 *F620 *FE60 *201B *CD012B *FE04 *D24A1E *E5 *21003C *19 LD LD JP CALL CP JR CALL LD DEC RST CALL JP OR CP JR CALL CP JP PUSH LD ADD

DOS Exit * PRINT routine Test for # Jmp if not PRINT # Write header on cassette file * PRINT # routine Set current system device to cassette Backspace over previous symbol in code string Re-examine previous char in code string If end of string write a Carriage Return If end of string turn off cassette and return Not end of string. Convert possible 40 to 60 Then test for @ Jmp if not PRINT @ Evaluate @ expression, result in DE * PRINT @ routine A = MSB, test for @ value > 1023 FC error if @ position > 1023 Save current code string addr HL = starting addr of video buffer Add tab position

59

2097 209A 209B 209D 20A0 20A1 20A2 20A3 20A5 20A6 20A8 20AB 20AD 20B0 20B1 20B3 20B5 20B7 20B9 20BC

*222040 *7B *E63F *32A640 *E1 *CF *2C *18C7 *7E *FEBF *CABD2C *FEBC *CA3721 *E5 *FEC2 *2853 *FE3B *285E CD3723 *E3

LD LD CP LD POP RST INC JR LD CP JP CP JP PUSH CP JR CP JR CALL EX

-----------------------------------------

And save addr in video DCB as cursor addr Then get position within line And truncate it to 63 Then save as current position within line Restore code string addr (starting addr of item list) But make sure a comma follows the tab position DC 2C ',' Go get first variable from item list Reload next element from code string Test for USING token Jmp if USING token Test for TAB token Jmp if TAB token Save current code string addr Test for a comma Go get next item if a comma Not comma, test for semi-colon Go get next item if semi-colon Evaluate next item to be printed Save current code string addr HL = addr of current item

20F6 *C37C20 JP 213A *E67F AND

--- And loop till end of statement (EOS) --- Result in A-reg. Do not let it exceed 127 --- Process next of PRINT TAB statement ----------Remove Erroneous Test For FD error

2166 *C38120 JP 226A 226B 226C 226D 226E 2C1F 2C21 2C23 2C24 2C27 2C28 2C29 2C2A 2C2C 2C2F 2C32 2C33 2C34 2C35 2C36 2C37 2C3A ZC3D 2C40 2C43 *00 *00 *00 *00 *00 *D6B2 *2802 *AF *012F23 *F5 *7E *B7 *2807 *CD2723 *CD132A *1A *6F *F1 *B7 *67 *222141 *CC4D1B *210000 *CD9302 NOP NOP NOP NOP NOP -----------------------------------------

Test for CLOAD? * CLOAD routine Jmp if CLOAD? Signal CLOAD 2C25: CPL A=-1 if CLOAD?, 0000 if CLOAD 2C26: INC HL position to file name Save CLOAD? / CLOAD flag Get next element from code string. Should be file name Set status flags Jmp if end of line Evaluate expression (get file name) Get addr of file name into DE Get file name And move it to L-reg Restore CLOAD? / CLOAD flags Set status register according to flags H=CLOAD?/CLOAD flag, L=file name Save flag and file name in WRA1 If CLOAD call NEW routine to initialize system variables This will cause the drive to be selected when We look for leader and synch byte Restore CLOAD? / CLOAD flag, file name

2FFB *DEC3 2FFD *C344B2

--- These instructions --- Are not used by Level II

60

Chapter 8 !!!!!!!!!!!!

BASIC Decoded: Old ROMs

How to use this book


Unlike most books, this book is made to come apart. Due to the unique nature of the subject matter and the use to which it will be put, its pages may be removed and inserted into a three ring binder. The pages are pre-drilled, and the binding is such that the pages may be removed with little effort. Each page has 62 lines of comments. This exactly matches the Apparat disassembler's output format. Any printer that will print 66 lines per eleven inch length page, will print the disassembler's output so that it may be lined up with the comments exactly. Remove the pages and insert them into a three ring binder. The comments and memory locations are for the original three chip ROM sets, please see chapter 7 for differences on later 2 chip sets.

61

0000 0001 0002 0005 0008 000B 000C 000D 0010 0013 0014 0016 0018 001B 001C 001E 0020 0023 0024 0026 0028 002B 002E 0030 0033 0036 0038 003B 003E 0040 0043 0044 0045 0046 0049 004C 004D 004E 0050 0051 0052 0053 0054 0057 0058 0059 005A 005B 005D 005E 0060 0061 0062 0063 0065 0066 0069 006C 006D 006F

F3 AF C37406 C30040 C30040 E1 E9 C39F06 C30340 C5 0601 182E C30640 C5 0602 1826 C30940 C5 0604 181E C30C40 111540 18E3 C30F40 111D40 18E3 C31240 112540 18DB C3D905 C9 00 00 C3C203 CD2B00 B7 C0 18F9 0D 0D 1F 1F 01015B 1B 0A 1A 08 1809 19 2020 0B 78 B1 20FB C9 310006 3AEC37 3C FE02 D20000

DI XOR JP JP JP POP JP JP JP PUSH LD JR JP PUSH LD JR JP PUSH LD JR JP LD JR JP LD JR JP LD JR JP RET NOP NOP JP CALL OR RET JR DEC DEC RRA RRA LD DEC LD LD EX JR ADD JR DEC LD OR JR RET LD LD INC CP JP

A 0674H 4000H 4000H HL (HL) 069FH 4003H BC B,01H 0046H 4006H BC B,02H 0046H 4009H BC B,04H 0046H 400CH DE,4015H 0013H 400FH DE,401DH 001BH 4012H DE,4025H 001BH 05D9H

03C2H 002BH A NZ 0049H C C

BC,5B01H DE A,(BC) A,(DE) AF,AF' 0066H HL,DE NZ,0080H BC A,B C NZ,0060H SP,0600H A,(37ECH) A 02H NC,0000H

---------- ---------------------------------------------- -------------------------------------------------------

Power on IPL entry -Turn off clock/disk interrupts Clear A-reg, status Go to beginning of IPL sequence *********************************** Compare ****** RST 08 (JP 1C96) Compare value following cont--> These instructions are not used by Level II Jmp to load & execute sector loader RST 10 (JP 1D78) Load and examine next char Save BC - Keyboard routine B = Entry code Go to driver entry routine (3C2) RST 18 (JP 1C90H) Compare DE:HL Save BC - Display routine, printer routine B = Entry code Go to driver entry routine (3C2) RST 20 (JP 25D9H) Determine data type. Save BC B = Entry code Go to driver entry routine (3C2) RST 28 (Non DOS - Ret; DOS 2.0 - JP 4BA2H) Load keyboard DCB addr into DE ** Scan keyboard Jmp to keyboard driver RST 30 (Non DOS - Rtn DOS 2.0 - JP 44B4H) Load video DCB addr into DE ***** Video display Jmp to video driver RST 38 (Non DOS - DI, Rtn DOS 2.0 cont--> Load printer DCB ptr ***************************** Jmp to printer driver Go see what's being typed These instructions are not used by Level II Go to driver entry routine Strobe keyboard ******** Wait for keyboard input * Test if any key active Go if key active Loop till some key pressed ENTER, no shift (0D) *************** see note--> * ENTER, shift (0D) CLEAR, no shift (1F) CLEAR, shift (1F) BREAK ns (01), BREAK shift (01), UP arrow ns (5B) Up arrow, shift (1B) Down arrow, no shift (0A) Down arrow, shift (00) Left arrow, no shift (08) Left arrow, shift (18): Right arrow, ns (09) Right arrow, shift (19) Space, ns (20): Space, shift (20) Decrement cycle count *** Delay **** see note--> * Test if count zero Combine LSB/MSB of count Loop until delay count exhausted Rtn to caller Reset IPL entry ******************** Reset ******* Get controller status see note--> Test for controller present Status usually FF if no EI NC if controller addressable. Join common IPL code

63

0005 0008

* ************************************************************* : RST 08 with next input symbol. : Syntax error if unequal

002E

* *************************************************************

0033 0038 003B

* ************************************************************* : JP(4518H) Entry pt. for all interrupts * *************************************************************

0049

* *************************************************************

0050

* Table for keyboard routine at 3E3H ************************** * * ASCII values for ENTER, CLEAR, BREAK, UP ARROW, * DOWN ARROW, LEFT ARROW, RIGHT ARROW and SPACE

0060

* Delay for ((BC-1) * 26 + 17) * 2.255T-states ****************

0066

* ************************************************************* : Status = 00 - If EI (Expansion Interface) present and DISK : 80 - If EI and DISK not ready :ready : FF - If EI off or not present

64

0072 0075 0078 007B 007E 0080 0083 0085 0086 0087 0088 008A 008B 008E 0091 0093 0096 0098 0099 009A 009B 009C 009D 009F 00A1 00A3 00A4 00A5 00A6 00A8 00AB 00AC 00AF 00B2 00B5 00B8 00BB 00BE 00C0 00C1 00C2 00C4 00C7 00C8 00C9 00CA 00CC 00CD 00CE 00CF 00D0 00D1 00D2 00D4 00D6 00D9 00DA 00DD 00DE 00DF

C3CC06 118040 21F718 012700 EDB0 21E541 363A 23 70 23 362C 23 22A740 112D01 061C 215241 36C3 23 73 23 72 23 10F7 0615 36C9 23 23 23 10F9 21E842 70 31F841 CD8F1B CDC901 210501 CDA728 CDB31B 38F5 D7 B7 2012 214C43 23 7C B5 281B 7E 47 2F 77 BE 70 28F3 1811 CD5A1E B7 C29719 EB 2B 3E8F

JP LD LD LD LDIR LD LD INC LD INC LD INC LD LD LD LD LD INC LD INC LD INC DJNZ LD LD INC INC INC DJNZ LD LD LD CALL CALL LD CALL CALL JR RST OR JR LD INC LD OR JR LD LD CPL LD CP LD JR JR CALL OR JP EX DEC LD

06CCH DE,4080H HL,18F7H BC,0027H HL,41E5H (HL),3AH HL (HL),B HL (HL),2CH HL (40A7H),HL DE,012DH B,1CH HL,4152H (HL),0C3H HL (HL),E HL (HL),D HL 0096H B,15H (HL),0C9H HL HL HL 00A1H HL,42E8H (HL),B SP,41F8H 1B8FH 01C9H HL,0105H 28A7H 1BB3H C,00B5H 10H A NZ,00D6H HL,434CH HL A,H L Z,00E7H A,(HL) B,A (HL),A (HL) (HL),B Z,00C7H 00E7H 1E5AH A NZ,1997H DE,HL HL A,8FH

-------------------------------------------------------------------------------------------------------------------

No disk go to BASIC 'READY' prompt Here on power on or reset with no disk *********** Move initialization data to communication area Number of bytes to move Move ROM 18F7-191D to RAM 4080-40A6 see note--> Continue with comm. region initialization 3A to 41E5 LD A,(2C00) Bump to 41 E6 0 to 41 E6 Bump to 41 E7 2C to 41 E7 HL = 41E8. Set input buffer pointer (40A7) to keyboard buffer area (41 E8) Addr field for JP instr Initialize 4152-41A5 to JP 12D this gives an L3 Error if disk basic commands are attempted C3 to 4152 gives ( JP 2D ) Bump to LSB of address field 2D to 4153 gives ( JP 012D ) 23 Bump to MSB of address field 01 to 4154 gives ( JP 012D) Bump to addr. of next JP instr Repeat 28 times (84 locations) loop count for DOS EXIT RETURNS C9 to 41 A6 gives (RETURN INSTRUCTION) 41A9: Ret Clear DOS EXIT vectors : to RETURNS 41E2: Ret repeat: (gives JP 012D) in locs 4152 - 41A5 Load HL with addr so we can store 0 to 42 E8 Stack addr. during IPL is 41F8 Initialize BASIC printers and variables Clear screen 'MEMORY SIZE ?' message pntr Output message Print '? ' and wait for user input If break was hit, ask again Examine a character from response Set status flags Jmp if not end of response If CR only entered, then determine cont--> Start at 17220 and work towards 65535 testing for LSB of next test addr :memory Combine w/MSB of next test addr Memory up thru 65535 scanned. cont--> Fetch original contents of memory test location Save it for restoration Complement it (gives test pattern) Store test pattern. Compare contents of mem loc with test pattern Restore original value Address exists. Go test for min amt of memory Address non-existent. Bump to next addr & test Get binary equivalent of value :again into DE/A SN error if NZ HL - memory size Size minus one Test memory size value Comparison value make sure it's there.

65

0075

* *************************************************************

007E

: : : : : : : : : : : : : :

Load 4080 408E 4090 4093 4095 4096 4098 4099 409A 409B 409C 40AD 409E

division support routine. Initialize comm. region to: - 408D Division support routine 1E4A Address of user subroutine E64DDB Random number seed IN A,(00) INP skeleton instruction . RET OUT A,00 OUTP skeleton instruction. RET 00 Last character typed 00 Error count 00 Count of chars in current line Output device type 00 Size of display line (64 characters) 30 Line size during PRINT Start of string area Initial BASIC line number Address of PROGRAM STATEMENT TABLE (PST)

: 40A0 - 434C : 40A2 FEFF : 40A4 42E9

00C4

: men. size dynamically

00CA

: Go test for min amt required

66

00E1 00E2 00E3 00E4 00E5 00E7 00E8 00EB 00EC 00EF 00F2 00F5 00F6 00F9 00FC 00FF 0102 0105 0106 0107 0108 0109 010A 010B 010D 010E 010F 0110 0111 0112 0113 0114 0115 0116 0118 0119 011A 011B 011C 011E 011F 0120 0121 0122 0124 0125 0127 0128 0129 012A 012B 012C 012D 012F 0132 0133 0134 0137 013A 013B

46 77 BE 70 20CE 2B 111444 DF DA7A19 11CEFF 22B140 19 22A040 CD4D1B 211101 CDA728 C3191A 4D 45 4D 4F 52 59 2053 49 5A 45 00 52 41 44 49 4F 2053 48 41 43 4B 204C 45 56 45 4C 2049 49 2042 41 53 49 43 0D 00 1E2C C3A219 D7 AF 013E80 013E01 F5 CF

LD LD CP LD JR DEC LD RST JP LD LD ADD LD CALL LD CALL JP LD LD LD LD LD LD JR LD LD LD NOP LD LD LD LD LD JR LD LD LD LD JR LD LD LD LD JR LD JR LD LD LD LD DEC NOP LD JP RST XOR LD LD PUSH RST

B,(HL) (HL),A (HL) (HL),B NZ,00B5H HL DE,4414H 18H C,197AH DE,0FFCEH (40B1H),HL HL,DE (40A0H),HL 1B4DH HL,0111H 28A7H 1A19H C,L B,L C,L C,A D,D E,C NZ,0160H C,C E,D B,L D,D B,C B,H C,C C,A NZ,016BH C,B B,C B,E C,E NZ,016AH B,L D,(HL) B,L C,H NZ,016DH C,C NZ,0169H B,C D,E C,C B,E C E,2CH 19A2H 10H A BC,803EH BC,013EH AF 08H

--- Fetch contents of memory and save in B reg --- Store test pattern --- Compare test pattern stored with pattern in A reg --- Restore original value of memory location --- Specified memory size not present, ask again --- Amt of memory - 2 --- DE = 17428 (dec.) --- Test for a minimum amount of mem (17428) --- OM error if C. Insufficient memory --- Load constant for default size of see note--> --- Save memory size --- Subtract size of string area from see note--> --- Save starting addr of string area --- Initialize all BASIC variables and pointers ---'RADIO . . .BASIC' message pntr --- Output message --- Go to ready routine --- M ** 'MEMORY SIZE' message *********************** --- E --- M --- 0 --- R --- y --- Space, S --- I --- Z --- E --- 00 - message terminator --- R ** 'RADIO SHACK LEVEL II BASIC' message ******** --- A --- D --- I --- 0 --- Space, S --- H --- A --- C --- K --- Space, L --- E --- V --- E --- L --- Space, I --- I --- Space, B --- A --- S --- I --- C --- 0D - carriage return --- 00 - end of message terminator --- Code for L3 error *************************** --- Jump to error routine and print L3 error --- Position to next character ** ( POINT/SET/RESET) --- A = 0 if POINT entered else POINT (x,y) --- 0135 LD A,80 SET routine A = -1 SET (x,y) --- 0138 LD A,01 RESET routine A = +1 RESET (x,y) --- Save flag indicating POINT/SET/RESET entry --- Examine next char, look for (

67

00EF 00F5

: string area (50 dec. bytes) : ending memory addr.

0105

* *************************************************************

0111

* *************************************************************

012D 0132

* ************************************************************* * *************************************************************

68

013C 013E 013F 0140 0142 0145 0146 0147 0148 014B 014D 0150 0152 0153 0155 0157 0159 015A 015B 015C 015D 015F 0160 0161 0162 0163 0164 0165 0167 0168 0169 016A 016B 016C 016D 016E 0170 0171 0172 0174 0175 0176 0177 017A 017C 017D 017E 017F 0180 0182 0183 0186 0187 0188 0189 018A 018B 018C 018D 018E

28CD 1C 2B FE80 D24A1E F5 CF 2C CD1C2B FE30 D24A1E 16FF 14 D603 30FB C603 4F F1 87 5F 0602 7A 1F 57 7B 1F 5F 10F8 79 8F 3C 47 AF 37 8F 10FD 4F 7A F63C 57 1A B7 FA7C01 3E80 47 F1 B7 78 2810 12 FA8F01 79 2F 4F 1A A1 12 CF 29 C9

JR INC DEC CP JP PUSH RST INC CALL CP JP LD INC SUB JR ADD LD POP ADD LD LD LD RRA LD LD RRA LD DJNZ LD ADC INC LD XOR SCF ADC DJNZ LD LD OR LD LD OR JP LD LD POP OR LD JR LD JP LD CPL LD LD AND LD RST ADD RET

Z,010BH E HL 80H NC,1E4AH AF 08H L 2B1CH 30H NC,1E4AH D,0FFH D 03H NC,0152H A,03H C,A AF A,A E,A B,02H A,D D,A A,E E,A 015FH A,C A,A A B,A A A,A 016DH C,A A,D 3CH D,A A,(DE) A M,017CH A,80H B,A AF A A,B Z,0192H (DE),A M,018FH A,C C,A A,(DE) C (DE),A 08H HL,HL

--- 13C: DC 28 ( for RST 08 --- 13D: CALL 2BlC go evaluate 1st variable (x) --- Result in A-reg --- Compare x coordinate to 128 dec. --- FC error if x => 128 --- Save x coordinate --- Examine next symbol in input string --- Make sure its a , (comma) --- Go evaluate 2nd variable (y) --- Result in A-reg. Compare to 48 dec. --- FC error if y => 48 --- Prepare to divide y coordinate by 3 giving Q+R <----: D = Q : Divide by compound subtraction ---->: Loop till remainder < 3 --- Make remainder positive --- And store it in C --- A = x coordinate --- Times 2 see note ---> --- E = 2 times x --- B = shift count <----: Right shift D/E (Q,2*x) : Two places so that : Bit 1 of E is left in the : Carry. This bit will be : zero if we're on the first column : of a rectangular box, and one if ---->: we're on the 2nd column. --- Now, compute position of point within --- the word according to the formula --- (2*R)+1+(0 or 1 for column 1 or 2) --- Save bit position count --- Clear A and carry flag then --- force CARRY on. <---: Build a bit mask to position a one over --->: the point we're looking for. Save mask in C. --- Compute word address for box, store in DE --- Mask for bit we want --- A = Q from y/3 --- Restore so that DE = addr of box we want --- Fetch the bits for this box --- and ret the status flag --->: Jump if graphics word -- : Else, make it a graphics word <---: B = bits for this display box --- Get entry point flag --- And test it --- A = bits for this box --- Jump if POINT called --- Restore box contents --- Jump if SET called else --- This must be-a RESET call --- Turn bit to be RESET off --- Save mark with bit off in C reg --- Fetch box from memory --- Turn specified bit off --- And restore. Then we're --- Done, prepare to exit after testing for ) --- DC ) --- Return to caller

: : : : : :

69

0150

: : : : : : : :

: Compute the memory address for the specified point. Graphics : area in memory ranges from 3C00 - OFF. Each six bit (2X3) : box is represented by an 8 bit byte starting at 3D00. The boxes are stored in memory as a string of 6 bits, right justified in the byte. The bits in the byte are numbered from right to left (as you would expect) starting at 0 and going thru 5. Bits 6 & 7 are unused. Rectangular coordinates within the box are represented in the box 'byte' as follows: bits 0 & 1 represent the first row, points 0 and one respectively; bits 2 & 3 correspond to the second row, bits 0 and 1, respectively; etc.

70

018F 0190 0192 0193 0195 0196 0197 019A 019B 019D 019E 019F 01A2 01A3 01A5 01A8 01A9 01AB 01AC 01AD 01B0 01B1 01B4 01B5 01B8 01B9 01BC 01BF 01C2 01C4 01C7 01C8 01C9 01CB 01CE 01D0 01D3 01D5 01D8 01D9 01DC 01DF 01E1 01E3 01E6 01E9 01EB 01ED 01F0 01F3 01F5 01F7 01F8 01F9 01FC 01FE 01FF 0201 0203 0205

B1 18F9 A1 C6FF 9F E5 CD8D09 E1 18EF D7 E5 3A9940 B7 2006 CD5803 B7 2811 F5 AF 329940 3C CD5728 F1 2AD440 77 C38428 212819 222141 3E03 32AF40 E1 C9 3E1C CD3A03 3E1F C33A03 ED5F 32AB40 C9 2101FC CD2102 060B 10FE 2102FC CD2102 060B 10FE 2100FC CD2102 065C 10FE C9 E5 2100FB 181B 7E D623 3E00 200D CD012B

OR JR AND ADD SBC PUSH CALL POP JR RST PUSH LD OR JR CALL OR JR PUSH XOR LD INC CALL POP LD LD JP LD LD LD LD POP RET LD CALL LD JP LD LD RET LD CALL LD DJNZ LD CALL LD DJNZ LD CALL LD DJNZ RET PUSH LD JR LD SUB LD JR CALL

C 018BH C A,0FFH A,A HL 098DH HL 018CH 10H HL A,(4099H) A NZ,01ABH 0358H A Z,01BCH AF A (4099H),A A 2857H AF HL,(40D4H) (HL),A 2884H HL,1928H (4121H),HL A,03H (40AFH),A HL A,1CH 033AH A,1FH 033AH A,R (40ABH),A HL,0FC01H 0221H B,0BH 01E1H HL,0FC02H 0221H B,0BH 01EBH HL,0FC00H 0221H B,5CH 01F5H HL HL,0FB00H 0219H A,(HL) 23H A,00H NZ,0212H 2B01H

-------------------------------------------------------------------------------------------------------------------------

SET continues **** Turn on bit in box ************ Restore box and rtn to caller POINT continues ** Isolate bit we're testing for** If bit was on, overflow will occur A = 0 if bit off, = -1 if bit on Save current code string address Save 00 (false) or -1 (true) as current value Restore code string addr Test for closing paren & return to caller INKEY$ routine * Position to next char in code str Save current code string addr Get last char typed during keyboard scan (shift Set status flags @ key) Jmp if shift @ key struck else Scan keyboard once Set status flags for result Jmp if no input Save char typed Clear A-reg status flags Clear shift @ key character A = 1, size of character string to be built Make sure there is room for char string, cont--> A = char typed HL = addr of string in literal string pool area Save character Move string to literal string pool area Load address of 'READY' message and ************** move to current string variable point Data type = String Set current type to string Message address to HL Rtn to caller Clear screen ************** Home cursor command ** Send to video Clear screen command Send to video then return Load current refresh addr **** RANDOM routine **** Save random value : see note --> Rtn to caller Set bit 0 of 4 bit data latch ******************** OUT (FF) 01 B = count for delay loop B = count for delay loop = 80 US Set bit 1 of 4 bit data latch OUT (FF) 02 B = count for delay loop see note --> Delay 3.25X10-6 * 11 * 2.26 a 80 US Clear bits 0 and 1 of 4 bit data latch OUT (FF) 00 B = delay loop count 92 Delay = 3.25X10-6 * 92 * 2.26 = 676 US Rtn to caller Entry to turn off cassette *********************** HL = command to turn off cassette Go to cassette driver Get next token from input string ***************** Test for # A = unit 0 if care of no # x specification Jmp if not # Get unit number in DE cont-->

71

018F 0192

* ************************************************************* * *************************************************************

019D

* *************************************************************

01B1

: Save length, addr at 4023

01BC

* *************************************************************

01C9

* *************************************************************

01D3

* (Uses refresh register contents)*****************************

01D9

* *************************************************************

01E1 : Write one bit on cassette. Assume motor has been turned : on. Called to write clock pulses Requires three steps : consisting of an : OUT (FF) 01 : OUT (FF) 02 : OUT (FF) 00 : Total time for clock pulse is 836 US

01F8

* *************************************************************

01FE

* *************************************************************

0205

: (as integer in 'current' area) in DE

72

0208 0209 020A 020B 020C 020E 0211 0212 0215 0216 0219 021C 021D 021E 0221 0224 0225 0226 0228 022B 022C 022F 0231 0234 0235 0236 0237 0239 023C 023E 023F 0240 0241 0242 0243 0245 0246 0248 024A 024C 024F 0251 0253 0255 0256 0257 0259 025A 025B 025E 025F 0260 0261 0264 0265 0266 0267 0268 026A 026B

CF 2C 7B A2 C602 D24A1E 3D 32E437 E5 2104FF CD2102 E1 C9 2100FF 3A3D40 A4 B5 D3FF 323D40 C9 3A3F3C EE0A 323F3C C9 C5 E5 0608 CD4102 10FB E1 C1 C9 C5 F5 DBFF 17 30FB 0641 10FE CD1E02 0676 10FE DBFF 47 F1 CB10 17 F5 CD1E02 F1 C1 C9 CD6402 E5 C5 D5 F5 0E08 57 CDD901

RST INC LD AND ADD JP DEC LD PUSH LD CALL POP RET LD LD AND OR OUT LD RET LD XOR LD RET PUSH PUSH LD CALL DJNZ POP POP RET PUSH PUSH IN RLA JR LD DJNZ CALL LD DJNZ IN LD POP RL RLA PUSH CALL POP POP RET CALL PUSH PUSH PUSH PUSH LD LD CALL

08H L A,E D A,02H NC,1E4AH A (37E4H),A HL HL,0FF04H 0221H HL HL,0FF00H A,(403DH) H L (0FFH),A (403DH),A A,(3C3FH) 0AH (3C3FH),A BC HL B,08H 0241H 0239H HL BC BC AF A,(0FFH) NC,0243H B,41H 024AH 021EH B,76H 0251H A,(0FFH) B,A AF B AF 021EH AF BC 0264H HL BC DE AF C,08H D,A 01D9H

--- Look for comma following unit number --- DC 2C Comma --- Convert unit from --- - XX to its positive --- Equivalent --- FC error if NC --- A = positive value for unit number --- Entry to define drive **** Select cassette unit ** --- Save current code string address --- Code to turn on cassette --- Turn drive on/off --- Restore code string addr --- Rtn to caller --- Mask for preserving video controller flags --- Get video control bits (32/64 char) --- Combine with cassette --- Control bits :controller) --- Write reg A to port 255 (cassette/video --- Save new value as current control value --- Return to caller --- Blink '*' when reading cassette ******* cont --> * --- Gives 2A/20/2A . . . *, ,*, ,. . . --- Store new display value --- Rtn to caller --- Entry to read cassette **************** cont --> * --- Saves callers register --- B = number of bits to read --- Read 1 bit. Assembled into a byte in the A-reg --- Loop till 8 bits (one byte) read --- Restore caller's --- register --- Return --- Read 1 data bit from cassette ********* cont --> * --- Save caller's registers <---: Begin tape motion. Stop when first start pulse :Input and test for clock pulse :is sensed :Not there, loop till it shows up --->: Now delay for 476 micro seconds --- After sensing start pulse --- Reset outsig flip/flop so we can read data pulse --- Then delay for 865 micro seconds before reading --- The data pulse --- Read data pulse --- Save it as B --- A = prior bits for this byte --- Shift data bit into carry flag --- Combine this data bit with others --- Save byte thus far --- Reset outsig flip/flop --- Restore data byte --- Other registers --- And return --- Call 0264 to write clock pulse --- Entry to write byte --- Save caller's registers --- BC --- DE see note ----> --- C = no of bits to write --- D = data word to be written bit by bit --- Write clock bit

73

0212

* *************************************************************

022C

* Fetch display word that holds an ****************************

0235

* Reads one byte then returns *********************************

0241

* Called 8 times to read one byte *****************************

0265

: : : : :

Writing a byte is done by serially writing each bit in the byte. Each bit is preceeded by a clock pulse followed by another pulse if the bit is a one or no pulse if the bit is a zero. The time from the clock pulse to the bit pulse is approx 1 millisecond

74

026E 026F 0270 0271 0273 0276 0277 0279 027A 027B 027C 027D 027E 0280 0282 0284 0287 0289 028A 028D 028F 0291 0293 0296 0297 0298 029B 029D 029F 02A1 02A4 02A7 02A8 02A9 02AC 02AF 02B2 02B5 02B8 02BB 02BD 02C0 02C3 02C6 02C7 02CA 02CC 02CE 02D1 02D4 02D6 02D8 02DA 02DB 02DC 02DE 02E1 02E2 02E4 02E5

7A 07 57 300B CDD901 0D 20F2 F1 D1 C1 E1 C9 0687 10FE 18F2 CDFE01 06FF AF CD6402 10FB 3EA5 18D1 CDFE01 E5 AF CD4102 FEA5 20F9 3E2A 323E3C 323F3C E1 C9 CD1403 22DF40 CDF801 CDE241 318842 CDFE20 3E2A CD2A03 CDB31B DACC06 D7 CA9719 FE2F 284F CD9302 CD3502 FE55 20F9 0606 7E B7 2809 CD3502 BE 20ED 23 10F3

LD RLCA LD JR CALL DEC JR POP POP POP POP RET LD DJNZ JR CALL LD XOR CALL DJNZ LD JR CALL PUSH XOR CALL CP JR LD LD LD POP RET CALL LD CALL CALL LD CALL LD CALL CALL JP RST JP CP JR CALL CALL CP JR LD LD OR JR CALL CP JR INC DJNZ

A,D D,A NC,027EH 01D9H C NZ,026BH AF DE BC HL B,87H 0280H 0276H 01FEH B,0FFH A 0264H 028AH A,0A5H 0264H 01FEH HL A 0241H 0A5H NZ,0298H A,2AH (3C3EH),A (3C3FH),A HL 0314H (40DFH),HL 01F8H 41E2H SP,4288H 20FEH A,2AH 032AH 1BB3H C,06CCH 10H Z,1997H 2FH Z,031DH 0293H 0235H 55H NZ,02D1H B,06H A,(HL) A Z,02E7H 0235H (HL) NZ,02D1H HL 02DAH

--- Get byte to be written --- Set status (carry) if upper bit is one else no --- Save shifted data byte : carry --- Jmp if high bit is zero see note --> --- Else write a one bit --- Count of bits written from this byte --- Not done, go write clock pulse then test data bit --- Restore caller's register : AF --- DE --- BC --- and HL --- Rtn to caller --- B = count of times to delay ********************** --- Delay 3.25 * 10-6 * 135 * 2.26 = 991 US --- Go count no of bits written --- Get unit no and turn on motor ******************** --- Entry to write leader and sync byte --- A = data word to write (all zeroes) --- Write 256 zeros --- Count one byte of zeroes written. Loop till 256 --- Trailer byte is A5 : bytes written --- Write trailer byte as A5 and rtn to caller --- Get unit no., turn on motor ********************** --- Entry to find leader and sync byte --- Zero A, status flags <---: Read cassette : Until a flag of 'A5' is found. We should skip --->: over 256 bytes of zeroes before getting there --- A = ASCII * --- Display ** --- On screen --- Restore code string addr --- Rtn to caller --- Go read 2 bytes from cassette ********* cont --> --- Save execution address --- Turn off drive --- DOS Exit (JP 5B51) --- Set CSP below assumed load address --- Print CR --- A = ASCII * --- Print '*' --- Wait for input from keyboard should be file name --- Jmp if BREAK key hit :to load ---- Examine next character in input stream --- SN error if EOS --- It is a '/' --- Jump if '/' --- Start up cassette. see note--> <---: Read 1 byte : Test for U --->: Loop till an ASCII 'U' is read : B = number of characters to match <-----: Get a character from type in 2C0 : : Test for zero, end of name : : Go start load, else : : Read 1 byte from cassette and : : Compare with type : : Bump to next char of type --->: : If no match, skip to next prog on cassette ----->: Loop till 6 chars match or end of cont -->

75

0271

: (Go delay for approx 1 ms)

027E

* ************************************************************

0284

* ************************************************************

0293

* *************************************************************

02A9

* Load an assembler program from cassette *********************

: Position to first data byte by skipping : over leader until a U is found

02E5

: type in command

76

02E7 02EA 02ED 02EF 02F1 02F3 02F5 02F8 02F9 02FC 02FD 02FE 0301 0302 0303 0304 0305 0307 030A 030B 030D 030F 0312 0314 0317 0318 031B 031C 031D 031E 0321 0322 0323 0326 0328 0329 032A 032B 032C 032F 0332 0333 0334 0335 0338 033A 033B 033E 033F 0342 0345 0346 0347 0348 034B 034D 0350 0352 0353 0355

CD2C02 CD3502 FE78 28B8 FE3C 20F5 CD3502 47 CD1403 85 4F CD3502 77 23 81 4F 10F7 CD3502 B9 28DA 3E43 323E3C 18D6 CD3502 6F CD3502 67 C9 EB 2ADF40 EB D7 C45A1E 208A EB E9 C5 4F CDC141 3A9C40 B7 79 C1 FA6402 2062 D5 CD3300 F5 CD4803 32A640 F1 D1 C9 3A3D40 E608 3A2040 2803 0F E61F E63F

CALL CALL CP JR CP JR CALL LD CALL ADD LD CALL LD INC ADD LD DJNZ CALL CP JR LD LD JR CALL LD CALL LD RET EX LD EX RST CALL JR EX JP PUSH LD CALL LD OR LD POP JP JR PUSH CALL PUSH CALL LD POP POP RET LD AND LD JR RRCA AND AND

022CH 0235H 78H Z,02A9H 3CH NZ,02EAH 0235H B,A 0314H A,L C,A 0235H (HL),A HL A,C C,A 02FEH 0235H C Z,02E7H A,43H (3C3EH),A 02EAH 0235H L,A 0235H H,A DE,HL HL,(40DFH) DE,HL 10H NZ,1E5AH NZ,02B2H DE,HL (HL) BC C,A 41C1H A,(409CH) A A,C BC M,0264H NZ,039CH DE 0033H AF 0348H (40A6H),A AF DE A,(403DH) 08H A,(4020H) Z,0355H 1FH 3FH

--- Blink * on video during load --- Read a byte <-------: Now test if byte is an upper case 8 : Yes, read next two bytes and save cont --> : Is it a < : No, read till '78' or '3C' found : Read number of bytes to load : Save count of bytes to load : Read following two bytes (addr) into HL : Cksum starts with addr : Save 8 bit cksum <--: : Read a byte : : Store it : : Bump store address : : Cksum data byte : : Save cksum -->: : Count 1 byte loaded : Read cksum : Compare w/computed cksum : Cksum OK, keep loading till a '78' found : Cksum error. Display a C : Store C in video memory ------->: Scan till start of next program --- Read one byte from cassette ********************** --- Save LSB see note--> --- Read another byte from cassette --- Save as MSB --- Rtn to caller --- DE = input response address ********************** --- 40DF = will hold execution address --- HL = input addr DE = execution addr location. --- Test for CR if not CR then --- Convert ASCII to binary. Result in DE --- Jmp if no digits found --- Else digit is execution address --- Jmp to addr given in /XXXX command --- Output (A) to screen, printer or tape ************ --- Save character to output --- Rtn if non-DOS --- Get device type code --- Set status flags according to dev type --- A = char to be written --- Restore callers BC --- Write to tape --- Write to printer --- Write to video --- Print --- Save character written --- Test for display memory full --- Update cursor position (0 - 3FH) --- Restore character written --- Restore caller's DE --- Rtn to caller --- Get video control word *************************** --- Test for 32/64 char line --- Addr if cursor --- Jump if 64 characters/line --- Force cursor position --- to be between 3C00 --- and 3FFF

77

02EF

: in 40DF. Wait for input

0314 0317

* ************************************************************* : Read 2 bytes from cassette and assemble as a 16 bit value

031D

* *************************************************************

032A

* ************************************************************* : : -1 : cassette : : 0 : video : : +1 : printer : :-----------------------: :---------------------:

0348

* *************************************************************

78

0357 0358 035B 035C 035F 0360 0361 0362 0365 0368 036B 036C 036F 0371 0374 0375 0376 0378 0379 037B 037E 037F 0380 0381 0382 0383 0384 0387 0388 0389 038B 038C 038F 0392 0393 0394 0396 0397 039A 039B 039C 039D 039E 039F 03A0 03A2 03A4 03A6 03A8 03AA 03AC 03AD 03AF 03B1 03B4 03B5 03B6 03B7 03BA 03BB

C9 CDC441 D5 CD2B00 D1 C9 AF 329940 32A640 CDAF41 C5 2AA740 06F0 CDD905 F5 48 0600 09 3600 2AA740 F1 C1 2B D8 AF C9 CD5803 B7 C0 18F9 AF 329C40 3A9B40 B7 C8 3E0D D5 CD9C03 D1 C9 F5 D5 C5 4F 1E00 FE0C 2810 FE0A 2003 3E0D 4F FE0D 2805 3A9B40 3C 5F 7B 329B40 79 CD3B00

RET CALL PUSH CALL POP RET XOR LD LD CALL PUSH LD LD CALL PUSH LD LD ADD LD LD POP POP DEC RET XOR RET CALL OR RET JR XOR LD LD OR RET LD PUSH CALL POP RET PUSH PUSH PUSH LD LD CP JR CP JR LD LD CP JR LD INC LD LD LD LD CALL

41C4H DE 002BH DE A (4099H),A (40A6H),A 41AFH BC HL,(40A7H) B,0F0H 05D9H AF C,B B,00H HL,BC (HL),00H HL,(40A7H) AF BC HL C A 0358H A NZ 0384H A (409CH),A A,(409BH) A Z A,0DH DE 039CH DE AF DE BC C,A E,00H 0CH Z,03B6H 0AH NZ,03ADH A,0DH C,A 0DH Z,03B6H A,(409BH) A E,A A,E (409BH),A A,C 003BH

--- Rtn to caller --- DOS Exit (JP 59CD) *************************** --- Save callers DE --- Scan keyboard --- Restore callers DE --- Rtn to caller --- Keyboard input routine *************************** --- Zero last char typed following break. --- And current cursor position. --- DOS Exit (JP 598E) --- Save BC --- Buffer = 41E8 (usually) --- Length of buffer = 240 --- Go see what's being typed into buffer --- Save flags --- C = input length --- BC = input length --- HL = end of input area ptr --- Flag end of input with a 00H --- HL= input area ptr --- Restore flags --- Restore BC --- HL = input area ptr - 1 see note--> --- Return w/carry set if BREAK key hit --- Else clear all status flags --- Rtn with HL = input buffer -1 --- Go scan keyboard ********************************* --- Test for any key depressed --- Exit if key pressed --- Else, loop till some entry made --- Clear A then ************************************* --- Set output device = video --- Get printer carriage position --- Set status flags --- Return if printer buffer empty --- Load char to print (carriage ret) --- Save caller's DE --- Call print driver --- Restore caller's DE --- Rtn to caller --- Save callers registers ************ see note --> --- DE --- and BC --- C = character to be printed --- E = new char/line count of 'C', 'D', or 'A' --- Test for skip to next line :printed ----->: Jmp if skip to next line -: Test for a line feed (A) -->: : Not LF, test for 'D' carriage ret -- : : Set next char to LP carriage ret -- : : Save LP carriage ret char <--:--: Test for second type of carriage ret -- : Jmp if 'A' or 'D' carriage ret -- : Get count of characters in current line -- : Bump count for next char going out -- : Move count to E-reg so we can <--: Use common code --- Save updated count of chars/this line --- Get char to be printed in A --- Call line printer driver

79

0358

* *************************************************************

0361

* *************************************************************

0380

: (Required for RST 16 routine)

0384

* *************************************************************

038B

* *************************************************************

039C

* : : :

Call print driver on entry. Char to be printed in ********** A-reg. If A = 'C', skip on line and reset count of characters in current line. If A = 'A' or 'D' print carriage return and reset character count for this line

80

03BE 03BF 03C0 03C1 03C2 03C3 03C5 03C6 03C8 03C9 03CC 03CD 03CE 03CF 03D0 03D1 03D4 03D6 03D9 03DC 03DD 03DE 03E0 03E1 03E2 03E3 03E6 03E9 03EB 03EC 03ED 03EE 03EF 03F0 03F2 03F3 03F4 03F6 03F9 03FA 03FB 03FC 03FD 03FE 03FF 0400 0402 0403 0404 0406 0407 0409 040B 040E 040F 0410 0412 0414 0416 0418

C1 D1 F1 C9 E5 DDE5 D5 DDE1 D5 21DD03 E5 4F 1A A0 B8 C23340 FE02 DD6E01 DD6602 E9 D1 DDE1 E1 C1 C9 213640 010138 1600 0A 5F AE 73 A3 2008 14 2C CB01 F2EB03 C9 5F 7A 07 07 07 57 0E01 79 A3 2005 14 CB01 18F7 3A8038 47 7A C640 FE60 3013 CB08 3031

POP POP POP RET PUSH PUSH PUSH POP PUSH LD PUSH LD LD AND CP JP CP LD LD JP POP POP POP POP RET LD LD LD LD LD XOR LD AND JR INC INC RLC JP RET LD LD RLCA RLCA RLCA LD LD LD AND JR INC RLC JR LD LD LD ADD CP JR RRC JR

BC DE AF HL IX DE IX DE HL,03DDH HL C,A A,(DE) B B NZ,4033H 02H L,(IX+01H) H,(IX+02H) (HL) DE IX HL BC HL,4036H BC,3801H D,00H A,(BC) E,A (HL) (HL),E E NZ,03FAH D L C P,03EBH E,A A,D

D,A C,01H A,C E NZ,040BH D C 0402H A,(3880H) B,A A,D A,40H 60H NC,0429H B NC,044BH

-------------------------------------------------------------------------------------------------------------------------

Restore caller's register, BC DE and AF Rtn to caller Driver entry routine *************** see note--> * Save registers B = entry code Load DCB addr DE = DCB addr into IX Save original contents of DE HL = return address Push return address onto stack Save char to be sent to device Fetch 1st word from DCB Isolate device code bits and compare w/entry code (B). If unequal goto driver via DOS Exit Clear status flags HL = driver address from DCB Load MSB of driver addr Go to driver routine Return from driver routine Restore registers, IX HL and BC Rtn to caller Keyboard driver routine ************ see note--> * BC = row A0 ptr D = column index Load row N 8 column bits XOR with previous Store column bits in buffer then test for active row Go if key active in row N Bump row index Seven byte buffer indexed by row Step address from 3801 - 3840 Try next row No key depression - return Save column bits ********************************* Row index 0 - 6 Row * 2 Row * 4 Row * 8 Save in D Start with bit 0 Mask Test for non-zero column Go if found Bump column number Align mask Try again Load shift bit Shift bit to B Row * 8 + column (0 - 7) Row * 8 + column (0 - 7) + 64 decimal Test for first 4 row (@,A-Z) Go if last 3 rows, numeric & special characters Shift to C Go if no shift

81

03C2

* Entered on RST 14,1C,24 *************************************

03E3

* HL = keyboard work area ptr *********************************

03FA

* *************************************************************

82

041A 041C 041D 0420 0422 0424 0425 0427 0429 042B 042D 042F 0431 0433 0435 0437 0439 043B 043D 043E 0440 0442 0443 0446 0447 0449 044A 044B 044C 044F 0452 0453 0455 0456 0457 0458 045B 045E 0460 0463 0464 0466 0467 0468 046A 046D 046F 0471 0473 0475 0477 0479 047B 047D 0480 0481 0483 0485 0486 0487

C620 57 3A4038 E610 2828 7A D660 1822 D670 3010 C640 FE3C 3802 EE10 CB08 3012 EE10 180E 07 CB08 3001 3C 215000 4F 0600 09 7E 57 01AC0D CD6000 7A FE01 C0 EF C9 DD6E03 DD6604 383A DD7E05 B7 2801 77 79 FE20 DA0605 FE80 3035 FE40 3808 D640 FE20 3802 D620 CD4105 7C E603 F63C 67 56 DD7E05

ADD LD LD AND JR LD SUB JR SUB JR ADD CP JR XOR RRC JR XOR JR RLCA RRC JR INC LD LD LD ADD LD LD LD CALL LD CP RET RST RET LD LD JR LD OR JR LD LD CP JP CP JR CP JR SUB CP JR SUB CALL LD AND OR LD LD LD

A,20H D,A A,(3840H) 10H Z,044CH A,D 60H 044BH 70H NC,043DH A,40H 3CH C,0435H 10H B NC,044BH 10H 044BH B NC,0443H A HL,0050H C,A B,00H HL,BC A,(HL) D,A BC,0DACH 0060H A,D 01H NZ 28H L,(IX+03H) H,(IX+04H) C,049AH A,(IX+05H) A Z,0467H (HL),A A,C 20H C,0506H 80H NC,04A6H 40H C,047DH 40H 20H C,047DH 20H 0541H A,H 03H 3CH H,A D,(HL) A,(IX+05H)

--- Set lower case --- Adjusted character --- Get row 6 column bits --- Test for down arrow or CR --- Go if no down arrow or CR --- Reload adjusted value for key struck --- Adjust to ASCII CR --- Go to return --- Test for last row (ENTER - SPACE) --- Go if last row --- Readjust for rows 4, 5 --- Convert rows 4, 5 --- Jmp if (0-1-2-3-4-5-6-7-8-9-:-;-,) key struck --- Invert row 5 bits --- Ret if shift key down --- Jmp if no --- then re-invert row 5 bits --- Go to output --- (Now (ROW * 8 + COLUMN - 48) * 2) --- Test for shift --- Go if no shift --- Now (ROW*8 + COLUMN-48) * 2 + 5 = COLUMN * 2 + 1 --- Table of codes for last row --- Ret C to value from 43D or 442 --- depending on shift. Set B = 0 --- Index into table --- Get ASCII - like code --- Save character --- Load delay count --- Delay 20 milliseconds --- A = ASCII - like character --- Is it BREAK? --- Go if not --- Yes, BREAK --- Return --- HL=cursor position ptr ************* see note--> * --- Load MSB of current video buffer addr --- Jmp if return last char request --- Get cursor on/off flag --- Set status flags for cursor on/off -->: Jmp if cursor off -- : Move char overlaid by cursor to character buffer <--: Get char to be displayed --- Compare with space --- Jump if control character --- Test for graphics word or compression code --- Jump if graphic or space compression character --- Compare w/letter A --- Jmp if not alphabetic @ - Z --- Subtract A to get 0 - 26 value for alpha --- Test for lower case -->: Jmp if not lower case -- : Convert lower case to upper case <--: Add new char to video display. Roll screen if --- Force addr of next char to :necessary --- be in the range 3C00 <= X <3FFF --- Force MSB of buffer addr to 3C - 3F --- Move updated MSB of buffer addr to HL --- Get value of char at cursor position --- Get cursor on/off flag

83

0458

* Display driver routine -

Load LSB if current video ********* buffer addr.

84

048A 048B 048D 0490 0492 0495 0498 0499 049A 049D 049E 049F 04A0 04A1 04A2 04A4 04A5 04A6 04A8 04AA 04AC 04AE 04AF 04B1 04B4 04B6 04B8 04B9 04BC 04BD 04BE 04C0 04C3 04C6 04C8 04CB 04CD 04CE 04CF 04D2 04D4 04D6 04D7 04D9 04DA 04DD 04DF 04E2 04E3 04E5 04E6 04E7 04EA 04EB 04EC 04ED 04EE 04F0 04F1 04F4

B7 2805 DD7205 365F DD7503 DD7404 79 C9 DD7E05 B7 C0 7E C9 7D E6C0 6F C9 FEC0 38D3 D6C0 28D2 47 3E20 CD4105 10F9 18C8 7E DD7705 C9 AF 18F9 21003C 3A3D40 E6F7 323D40 D3FF C9 2B 3A3D40 E608 2801 2B 3620 C9 3A3D40 E608 C4E204 7D E63F 2B C0 114000 19 C9 23 7D E63F C0 11C0FF 19

OR JR LD LD LD LD LD RET LD OR RET LD RET LD AND LD RET CP JR SUB JR LD LD CALL DJNZ JR LD LD RET XOR JR LD LD AND LD OUT RET DEC LD AND JR DEC LD RET LD AND CALL LD AND DEC RET LD ADD RET INC LD AND RET LD ADD

A Z,0492H (IX+05H),D (HL),5FH (IX+03H),L (IX+04H),H A,C A,(IX+05H) A NZ A,(HL) A,L 0C0H L,A 0C0H C,047DH 0C0H Z,0480H B,A A,20H 0541H 04AFH 0480H A,(HL) (IX+05H),A A 04B9H HL,3C00H A,(403DH) 0F7H (403DH),A (0FFH),A HL A,(403DH) 08H Z,04D7H HL (HL),20H A,(403DH) 08H NZ,04E2H A,L 3FH HL NZ DE,0040H HL,DE HL A,L 3FH NZ DE,0FFC0H HL,DE

--- Get status flags for cursor --->: Jmp if cursor off -- : Else save character to be replaced by cursor -- : Move ( ) cursor to addr of next char position <---: Save addr of next character --- Position on screen in DCB (3 ,4) --- Restore last character displayed --- Rtn to caller --- Get cursor on/off switch see note--> --- Set status flags for switch --- If cursor on, exit with character --- It overlaid in A-reg else --- Get last char displayed --- Get LSB of current video buffer addr. ** cont--> * --- Remove lower six bits giving value of XX00, --- XX40, XX80, or XXC0. 64 char/line assumed --- Rtn with new video buffer addr. in HL. --- Check for space compression code ***************** --- Graphic --- Subtract conversion bias --- Jmp if 0 blanks to be displayed --- B = count of blanks to be displayed --- A = blank --- Display a blank --- Loop till B blanks displayed --- Update pointer to video buffer and exit --- Load char of current position and ** see note--> * --- Save cursor on/off in DCB --- Rtn to caller --- Set cursor flag off --- Update video DCB and exit --- H1 = start of video area ******* Home cursor ***** --- Force 64 characters/line --- Clear 32 char/line bit in command word --- Save command word --- Send command word to video controller --- Rtn to caller --- Backspace one char in line ********* see note--> * --- Get status of video controller --- Test for 32/64 char per line --- Go if 64 characters/line --- Backspace one more word if 64 char/line --- Replace previous char with a blank --- Rtn to caller --- Get status of video controller ***** see note--> * --- Isolate number of chars/line --- Call backspace cursor twice if 32 char line --- Save LSB of current cursor position --- Backspace LSB of cursor to previous line --- Then backspace cursor 1 character --- Rtn if cursor on same line --- Else skip down one line --- by adding 64 to current cursor addr --- then rtn to caller --- Bump current cursor **************** see note--> * --- addr by 1, fetch LSB of addr --- and test for overflow into next line --- No overflow, rtn to caller --- Upward linefeed, add a --- minus 64 to current cursor addr

85

049A

: Return either current character or last character : replaced by cursor

04A1

* Backspace pointer in video buffer to start of *************** : current line. 64 char/line assumed

04A6

* *************************************************************

04B8

* cont--> use as cursor flag ********************************* : note--> Turn cursor on/off (control code processing)

04C0

* *************************************************************

04CE

* Backspace cursor on video (control char processing) *********

04DA

* Backspace cursor. Left arrow (control char processing) *****

04EC

* Advance cursor. Right arrow (control char processing) ******

86

04F5 04F6 04F9 04FB 04FE 0500 0501 0502 0504 0505 0506 0509 050A 050C 050E 0510 0511 0513 0515 0517 0519 051B 051D 051F 0521 0523 0525 0527 0529 052B 052D 052F 0531 0533 0535 0538 053A 053C 053E 0540 0541 0542 0543 0546 0548 054A 054B 054C 054E 054F 0552 0553 0554 0557 055A 055B 055E 0560 0561 0562

C9 3A3D40 F608 323D40 D3FF 23 7D E6FE 6F C9 118004 D5 FE08 28C0 FE0A D8 FE0E 384F 28A1 FE0F 28A2 FE17 28D7 FE18 28B7 FE19 28C5 FE1A 28BC FE1B 28C2 FE1C 288D FE1D CAA104 FE1E 2837 FE1F 283C C9 77 23 3A3D40 E608 2801 23 7C FE40 C0 11C0FF 19 E5 11003C 21403C C5 01C003 EDB0 C1 EB 1819

RET LD OR LD OUT INC LD AND LD RET LD PUSH CP JR CP RET CP JR JR CP JR CP JR CP JR CP JR CP JR CP JR CP JR CP JP CP JR CP JR RET LD INC LD AND JR INC LD CP RET LD ADD PUSH LD LD PUSH LD LDIR POP EX JR

A,(403DH) 08H (403DH),A (0FFH),A HL A,L 0FEH L,A DE,0480H DE 08H Z,04CEH 0AH C 0EH C,0564H Z,04B8H 0FH Z,04BDH 17H Z,04F6H 18H Z,04DAH 19H Z,04ECH 1AH Z,04E7H 1BH Z,04F1H 1CH Z,04C0H 1DH Z,04A1H 1EH Z,0573H 1FH Z,057CH (HL),A HL A,(403DH) 08H Z,054BH HL A,H 40H NZ DE,0FFC0H HL,DE HL DE,3C00H HL,3C40H BC BC,03C0H BC DE,HL 057DH

--- Rtn to caller --- Get video control word *************************** --- Turn on 32 char/line mode --- Restore video control word --- Select 32 char/line --- Increment current position in video buffer --- Force LSB to --- an even value when in 32 char/line mode --- Restore updated line addr to HL --- Rtn to caller --- Return addr after processing ******* see note--> * --- To stack :control character --- Backspace and erase character --- Jmp if backspace --- Not backspace, test for A --- Ignore if control code < A (hex) except for 08 --- Test for turn on cursor --- Jmp if A-D (carriage return) --- Jmp if turn on cursor --- Test for turn off cursor --- Jmp if turn off cursor --- Test for select 32 char/line --- Jmp if 32 select 32 char/line --- Left arrow --- Jmp if left arrow --- Right arrow --- Jmp if right arrow --- Down arrow --- Jmp if down arrow --- Up arrow --- Jmp if up arrow --- Home cursor --- Jmp if home cursor --- Beginning of line --- Jmp if backspace to start of current line --- Erase to end of line --- Jmp if delete rest of line --- Clear to end of frame --- Jmp if CLEAR rest of screen --- Ignore all others --- Send character to display memory *** see note--> * --- Bump to next addr in display memory --- Get status word for video --- Isolate characters/line flag --->: Jmp if 32 char/line -- : 64 char/line. Bump one more word to cont--> <---: Now, test if end of display mem reached --- If MSB of next avail word = 40, then end of meet --- Rtn if not out of memory :reached --- DE = -64 --- Backspace mem ptr 1 line. Prepare to roll screen --- Save starting mem addr of bottom line up one line --- DE = addr 1st line --- HL = addr of 2nd line --- Save BC --- BC = count of chars to move (15 lines) --- Move screen up one line --- Restore BC --- HL = addr of 16th (last) line --- Go blank out 16th line

87

04F6

* *************************************************************

0506

* Process control characters for video All characters < 20H **

0541

* Moves new char to display buffer ****************************

054A

: next addr in display mem

88

0564 0565 0567 0568 0569 056C 056D 056E 0570 0572 0573 0574 0575 0576 0578 0579 057A 057C 057D 0580 0582 0583 0584 0585 0587 0588 0589 058B 058C 058D 058E 058F 0591 0593 0595 0597 0599 059A 059D 059F 05A2 05A5 05A6 05A9 05AB 05AD 05B0 05B2 05B4 05B5 05B8 05BA 05BB 05BE 05C0 05C1 05C4 05C7 05CA 05CB

7D E6C0 6F E5 114000 19 7C FE40 28E2 D1 E5 54 7D F63F 5F 13 1804 E5 110040 3620 23 7C BA 20F9 7D BB 20F5 E1 C9 79 B7 2840 FE0B 280A FE0C 201B AF DDB603 2815 DD7E03 DD9604 47 CDD105 20FB 3E0A 32E837 10F4 1818 F5 CDD105 20FB F1 32E837 FE0D C0 DD3404 DD7E04 DDBE03 79 C0

LD AND LD PUSH LD ADD LD CP JR POP PUSH LD LD OR LD INC JR PUSH LD LD INC LD CP JR LD CP JR POP RET LD OR JR CP JR CP JR XOR OR JR LD SUB LD CALL JR LD LD DJNZ JR PUSH CALL JR POP LD CP RET INC LD CP LD RET

A,L 0C0H L,A HL DE,0040H HL,DE A,H 40H Z,0554H DE HL D,H A,L 3FH E,A DE 0580H HL DE,4000H (HL),20H HL A,H D NZ,0580H A,L E NZ,0580H HL A,C A Z,05D1H 0BH Z,059FH 0CH NZ,05B4H A (IX+03H) Z,05B4H A,(IX+03H) (IX+04H) B,A 05D1H NZ,05A6H A,0AH (37E8H),A 05A6H 05CCH AF 05D1H NZ,05B5H AF (37E8H),A 0DH NZ (IX+04H) A,(IX+04H) (IX+03H) A,C NZ

--- Get LSB of current char position --- And force its address to the start --- Of the current line see note --> --- Save starting line addr for current character --- DE = number of characters (words) in a line --- Gives starting addr for next line --- Now test EBB of next line addr --- Test for end of screen --- Jmp if end of screen (scroll up one line) --- DE = starting addr for current line --- Erase to end of line. HL = starting addr for next --- Compute ending addr :line --- For line blanking code below --- Take addr in HL, --- round it up to the next line --- number then --- Jmp to the line blanking code --- Erase to end of frame --- Test addr for end of loop check <---: Move a blank to current char pos in line : Bump to next char DOS : Test if end of line. Compare : MSB of current addr to 40 base 16 --->: Loop if not end of line --- Then compare LSB of --- addresses --- Loop if not end of line --- Restore HL - (current char position addr) --- Rtn to caller --- Print driver routine ** Get char to be printed *** --- Set status flags --- If zero, then get printer status and return --- Skip to top of form code see note--> --- Yes go issue line feeds till next page reached --- Test for conditional skip to top of form ----->: Jmp if data char --: Then clear A (gives null char to be printed) --: Get number of lines/page --: If zero don't skip any lines --: Get count of lines per page and --: subtract lines printed this page so far, gives --: B = no. of lines to skip to top of next page <---: : Get printer status --->: : Loop till not busy : : Get a line feed character : : Send it to the printer --->: : Loop till we're at top of next page --: Reset line count for new page & rtn to caller <-----: Save print status <---: Get print status --->: Loop till not busy --- Get character to print --- Send it to printer --- Carriage return? --- Rtn to caller if data char --- Bump count of lines printed this page --- Fetch line count for this page --- And compare to no of lines per page --- Restore print char to A (carriage ret) --- Exit if Daze not full

89

0567

: (Control code processing)

058D

* ************************************************************* : Carriage control codes : A = line feed + CR : B = skip to top of form : C = conditional skip to top of form : D = CR

90

05CC 05D0 05D1 05D4 05D6 05D8 05D9 05DA 05DC 05DF 05E0 05E3 05E5 05E7 05E9 05EC 05EE 05F0 05F2 05F4 05F7 05F8 05FA 05FC 05FE 0600 0602 0604 0606 0608 060A 060B 060C 060D 060E 060F 0611 0612 0613 0616 0617 0619 061C 061D 061E 061F 0622 0625 0626 0627 0628 062A 062B 062C 062D 062F 0630 0631 0632 0633

DD360400 C9 3AE837 E6F0 FE30 C9 E5 3E0E CD3300 48 CD4900 FE20 3025 FE0D CA6206 FE1F 2829 FE01 286D 11E005 D5 FE08 2834 FE18 282B FE09 2842 FE19 2839 FE0A C0 D1 77 78 B7 28CF 7E 23 CD3300 05 18C7 CDC901 41 E1 E5 C3E005 CD3006 2B 7E 23 FE0A C8 78 B9 20F3 C9 78 B9 C8 2B

LD RET LD AND CP RET PUSH LD CALL LD CALL CP JR CP JP CP JR CP JR LD PUSH CP JR CP JR CP JR CP JR CP RET POP LD LD OR JR LD INC CALL DEC JR CALL LD POP PUSH JP CALL DEC LD INC CP RET LD CP JR RET LD CP RET DEC

(IX+04H),00H --- Page full, reset line count for next page to zero --- Rtn to caller A,(37E8H) --- Get printer status word ************************** 0F0H --- Isolate status 30H --- Test for printer selected and ready --- Rtn with status zero if selected & ready HL --- Input routine HL points to input area ** cont--> * A,0EH --- Code to turn on cursor HL = Start of buffer 0033H --- Turn on cursor B = Buffer size C,B --- C = buffer size Exit with carry if 0049H <---: Return when key is pressed BREAK hit 20H : Test for SPACE NC,060CH : Not a space but displayable if NC 0DH : Test for carriage ret. Z,0662H : Jmp if CR 1FH : Test for CLEAR Z,0619H : Jmp if CLEAR 01H : Test for BREAK Z,0661H : Jmp if BREAK DE,05E0H : Push rtn addr of 05 E0 onto stack in case DE : character is none of the following 08H : Test for backspace and erase char. Z,0630H : Jmp if backspace / erase 18H : Backspace cursor Z,062BH : Jmp if backspace 09H : Horizontal tab Z,0646H : Jmp if horizontal tab 19H : Select 32 char/line Z,0641H : Jmp if line size selection 0AH : Test for line feed NZ : Return to 5E0 if not a line feed DE : Remove 5E0 as a rtn addr (HL),A : He hit a printable character (save it) A,B : 240 - count of characters fetched A : Set status Z,05E0H : If end of buffer ignore unless BRK or CR A,(HL) : Reload char just entered HL : Bump buffer address 0033H : Print the character just received B : Count 1 char received 05E0H --->: Get next character 01C9H --- He hit CLEAR : CLS Clear screen B,C --- Reset count of characters transmitted HL --- Reset buffer address HL --- Save buffer origin on stack 05E0H --- Go get next character (first char of buffer) 0630H --- Go wait for next key HL --- Backup to previous character (one before CR) A,(HL) --- Fetch it and test for a LF HL --- Restore buffer addr to next avail position 0AH --- Was previous char a -line feed Z --- yes, rtn A,B --- No, test for buffer full. A = count of chars C --- Received minus size of buffer NZ,0622H --- Loop if room for more data --- Rtn (buffer full) A,B --- B = characters received C = size of buffer ****** C --- Test if buffer full Z --- Exit if buffer full HL --- Backspace to previous character

91

05D1

* *************************************************************

05D9

* Accept keyboard input ***************************************

0630

* *************************************************************

92

0634 0635 0637 0638 0639 063A 063C 063F 0640 0641 0643 0646 0649 064B 064C 064D 064F 0650 0651 0652 0653 0655 0656 0657 0658 065B 065C 065D 065E 065F 0661 0662 0663 0665 0666 0669 066B 066E 066F 0670 0671 0672 0673 0674 0676 0679 067C 067F 0681 0682 0683 0685 0687 0688 0689 068B 068E 0690 0693 0696

7E FE0A 23 C8 2B 3E08 CD3300 04 C9 3E17 C33300 CD4803 E607 2F 3C C608 5F 78 B7 C8 3E20 77 23 D5 CD3300 D1 05 1D C8 18EF 37 F5 3E0D 77 CD3300 3E0F CD3300 79 90 47 F1 E1 C9 D3FF 21D206 110040 013600 EDB0 3D 3D 20F1 0627 12 13 10FC 3A4038 E604 C27500 317D40 3AEC37

LD CP INC RET DEC LD CALL INC RET LD JP CALL AND CPL INC ADD LD LD OR RET LD LD INC PUSH CALL POP DEC DEC RET JR SCF PUSH LD LD CALL LD CALL LD SUB LD POP POP RET OUT LD LD LD LDIR DEC DEC JR LD LD INC DJNZ LD AND JP LD LD

A,(HL) 0AH HL Z HL A,08H 0033H B A,17H 0033H 0348H 07H A A,08H E,A A,B A Z A,20H (HL),A HL DE 0033H DE B E Z 0650H AF A,0DH (HL),A 0033H A,0FH 0033H A,C B B,A AF HL (0FFH),A HL,06D2H DE,4000H BC,0036H A A NZ,0676H B,27H (DE),A DE 0687H A,(3840H) 04H NZ,0075H SP,407DH A,(37ECH)

--- And fetch it --- Test for a line feed --- Bump to last character received --- Exit if previous char was a line feed --- Backspace over last char in buffer --- Backspace screen command --- Print backspace --- Adjust char received count --- Exit --- Send position command **************************** --- To video control unit and exit --- Go wait for next key ******************* cont--> * --- Isolate lower 3 bits of ASCII value --- Gives inverse of value --- Gives value 1 <= X <= 8 --- Clears upper bits of counter --- Save count of blanks to add <---: Get amt of space left in buffer : Test for full buffer : Exit if buffer full : Load an ASCII space into A-reg : Store space in buffer : Bump to next location in buffer : Save callers DE : Display blank : Restore DE : Decrement count of bytes left in buffer : Count one spaced added to buffer : Exit if specified number of blanks added --->: Else loop till buffer full or count zero --- CARRY flag set if BREAK hit. *********** cont--> * --- He hit a CR see note--> --- A = CR terminates buffer --- Save terminator in buffer --- Print it (CR) --- Cursor off code --- Turn cursor off via driver call --- C = buffer size --- Minus (buffer size - chars processed) --- Gives chars in buffer --- Restore status flag carry cont--> --- HL = start of buffer address --- Return to original caller --- 0 to cassette ************** Video controller **** --- Addr. of video/keyboard/printer DCB's --- Start of communications region --- Setup for block move --- Move 6D2-707 to 4000-4035 --- Change value being sent to port FF to FFFD, . . . --- FFFB, . . . . --- Go thru this 128 times --- 0 to A --- 0 to 4036-4062 --- Bump destination pntr --- Go if not done --- Test keyboard for BREAK --- BREAK key hit --- Go if BREAK --- New stack area --- Load disk status

93

0641 0646

* ************************************************************* * No. of blanks to produce ******** HT key during input ******* : Pad buffer with specified : number of blanks or until : buffer is full. : Number of blanks added is: : HT 0 - 8 : HT 5 - 3 : 1 - 7 : 6 - 2 : 2 - 6 : 7 - 1 : 3 - 5 : 8 - 0 : 4 - 4 :

0661 0662

* Else reset *** BREAK key during input *********************** : CR during input

0671

: Set if BREAK -Not set if CR

0674

* *************************************************************

94

0699 069A 069C 069F 06A1 06A4 06A7 06AA 06AC 06AF 06B2 06B4 06B6 06B7 06BA 06BD 06BF 06C0 06C2 06C4 06C5 06C6 06C7 06C9 06CC 06CF 06D2 06D5 06D8 06DB 06DE 06DF 06E0 06E1 06E2 06E3 06E4 06E5 06E6 06E7 06EA 06EB 06EC 06ED 06EE 06EF 06F0 06F1 06F2 06F3 06F4 06F5 06F6 06F7 06F9 06FA 06FB 06FC 06FD 06FE

3C FE02 DA7500 3E01 32E137 21EC37 11EF37 3603 010000 CD6000 CB46 20FC AF 32EE37 010042 3E8C 77 CB4E 28FC 1A 02 0C 20F7 C30042 01181A C3AE19 C3961C C3781D C3901C C3D925 C9 00 00 C9 00 00 FB C9 00 01E303 00 00 00 4B 49 07 58 04 00 3C 00 44 4F 068D 05 43 00 00 50 52

INC CP JP LD LD LD LD LD LD CALL BIT JR XOR LD LD LD LD BIT JR LD LD INC JR JP LD JP JP JP JP JP RET NOP NOP RET NOP NOP EI RET NOP LD NOP NOP NOP LD LD RLCA LD INC NOP INC NOP LD LD LD DEC LD NOP NOP LD LD

A 02H C,0075H A,01H (37E1H),A HL,37ECH DE,37EFH (HL),03H BC,0000H 0060H 00H,(HL) NZ,06B2H A (37EEH),A BC,4200H A,8CH (HL),A 01H,(HL) Z,06C0H A,(DE) (BC),A C NZ,06C0H 4200H BC,1A18H 19AEH 1C96H 1D78H 1C90H 25D9H

BC,03E3H

C,E C,C E,B B A B,H C,A B,8DH B B,E

D,B D,D

--- Test for Expansion Interface --- and disk drive --- Go if no disk --- Unit select mask for drive 0 --- Select drive 0 --- Addr of disk command / status register --- Addr of disk data register --- 3 to disk command register = restore, position --- Delay count :to track 0 --- Delay for approx 3 seconds --- Test if controller busy, --- Loop till not busy --- 0 to A --- 0 to sector register --- BC = addr of buffer area --- A = read command --- Read sector 0, track 0 into 4200 - 4455 --- Test if data ready --- Go if no data avail --- Get next byte from disk --- Transfer data to 4200+ --- Bump buffer pntr --- Go if not 256 bytes --- Done, transfer to TRSDOS loader --- Addr of BASIC READY routine (rtn addr) *********** --- Initialize BASIC's variables & pntrs ** cont--> * * 4000 *--- RST 08 vector JP 1C96 (compare) ********** * 4003 *--- RST 10 vector JP 1D78 (get next char) * 4006 *--- RST 18 vector JP 1C90 (compare DE:HL) * 4009 *--- RST 20 vector JP 25D9 (test data type) * 400C *--- RST 28 vector RET (JP 4BA2 for DOS) * * * 400E *--- RST 30 vector RET (JP 44B4 for DOS) * * 4012 *--- RST 38 vector DI/RET (JP 4518 for DOS) * :Interrupt entry point vector * * * 4015 *--- Keyboard DCB ***************************** * * Driver addr = 3E3 * * * 401D *--- Video DCB ******************************** * * * * Driver addr = 458 * * * * 4025 *--- Line printer DCB ************************* * * * Driver addr = 58D * * * ******************************************************

95

06CC 06CF 06D2

* * * * *

************************************************************* then goto 1A18 (BASIC READY routine) The contents of 6D2 - 707 are moved to location 4000 - 4035 in the Communications Region during the first stage of the IPL sequence

06E7

* *************************************************************

06EE

* *************************************************************

06F6

* *************************************************************

06FE

* *************************************************************

96

06FF 0702 0703 0704 0705 0707 0708 070B 070E 0710 0713 0716 0717 0718 0719 071C 071D 0720 0721 0723 0724 0725 0726 0729 072A 072D 072E 072F 0731 0732 0733 0736 0737 0738 073B 073C 073F 0742 0745 0748 0749 074A 074D 074F 0752 0754 0755 0756 0757 0758 0759 075A 075B 075C 075D 075E 075F 0760 0761 0762

C30050 C7 00 00 3E00 C9 218013 CDC209 1806 CDC209 CD8209 78 B7 C8 3A2441 B7 CAB409 90 300C 2F 3C EB CDA409 EB CDB409 C1 D1 FE19 D0 F5 CDDF09 67 F1 CDD707 B4 212141 F25407 CDB707 D29607 23 34 CAB207 2E01 CDEB07 1842 AF 90 47 7E 9B 5F 23 7E 9A 57 23 7E 99 4F DCC307

JP RST NOP NOP LD RET LD CALL JR CALL CALL LD OR RET LD OR JP SUB JR CPL INC EX CALL EX CALL POP POP CP RET PUSH CALL LD POP CALL OR LD JP CALL JP INC INC JP LD CALL JR XOR SUB LD LD SBC LD INC LD SBC LD INC LD SBC LD CALL

5000H 00H

A,00H HL,1380H 09C2H 0716H 09C2H 0982H A,B A Z A,(4124H) A Z,09B4H B NC,072FH A DE,HL 09A4H DE,HL 09B4H BC DE 19H NC AF 09DFH H,A AF 07D7H H HL,4121H P,0754H 07B7H NC,0796H HL (HL) Z,07B2H L,01H 07EBH 0796H A B B,A A,(HL) A,E E,A HL A,(HL) A,D D,A HL A,(HL) A,C C,A C,07C3H

* 402D *--- Changed by SYS 0 to JP 4400 * 4030 *--- Changed by SYS 0 to LD A,A3 * * 4043 *--- Changed by SYS 0 to RST 28 * 4033 *--- Changed by SYS 0 to 44BB * --- Address of the single precision routines ********* --- Load a SP number pointed to by HL into BC/DE --- Go add SP no. in registers to 4121 - 4124 --- Load current value into BC/DE --- Invert sign of value in WRA1 : see notes --> --- Get exponent for register value --- Set status flags for exponent --- If exponent = 0, then no. in registers is zero --- Now, get exponent of the other number --- and test its exponent --- Exit if it is zero. --- A = current exp - Reg. exp = bits to scale --- Register value has smallest exp. & therefore is --- smaller. Make diff in exponents positive. Also --- reverse registers and current values so that --- smallest one is in registers. --- Put SP no. in '4121-4124' onto stack --- Restore HL to addr of second value --- Put SP no. in registers into '4121 - 4124' --- Load SP no. saved on stack at 0726 above. --- If difference in exponent > 24, then no. cannot be --- added because of difference in magnitude. --- Save number of places to right shift register --- value so its exponent = exponent of current value --- Turn on MS bit of both values to be added. Save --- sign determination in H. A = no. of bit position --- to right shift BC/CE scale value in registers so --- it is equivalent to current value. Go unpack --- value in BC/DE. Set status flags for sign of --- Load addr of WRA1 :register value --- Jump if value in registers is negative. --- Add a SP no in CDE to SP no. pointed to by --- HL. Sum in CDE. Jump if coefficient --- same size else --- increase exponent by 1 --- error if exponent overflows to zero. --- L = number of bits to shift --- Right shift coefficient 1 place. --- Go normalize value & rtn to caller --- Clear A, status flags *************** see note--> * --- 0-exponent = -exponent --- Save negative of exponent --- Load LSB of mem. value --- Minus LSB of reg. value --- E = new LSB reg. value --- Bump to middle byte of mem. value --- Load middle byte of mem. value --- Subtract middle byte of reg. value --- D = new MSB of reg. value --- Bump to MSB of mem. value --- Load MSB of mem. value --- Minus MSB of reg. value --- C = new MSB of reg. value --- If carry go convert reg. value to cont-->

97

0708 0708 070B 0710

* Single precision addition routines ( 5 entry points) ******** : : : : : : : : : : This entry point loads a .5 into BC/DE then adds it to the value in WRA1 This entry point loads a SP value, pointed to by HL into and then adds it to WRA1 Loads SP value pointed to by HL into BC/DE. Then inverts the sign of WRA1 value, before adding BC/DE and WRA1 This entry point inverts the sign of the value in WRA1 before adding it to BC/DE Adds WRA1 to BC/DE, leaves sum in WRA1

0713 0716

0754

* Adds a negative SP value in BC/DE to a positive ************* : SP value pointed to by HL. Result left in BC/DE

: its positive equivalent

98

0765 0766 0767 0768 0769 076A 076B 076D 076E 076F 0770 0771 0772 0774 0776 0778 0779 077C 077D 077E 077F 0780 0781 0782 0783 0784 0785 0788 0789 078A 078B 078C 078E 0791 0792 0793 0795 0796 0797 079A 079B 079E 079F 07A0 07A1 07A3 07A4 07A5 07A8 07A9 07AA 07AB 07AC 07AD 07AE 07B0 07B1 07B2 07B4 07B7

68 63 AF 47 79 B7 2018 4A 54 65 6F 78 D608 FEE0 20F0 AF 322441 C9 05 29 7A 17 57 79 8F 4F F27D07 78 5C 45 B7 2808 212441 86 77 30E3 C8 78 212441 B7 FCA807 46 23 7E E680 A9 4F C3B409 1C C0 14 C0 0C C0 0E80 34 C0 1E0A C3A219 7E

LD LD XOR LD LD OR JR LD LD LD LD LD SUB CP JR XOR LD RET DEC ADD LD RLA LD LD ADC LD JP LD LD LD OR JR LD ADD LD JR RET LD LD OR CALL LD INC LD AND XOR LD JP INC RET INC RET INC RET LD INC RET LD JP LD

L,B H,E A B,A A,C A NZ,0785H C,D D,H H,L L,A A,B 08H 0E0H NZ,0768H A (4124H),A B HL,HL A,D D,A A,C A,A C,A P,077DH A,B E,H B,L A Z,0796H HL,4124H A,(HL) (HL),A NC,0778H Z A,B HL,4124H A M,07A8H B,(HL) HL A,(HL) 80H C C,A 09B4H E NZ D NZ C NZ C,80H (HL) NZ E,0AH 19A2H A,(HL)

--- L = exponent of original reg. value see note--> --- H = least sig. byte --- Clear A, status. <---: B = count of bytes tested : Load next byte of new reg. value(MSB/middle/LSB) : Test if EBB is zero : Jmp if MSB non-zero (go normalize reg. value) : This is a circular see note--> : Left shift of 8 bits : C <-- D <-- H : H <-- L <-- A : Zero in B gets propagated until a non-zero byte : or all 3 bytes of reg. value have tested : Test if all 3 bytes of value tested --->: Jmp if no --- Yes, value is zero --- Zero exponent --- Rtn to caller <---: Count 1 left shift *************** see note--> * : Shift HL left 1 bit : Then shift D left 1 bit : Picking up any carry from HL : Restore shifted D : Then shift C left 1 bit : Picking up any carry from D : Restore shifted C --->: Loop till CDHL is normalized --- A = count of bits shifted left --- Save HL so we can --- use it for addr of exponent --- Test count of bits shifted --->: Jump if reg value already normalized or negative : HL = addr. of original exponent of reg. value : Add shifted count to bias : Store result as exponent : Set exponent to zero if value < 2**24 : Rtn with WRA1 = zero if exponent is zero <---: Load least sig. byte of value --- Addr. of exponent to HL see note--> --- Test if any bits in LSB --->: if so go test for overflow : otherwise load the exponent into B : Bump to 4025 (contains sign of result) : then load the sign. Isolate it so : that it can be combined with new exponent : Clear sign bit of MSB : B=exponent, C=MSB, D=next MSB, E=LSB : Store SP number in BC, DE into 4121-4124. <---: Bump least sig. byte ************* see note--> * --- Exit if no overflow --- Go on to next byte. Bump it --- Exit if no overflow --- Go on to next byte. Bump it --- Exit if no overflow --- Set value to -0 --- Bump exponent --- Exit if we have not overflowed --- OV error code --- Output OV error message --- Load LSB of memory value

99

076D

: : : : : : : : : :

Part I of integer to SP conversion On entry C=MSB, D=middle byte, E=MSB of integer to be converted If both bytes are zero, set the exponent to zero (4124), the other three bytes are already zero. If the integer is not zero, locate the first non-zero byte and go to 785-77D to normalize (shift it left until the most significant bit is 1) it. ------- Rotate reg. value left 8 bits. : If entire value is zero set exponent to zero & exit : C <-- D <-- H <-- L <-- A

077D

* : : : : :

Part II of integer to SP conversion Shift CDHL left as a single unit the MS bit of L->H, MS bit of H->D, MS bit of D->C. Shifting stops when the MS bit of C is shifted into bit 15. A count of the number of shifts necessary is kept in B as a negative number.

: : : :

Part III of integer to SP conversion. Clear sign of mantissa (it was set neg during the normalization process above). Setup registers for storing result.

07A8 * : : : : : : :

Return to caller for negative numbers, zeros have been converted to all ones. Now, convert all the trailing zeros (which are now ones) back to zeros. Also used to test for overflow when creating a SP number.

: Add 3 bytes of a SP number in C D/E

100

07B8 07B9 07BA 07BB 07BC 07BD 07BE 07BF 07C0 07C1 07C2 07C3 07C6 07C7 07C8 07C9 07CA 07CB 07CC 07CD 07CE 07CF 07D0 07D1 07D2 07D3 07D4 07D5 07D6 07D7 07D9 07DB 07DD 07DE 07DF 07E0 07E2 07E4 07E6 07E7 07E8 07E9 07EA 07EB 07EC 07ED 07EE 07EF 07F0 07F1 07F2 07F3 07F4 07F5 07F6 07F8 07F9 07FA 07FB 07FC

83 5F 23 7E 8A 57 23 7E 89 4F C9 212541 7E 2F 77 AF 6F 90 47 7D 9B 5F 7D 9A 57 7D 99 4F C9 0600 D608 3807 43 5A 51 0E00 18F5 C609 6F AF 2D C8 79 1F 4F 7A 1F 57 7B 1F 5F 78 1F 47 18EF 00 00 00 81 03

ADD LD INC LD ADC LD INC LD ADC LD RET LD LD CPL LD XOR LD SUB LD LD SBC LD LD SBC LD LD SBC LD RET LD SUB JR LD LD LD LD JR ADD LD XOR DEC RET LD RRA LD LD RRA LD LD RRA LD LD RRA LD JR NOP NOP NOP ADD INC

A,E E,A HL A,(HL) A,D D,A HL A,(HL) A,C C,A HL,4125H A,(HL) (HL),A A L,A B B,A A,L A,E E,A A,L A,D D,A A,L A,C C,A B,00H 08H C,07E4H B,E E,D D,C C,00H 07D9H A,09H L,A A L Z A,C C,A A,D D,A A,E E,A A,B B,A 07E7H

A,C BC

--- Add to LSB of register value --- Save new LSB --- Bump to middle byte of memory value --- Load middle byte of memory value : see note--> --- Add middle byte of register value --- Save new middle byte --- Bump to MSB of memory value --- Load MSB of memory value --- Add MSB of register value --- Save new MSB --- Rtn to caller --- Reset sign flag so that ************ see note--> * --- mantissa will have a negative sign --- Invert the sign flag --- Store sign flag --- Zero A --- then save it --- Complement B (0 - B) --- Save new value of B --- Reload zero into A --- Complement E (0 - E) --- Save new value for E --- Reload A with zero --- Complement D (0 - D) --- Save new D value --- Reload A with zero --- Complement C (0 - C) --- Save new C value ---Rtn to caller *********** Unpack a SP number ****** <--: On entry, A = no bits to right shift ---:>: If carry, then shift right (A) bits, : : else shift number right one byte : : This code thru 07 E2 : : shifts 00CDE such : : that afterwards we have E00CD -->: : Loop to see if must right shift another byte <----: Make shift count positive --- And move it to L --- Clear status flags --- Decrement shift count --- Exit if done --- Now, right shift BCDE one bit at a time as a unit --- Right shift C one position, put bit 0 of C into --- Restore C :carry --- Now, right shift D one place. Bit 0 of C becomes --- Bit 0 of D to carry : bit 8 of D --- Restore D --- Right shift E one bit. Bit 0 of D becomes bit 8 --- Bit 0 of E to carry : of E --- Restore E --- Finally right shift B one bit. --- Bit 0 of E becomes --- bit 7 of B. Bit 0 of B is lost. --- Loop till (L) bits shifted. cont--> --- ************************************************** --- 07F8 - 07FB = SP 1.0 ------- Count of following SP values (03) --- Coefficients for power series used in LN comp

101

: : : : : : : : :

To 3 bytes of a SP number pointed to by HL - One of the numbers must have been scaled so its exponent is the same as the other. A carry from a LSB is added to the MSB, etc. On exit A=MSB, carry flag set if coefficient has increased and therefore the exponent must be adjusted. Zero otherwise. Sum left in C D/E

07C3

* : : : :

This routine converts a 4 byte negative integer into its **** twos complement positive equivalent so it can be converted to SP state, the SP sign flag (4125) is also complemented. This will insure a negative coefficient after normalization.

07D7

* *************************************************************

07F6 07F8

: Integer portion left in C/D/E. Fractional part left in B. * *************************************************************

102

07FD 07FE 07FF 0800 0801 0802 0805 0806 0807 0809 080C 080D 0810 0813 0814 0817 081A 081B 081C 081D 081E 081F 0822 0823 0824 0825 0828 082B 082E 0831 0834 0837 083A 083D 083E 0841 0844 0847 084A 084B 084D 0850 0851 0854 0855 0858 085B 085C 085D 0860 0861 0864 0865 0866 0869 086A 086B 086C 086E 086F

AA 56 19 80 F1 227680 45 AA 3882 CD5509 B7 EA4A1E 212441 7E 013580 11F304 90 F5 70 D5 C5 CD1607 C1 D1 04 CDA208 21F807 CD1007 21FC07 CD9A14 018080 110000 CD1607 F1 CD890F 013180 111872 CD5509 C8 2E00 CD1409 79 324F41 EB 225041 010000 50 58 216507 E5 216908 E5 E5 212141 7E 23 B7 2824 E5 2E08

XOR LD ADD ADD POP LD LD XOR JR CALL OR JP LD LD LD LD SUB PUSH LD PUSH PUSH CALL POP POP INC CALL LD CALL LD CALL LD LD CALL POP CALL LD LD CALL RET LD CALL LD LD EX LD LD LD LD LD PUSH LD PUSH PUSH LD LD INC OR JR PUSH LD

D D,(HL) HL,DE A,B AF (8076H),HL B,L D C,078BH 0955H A PE,1E4AH HL,4124H A,(HL) BC,8035H DE,04F3H B AF (HL),B DE BC 0716H BC DE B 08A2H HL,07F8H 0710H HL,07FCH 149AH BC,8080H DE,0000H 0716H AF 0F89H BC,8031H DE,7218H 0955H Z L,00H 0914H A,C (414FH),A DE,HL (4150H),HL BC,0000H D,B E,B HL,0765H HL HL,0869H HL HL HL,4121H A,(HL) HL A Z,0892H HL L,08H

-------------------------------------------------------------------------------------------------------------------------

07FD - 0800 = .5988

0801 - 0804 = .96145 0805 - 0808 = 2.88539

Test sign of current SP number **** LOG routine ** Set status flags according to sign : see note--> Error if value is negative HL = addr of exponent of current value A = exponent of current value BC/DE = .707092 (approx in 2) Scale value so it's <1 Save scale factor Force exponent of current value to be same as constant in BC/DE Save constant in BC/DE on stack Add constant in BC/DE to current value Restore constant into BC/DE Bump exponent. Multiply constant by 2**1 or Divide 1.4141 (approx in 4) by scaled value + HL = add of SP 1.0 : 1n 2 Load BC/DE with 1.0 and subtract from current Addr of table of 3 S.P. values :value Call series routine to evaluate sum cont--> BC = -.5 Add (-.5) to current value Restore scale factor from 81A above Scale current value to original magnitude Load BC/DE with .693115 then multiply sum from series by .693115 Test sign & exponent ******************* cont--> * Exit if exponent is zero L = 00 means add exponents Add exponents together. Set most sig bit of MSB for each value. 414F = MSB of register value 4150 - 4151 = next MSB of register value BC = 00 DE = 00 Integer to SP conversion called after multiplication to convert result to SP. We will go there after unpacking the SP numbers. Now, put 869 on stack twice so we'll unpack each SP number. HL = address of current value Test LSB for zero HL = addr. of next MSB A = LSB of current SP value Jmp if LSB is zero (do a circular Save addr of next MSB L = count of bits to right shift

cont--> cont-->

103

0809

* * * * * * * * * * * *

************************************************************* Method used: 1. Test sign of value. If negative exit with FC error. 2. Scale the value so it is between 0.5 and 1. Save the count of bits used for scaling 3. Recompute scaled value as x = 1 - (2 In 2 / ( x + In 2)) 4. Evaluate ((x**2 * c0 + cl) x**2 + c2)x 5. Subtract 0.5 from final term of series 6. Add the shift count to the result of step 5 7. Multiply result of step 6 by In 2

: of coeff. (I)*value(I)**2I+2 for I=-2

0847

* : : :

of current SP number **************************************** Single precision multiplication ------Multiply BC/DE by current value. Use shift and add method. Unpack each number first then we shift and add.

086C 086E

: right shift of one byte) then go get next byte. : SP number ( or until it's right justified

104

0871 0872 0873 0874 0876 0877 087A 087B 087C 087D 0880 0881 0882 0883 0884 0885 0886 0887 0888 0889 088A 088B 088C 088D 088E 0890 0891 0892 0893 0894 0895 0896 0897 089A 089D 08A0 08A1 08A2 08A5 08A8 08AA 08AD 08AE 08AF 08B0 08B1 08B4 08B5 08B6 08B9 08BA 08BB 08BE 08BF 08C0 08C1 08C2 08C3 08C4 08C7

1F 67 79 300B E5 2A5041 19 EB E1 3A4F41 89 1F 4F 7A 1F 57 7B 1F 5F 78 1F 47 2D 7C 20E1 E1 C9 43 5A 51 4F C9 CDA409 21D80D CDB109 C1 D1 CD5509 CA9A19 2EFF CD1409 34 34 2B 7E 328940 2B 7E 328540 2B 7E 328140 41 EB AF 4F 57 5F 328C40 E5

RRA LD LD JR PUSH LD ADD EX POP LD ADC RRA LD LD RRA LD LD RRA LD LD RRA LD DEC LD JR POP RET LD LD LD LD RET CALL LD CALL POP POP CALL JP LD CALL INC INC DEC LD LD DEC LD LD DEC LD LD LD EX XOR LD LD LD LD PUSH

H,A A,C NC,0881H HL HL,(4150H) HL,DE DE,HL HL A,(414FH) A,C C,A A,D D,A A,E E,A A,B B,A L A,H NZ,0871H HL B,E E,D D,C C,A 09A4H HL,0DD8H 09B1H BC DE 0955H Z,199AH L,0FFH 0914H (HL) (HL) HL A,(HL) (4089H),A HL A,(HL) (4085H),A HL A,(HL) (4081H),A B,C DE,HL A C,A D,A E,A (408CH),A HL

<--: Right shift LSB 1 position : Save shifted LSB : Load MSB into A : Jmp there when no one bit shifted from LSB : else save shifted LSB and count : Addr of middle & LSB bytes of orig register value : Add to total thus far far (compound add) : and leave sum in proper register : Restore shifted LSB and shift count : then add MSB of original register value : to the accumulated total : Right shift MSB : Save shifted MSB see notes--> : Load middle byte so : we can right shift it 1 bit : Save shifted middle byte : Load LSB and : right shift it 1 bit : then move it back : Load exponent : Right shift it : and restore it : Decrement count of bits tested : Restore original LSB value to A -->: Loop till all 8 bits tested --- Restore HL to addr. of next byte --- And rtn **************************************** see note--> * --Left circular shift BC/DE one byte. B is --lost and C is replaced by A. Shift appears --as follows: A BC/DE --A->C C->D D->E E->B --- Move value in WRA1 onto stack --- Addr of floating pt. 10. --- Load flt. pt. 10 into BC/DE and move into --- Reload original value :(4121 - 4124) --- of WRA1 into BC/DE --- Single precision division routine ****** cont--> * --- Error - division by zero attempted --- L = FF means subtract exponents --- Compute new exponent by addition. Set most sig. --- bit of each value, ret sign of result in 4125. --- Add 2 to exponent of dividend --- HL = 4123 = MSB of current value --- Load MSB of value in WRA1 --- 4089 = MSB of current value --- HL = addr of next most sig byte --- A = next most sig byte --- 4085 = most sig byte of current value --- HL = addr of least sig byte --- Load LSB and move it to --- 4081 = next most sig byte of current value --- B = most sig byte of register value --- DE = 4122, HL = MSB/LSB register value --- now, set --- MSB, next MSB --- LSB of register value --- to zero --- Zero count of times doubling B/HL overflows --- Save divisor in BC/HL on stack

105

: : : : : :

Examine current value for ones by using a right shift and test carry method. For each one bit found, add the register value (now in 414F - 4151) to the current value repeat process until all bits positions in current value have been tested.

: : : : : : : : :

Get MSB register value and add to MSB current value, then continue. Right justify current value in registers to get integer equivalent of value. Right shift D/E. Shift D first, bit 1 goes to carry which will be picked up when E is shifted. Result is left in BC/DE as an un-normalized floating point number. 4124 (exponent of current value holds adjusted exponent).

0892

* Called by single precision multiplying ********************* : while unpacking SP numbers before multiplying them

0897

* ************************************************************

08A2

* Test sign of value in WRA1 **********************************

106

08C8 08C9 08CA 08CD 08CF 08D0 08D2 08D5 08D6 08D7 08D8 08DB 08DC 08DD 08DE 08DF 08E2 08E3 08E4 08E5 08E6 08E7 08E8 08E9 08EA 08EB 08EC 08ED 08EE 08EF 08F0 08F3 08F4 08F7 08F8 08F9 08FA 08FC 08FD 0900 0901 0902 0904 0907 0909 090B 090E 090F 0910 0911 0912 0914 0915 0916 0918 0919 091C 091D 091E 091F

C5 7D CD8040 DE00 3F 3007 328C40 F1 F1 37 D2C1E1 79 3C 3D 1F FA9707 17 7B 17 5F 7A 17 57 79 17 4F 29 78 17 47 3A8C40 17 328C40 79 B2 B3 20CB E5 212441 35 E1 20C3 C3B207 3EFF 2EAF 212D41 4E 23 AE 47 2E00 78 B7 281F 7D 212441 AE 80 47 1F

PUSH LD CALL SBC CCF JR LD POP POP SCF JP LD INC DEC RRA JP RLA LD RLA LD LD RLA LD LD RLA LD ADD LD RLA LD LD RLA LD LD OR OR JR PUSH LD DEC POP JR JP LD LD LD LD INC XOR LD LD LD OR JR LD LD XOR ADD LD RRA

BC A,L 4080H A,00H NC,08D9H (408CH),A AF AF NC,0E1C1H A,C A A M,0797H A,E E,A A,D D,A A,C C,A HL,HL A,B B,A A,(408CH) (408CH),A A,C D E NZ,08C7H HL HL,4124H (HL) HL NZ,08C7H 07B2H A,0FFH L,0AFH HL,412DH C,(HL) HL (HL) B,A L,00H A,B A Z,0937H A,L HL,4124H (HL) A,B B,A

--- BC = most sig byte of reg value/00 --- A=LSB register value. Now compute dividend-divisor --- Subtract current value from reg. value cont--> --- On exit A=0, carry=1 if reg value<current value --- Reset carry so carry=1 if reg value>current value --->: Jmp if reg value<current value. Go double -- : Save count of times B/HL overflows :divisor -- : Clear last division from stack -- : We didn't need it -- : Set carry flag. <---: 8D9: POP BC Restore last divisor so --8DA: POP HL We can double it --- but first test for possible overflow --- by division out of HL into BC --- Test bit 0 of C, if it is on --- Done: Go normalize result --- Clear possible CARRY ON --- Shift E left one position. cont--> --- Pick up bit 8 of A-reg, --- Restore shifted E. Most sig. bit in CARRY --- Shift D left one position --- Pick up bit 8 from E becomes bit 0 of D --- Restore shifted D. Most sig. bit in CARRY --- Shift C left one position --- Pick up bit 8 from D becomes bit 0 of C --- Restore shifted C --- Now, double the divisor so that eventually it --- will exceed the dividend. When it does, the --- quotient plus reminder will be in B/HL as reg. --- values. Carry any overflow from shifting HL left --- one place to B. Then shift B left one place. Keep --- count of overflow amt of B in 408C as a bit --- string. i.e. the number of ones equals the --- number of times overflow occurred --- now combine all bytes --- of the register value and --- loop until divisor overflows --- Save HL --- Exponent of saved value --- Decrement it by 1 for: (A**X)/(B**Y)=(A/B)**(X-Y) --- Restore HL --- Continue with shift and decrement loop --- OV error (exponent has gone to zero) --- Computes new exponent for flt. pt. multiplication* --- 090A: XOR A Zero A, clear flags --- HL = addr of MSB for WRA2 DP value --- C = MSB, saved value : see note --> --- HL = addr of exponent for WRA2 DP value --- Make exp pos/neg depending on entry used --- Save exponent in B --- Mask for testing exponent sign of WRA1 (force --- Ref etch exponent & test for zero : sign +) --- Set status flags --- WRA1 value is zero --- Not zero. Get exponent for WRA1 value --- Which we already know is non-zero --- Combine sign of exp WRA1 with mask cont --> * --- Now, add the exponents for the two values to be --- multiplied and save in B-reg. Addition should --- produce a carry. Now test for presence.

107

08CA

: (4081-4089). Result in B/HL

0813

: Shift C/D/E left as one unit. Bits carried out of E are : shifted into D, etc.

0907

* ************************************************************ : : : : : When entered at 0917 it is the callers responsibility to load the L register according to the sign of the value in WRA1. L = 0 if WRA1 >= 0, L = FF if WRA1 < 0

091C

* in L. Note : The second entry at 0917

108

0920 0921 0922 0925 0927 0928 092B 092E 092F 0930 0931 0934 0935 0936 0937 0938 093B 093E 0941 0942 0943 0944 0946 0949 094A 094D 0950 0951 0952 0955 0958 0959 095A 095D 095F 0960 0961 0962 0963 0964 0966 0969 096C 096D 096E 0970 0971 0973 0974 0977 097A 097B 097C 097F 0982 0985 0986 0988 0989 098A

A8 78 F23609 C680 77 CA9008 CDDF09 77 2B C9 CD5509 2F E1 B7 E1 F27807 C3B207 CDBF09 78 B7 C8 C602 DAB207 47 CD1607 212441 34 C0 C3B207 3A2441 B7 C8 3A2341 FE2F 17 9F C0 3C C9 0688 110000 212441 4F 70 0600 23 3680 17 C36207 CD9409 F0 E7 FA5B0C CAF60A 212341 7E EE80 77 C9 CD9409

XOR LD JP ADD LD JP CALL LD DEC RET CALL CPL POP OR POP JP JP CALL LD OR RET ADD JP LD CALL LD INC RET JP LD OR RET LD CP RLA SBC RET INC RET LD LD LD LD LD LD INC LD RLA JP CALL RET RST JP JP LD LD XOR LD RET CALL

B A,B P,0936H A,80H (HL),A Z,0890H 09DFH (HL),A HL 0955H HL A HL P,0778H 07B2H 09BFH A,B A Z A,02H C,07B2H B,A 0716H HL,4124H (HL) NZ 07B2H A,(4124H) A Z A,(4123H) 2FH A,A NZ A B,88H DE,0000H HL,4124H C,A (HL),B B,00H HL (HL),80H 0762H 0994H P 20H M,0C5BH Z,0AF6H HL,4123H A,(HL) 80H (HL),A 0994H

-------------------------------------------------------------------------------------------------------------------------

Of carry by shifting it into bit 8 and doing an exclusive OR with new exponent see note-> Jmp if sum of exponent is out of range Reload new exponent into A and turn on bit 8 Store new exponent Jmp if value is exactly zero Turn on MSB of current value so it can be unpacked for repetitive addition. HL = next most sig byte Return to caller Go test sign of floating pt. number in WRA1 ****** Reverse the results so A = minus if value +, and is positive if value is minus. Set status flags according to new exponent Clear stack Set current floating point value to zero & return OV error exit Load a SP no. from 4121 - 4124 ***** see note--> * B = Exponent, C = MSB, D = Next MSB, E = LSB Set status flags according to new exponent Exit if number is zero Multiply number in registers by 4 Error if exponent overflows Restore adjusted exponent Add original value which gives value * 5 4124 = addr of exp of result. By adding 1 to it we double it which gives us the original value * 10 OV error exit Test sign of SP number. On exit A=-1 if negative Set status flags for exponent : A=+1 if positive Exit if exponent is zero No, get MSB of SP number 095E : CPL A Sign bit to carry Gives 0 - sign bit Return with A = all 1'S if MSB negative Return with A = +1 if MSB positive Rtn to caller B = 80 + number of bits to convert *************** Zero register used in normalization routine Addr of exponent for WRA1 C = MSB of integer Save initial exponent B must be zero before entering see note--> Normalization routine. Bump to sign word of WRA1 rtn it positive Set CARRY to sign of integer value Go normalize Convert a negative value *************** cont--> * Rtn if positive, else determine data type Test data type Integer, convert to + value, cont--> TM error if Z We have a SP, or a DP number. Make it positive by setting the sign bit (bit 8) of the MSB to zero. Set current value to zero if current value is +, all ones otherwise Rtn to caller Go test sign of current value ****** see note--> *

109

0921

: (Which should have bit 8 zero since it produced the carry : we're testing.)

0931

* ************************************************************

093E

* Multiply a SP number by 10 ********************************** : First, add 2 to exponent which is equivalent to multiplying : by 4 then add the original quantity which yields value * 5.

0964 * ************************************************************* : Start of integer to SP conversion. : Store exponent bits in 4124. : Set sign flag (4125) for positive : coefficient. Set C = MSB, : D = LSB of integer. Set carry to : Sign of MSB. Call normalization : routine. If entered at 0969 B must : be set to 80 + no of bits in integer value * to its positive equivalent ***---Test sign of current value *

0977

097C

: SP if it has overflowed & rtn to caller

098A

* A = +1 if positive, all ones if negative. *******************

110

098D 098E 098F 0990 0991 0994 0995 0998 099B 099E 099F 09A0 09A1 09A2 09A4 09A5 09A8 09A9 09AA 09AD 09AE 09AF 09B0 09B1 09B4 09B5 09B8 09B9 09BA 09BD 09BE 09BF 09C2 09C3 09C4 09C5 09C6 09C7 09C8 09C9 09CA 09CB 09CE 09D0 09D2 09D3 09D6 09D7 09D8 09D9 09DA 09DB 09DC 09DE 09DF 09E2 09E3 09E4 09E5 09E6

6F 17 9F 67 C39A0A E7 CAF60A F25509 2A2141 7C B5 C8 7C 18BB EB 2A2141 E3 E5 2A2341 E3 E5 EB C9 CDC209 EB 222141 60 69 222341 EB C9 212141 5E 23 56 23 4E 23 46 23 C9 112141 0604 1805 EB 3AAF40 47 1A 77 13 23 05 20F9 C9 212341 7E 07 37 1F 77

LD RLA SBC LD JP RST JP JP LD LD OR RET LD JR EX LD EX PUSH LD EX PUSH EX RET CALL EX LD LD LD LD EX RET LD LD INC LD INC LD INC LD INC RET LD LD JR EX LD LD LD LD INC INC DEC JR RET LD LD RLCA SCF RRA LD

L,A A,A H,A 0A9AH 20H Z,0AF6H P,0955H HL,(4121H) A,H L Z A,H 095FH DE,HL HL,(4121H) (SP),HL HL HL,(4123H) (SP),HL HL DE,HL 09C2H DE,HL (4121H),HL H,B L,C (4123H),HL DE,HL HL,4121H E,(HL) HL D,(HL) HL C,(HL) HL B,(HL) HL DE,4121H B,04H 09D7H DE,HL A,(40AFH) B,A A,(DE) (HL),A DE HL B NZ,09D7H HL,4123H A,(HL)

(HL),A

-------------------------------------------------------------------------------------------------------------------------

Set up HL as follows: HL = 00 00 if current value if positive. HL = FF FF if current val is negative gives A=0 if carry is zero or A=FF if CARRY is set. Move flag to H Save HL as current value, cont--> Determine current data type ************ cont--> * TM error if Z (string) Jump if SP or DP. Determine sign & rtn to caller Load integer value in HL Combine LSB and MSB in order to test if zero Exit if integer value zero A = MSB of integer Go test sign & rtn to caller cont--> ************************************************** Save HL Value to be moved onto stack Rtn addr to HL, stack = (4121) Rtn addr to stack 2nd value to be moved onto stack Rtn addr back to stack Restore HL Rtn to caller Load a SP no. pointed to by HL into BC/DE. ******* Then move it to WRA1 value area. On exit save HL (points to byte following exponent). On exit, B = exponent, C = MSB, D = next MSB, E = LSB, HL = addr of byte following exponent. Save LSB and next LSB in WRA1 Restore HL to original contents Return to caller Load a SP number from 4121 - 4124 or addr in HL ** E = LSB (4121) :see note --> Bump to next byte D = next MSB (4122) Bump to next byte C = MSB (4123) Bump to next byte B = exponent (4124) Bump to byte following exponent Rtn to caller Source address of a SP number ********** cont--> * Number of bytes to remove Move to address specified in HL and rtn to caller Move routine *********************** see note--> * Get type specification (which is also the length Length of field to move Load a byte from source field Store it in destination field see note--> Bump source addr Bump destination addr Count 1 byte moved Jmp if more bytes to move else rtn to caller Turn on most significant bit of a SP number ****** Get MSB Bit 7 to CARRY Turn on bit 7 and reposition number, also original sign bit to CARRY. Restore number with MSB on

111

0991 0994

: rtn type to integer & return to caller. * Test sign of current numeric value: on entry A = +1 : if positive or all ones if negative.

09A2 09A4

: on rtn A = all 1'S (negative), +1 (positive) * Store 4121 - 4124 (WRA1) on stack ***************************

09B1

* ************************************************************

09BF

* * * * *

************************************************************ 09BF: This entry point loads a SP number from WRA1 into BC/DE 09C2: This entry point loads a SP number pointed to by HL into BC/DE.

* * 09CB

On entry HL points to the LSB of a SP value On exit HL points to the byte following the exponent

* Move a SP no. from (HL) to 4121 - 4124 **********************

09D2

* Entry pt. when HL = source addr & DE = dest. addr. ********** : : : : Move number of bytes in type/ length specification from location given in DE to address specified in HL.

09DF

* ************************************************************

112

09E7 09E8 09E9 09EA 09EB 09EC 09ED 09EE 09EF 09F0 09F1 09F2 09F3 09F4 09F7 09FA 09FC 09FF 0A02 0A03 0A06 0A07 0A08 0A0B 0A0C 0A0D 0A0E 0A11 0A14 0A15 0A18 0A19 0A1A 0A1D 0A1E 0A1F 0A20 0A23 0A24 0A25 0A26 0A27 0A28 0A29 0A2A 0A2B 0A2C 0A2D 0A2E 0A2F 0A30 0A31 0A32 0A33 0A34 0A35 0A36 0A37 0A38 0A39

3F 1F 23 23 77 79 07 37 1F 4F 1F AE C9 212741 11D209 1806 212741 11D309 D5 112141 E7 D8 111D41 C9 78 B7 CA5509 215E09 E5 CD5509 79 C8 212341 AE 79 F8 CD260A 1F A9 C9 23 78 BE C0 2B 79 BE C0 2B 7A BE C0 2B 7B 96 C0 E1 E1 C9 7A

CCF RRA INC INC LD LD RLCA SCF RRA LD RRA XOR RET LD LD JR LD LD PUSH LD RST RET LD RET LD OR JP LD PUSH CALL LD RET LD XOR LD RET CALL RRA XOR RET INC LD CP RET DEC LD CP RET DEC LD CP RET DEC LD SUB RET POP POP RET LD

HL HL (HL),A A,C

C,A (HL) HL,4127H DE,09D2H 0A02H HL,4127H DE,09D3H DE DE,4121H 20H C DE,411DH A,B A Z,0955H HL,095EH HL 0955H A,C Z HL,4123H (HL) A,C M 0A26H C HL A,B (HL) NZ HL A,C (HL) NZ HL A,D (HL) NZ HL A,E (HL) NZ HL HL A,D

-------------------------------------------------------------------------------------------------------------------------

Complement bit zero and position it into bit 7 (sign & MS bit) of MSB HL = 4125 = sign of result -determined below Gives HL - 4125 Save complement of original sign in 4125 Turn on most significant bit of most significant byte for the SP value in BC/DE then force CARRY so we can restore byte with bit 7 = 1, original sign bit to Restore C = MSB :CARRY Original sign bit to bit 7 set sign flag as sign of both #'s equal, then 4125 = 80, else 00. Destination addr for numeric value of variable *** Return addr Move value in WRA1 to WRA2 Addr of WRA2 Move value in WRA1 to WRA2 Force rtn addr to 9D3 see note--> Addr of current variable in WRA1 Determine data type of variable Exit to move routine if INT, STR, or SP Addr of double precision variable Exit to move routine Compare a SP number in BC/DE with ****** cont--> * Test exponent of register value Jump if exponent (and rest of number) are zero. Rtn addr when exiting from this routine To stack Test sign of MSB of SP number. A = MSB of SP number in registers. Exit if (4121 - 4124) does not hold a SP number Addr of MSB of WRA1 value Compare MSB of (4121) to MSB of value in register Reload MSB of register value Exit if signs are different Compare SP mo. in BC/DE with that in 4121 - 4124. Get CARRY flag from comparison and combine with sign bit of value in registers. Rtn to caller HL = addr of exponent WRA1 ********************** A = exponent of register value Compare exponents Exit if different : Gives addr of MSB for WRA1 : A=MSB of register value : Compare MSB : see note--> Exit if not equal : Gives addr of middle for WRA1 : A = middle byte of reg value : Compare next most MSB : Exit if unequal Gives addr of LSB for WRA1 A = LSB of register value Compare LSB of values. Exit if not equal Exit if not equal Numbers are equal Clear 095E from stack and Rtn to caller of 0A0C Prepare to test signs ** Compare integer values **

113

09F4

* *************************************************************

0A02 : (Move 4DAF bytes from 4121 to 4127)

0A0C

* One in 4121 - 4124. Signs must be alike. On exit negative : if signs unlike or quantity in memory > value in registers.

0A26

* *************************************************************

0A29

: : : : : : : :

Compare a SP no. in BC/DE with a SP no. in 4121 - 4124 must have same signs. Do not compare exponents. Begin by comparing the exponent of each number, working down to the LSB. Exit as soon as a mix-match if found. HL = addr of byte that mis-compared. If the numbers are Identical exit with HL = 411F, A = 0, FLAGS = 0. If unequal C = 0 (memory) = or < register value C = 1 (memory) > register value

0A39

* *************************************************************

114

0A3A 0A3B 0A3C 0A3F 0A40 0A43 0A44 0A45 0A48 0A49 0A4C 0A4F 0A52 0A53 0A54 0A57 0A5A 0A5B 0A5E 0A5F 0A60 0A61 0A62 0A65 0A66 0A67 0A68 0A69 0A6A 0A6C 0A6D 0A6E 0A71 0A72 0A73 0A74 0A76 0A77 0A78 0A7B 0A7E 0A7F 0A80 0A83 0A84 0A87 0A8A 0A8D 0A8E 0A91 0A93 0A95 0A98 0A99 0A9A 0A9D 0A9F 0AA2 0AA3 0AA6

AC 7C FA5F09 BA C26009 7D 93 C26009 C9 212741 CDD309 112E41 1A B7 CA5509 215E09 E5 CD5509 1B 1A 4F C8 212341 AE 79 F8 13 23 0608 1A 96 C2230A 1B 2B 05 20F6 C1 C9 CD4F0A C25E09 C9 E7 2A2141 F8 CAF60A D4B90A 21B207 E5 3A2441 FE90 300E CDFB0A EB D1 222141 3E02 32AF40 C9 018090 110000

XOR LD JP CP JP LD SUB JP RET LD CALL LD LD OR JP LD PUSH CALL DEC LD LD RET LD XOR LD RET INC INC LD LD SUB JP DEC DEC DEC JR POP RET CALL JP RET RST LD RET JP CALL LD PUSH LD CP JR CALL EX POP LD LD LD RET LD LD

H A,H M,095FH D NZ,0960H A,L E NZ,0960H HL,4127H 09D3H DE,412EH A,(DE) A Z,0955H HL,095EH HL 0955H DE A,(DE) C,A Z HL,4123H (HL) A,C M DE HL B,08H A,(DE) (HL) NZ,0A23H DE HL B NZ,0A6CH BC 0A4FH NZ,095EH 20H HL,(4121H) M Z,0AF6H NC,0AB9H HL,07B2H HL A,(4124H) 90H NC,0AA3H 0AFBH DE,HL DE (4121H),HL A,02H (40AFH),A BC,9080H DE,0000H

--- Compare sign of D to sign of H see note--> --- Prepare for subtraction --- Jmp if signs unequal --- Else, compare MSB's --- Jmp if unequal --- Prepare to compare LSB of integer --- Compare LSB's --- Jmp it unequal --- Rtn - Values are equal. A=00 --- Addr of WRA1 value **** Compare two DP values **** --- Move value pointed to by saved location 4127-412E --- Now get addr of the exponent for the value moved --- Load the exponent --- Set status flags according to exponent --- If exponent zero, test sign of MSB & rtn to caller --- Push rtn addr of 95E onto stack in case WRA1 and --- WRA2 values not equal --- Test WRA1 value for zero. Skip if zero at 0A61 --- DE = addr of MSB of moved value --- Load MSB --- and move it to C --- Exit if MSB of WRA1 value is zero --- HL = addr of MSB for current value --- Compare sign of moved & current values --- Restore MSB of WRA2 value (moved value) --- Exit if signs different --- DE = current value exponent addr --- HL = saved value exponent addr --- Prepare to compare current and saved values <--: Begin comparing values byte for byte : by subtracting WRA1 from WRA2 : Jump if unequal : Backspace WRA2 1 byte : Backspace WRA1 1 byte : Count number of bytes compared ---> Loop till all bytes compared --- Values are equal, clear rtn addr of 95E from stack --- and rtn to caller --- Compare current to saved value ***** see note--> * --- Set status flag if unequal --- Equal. Return with A=00, status = 0 --- Test data type ***************** CINT routine **** --- HL = addr of LSB of SP value in WRA1 --- Already an integer --- TM error if Z (string) --- If double precision, call CSGN --- Address of OV error routine becomes --- Rtn addr in case of error --- Get exponent of current value in WRA1 --- and test if > 16 : 16 bits) --->: Jump if exponent>16 (integer has more than -- : Convert A +SP number to its integer equivalent -- : Integer value in DE to HL -- : Clear error rtn or addition operand from stack -- : Return integer value in HL to WRA1 -- : Integer flag -- : Set data type to integer -- : Rtn to original caller <---: BC/DE = -2**16 ******************************** --- in SP format

115

0A3A

: Compare integer values in DE/HL. If signs are unlike, rtn : with status of -1. If DEAL then rtn A=-1, if DEAL then : A=+1, if DE=HL then A=00.

0A49

* *************************************************************

0A78

* Compare two DP values ***************************************

0A7F

* *************************************************************

0AA3

* *************************************************************

116

0AA9 0AAC 0AAD 0AAE 0AAF 0AB1 0AB2 0AB3 0AB6 0AB9 0ABC 0ABF 0AC0 0AC1 0AC2 0AC5 0AC8 0AC9 0ACC 0ACF 0AD2 0AD3 0AD4 0AD6 0AD8 0ADB 0ADC 0ADD 0AE0 0AE3 0AE6 0AE9 0AEC 0AEE 0AF1 0AF4 0AF5 0AF6 0AF8 0AFB 0AFC 0AFD 0AFE 0AFF 0B00 0B01 0B02 0B05 0B08 0B09 0B0A 0B0D 0B0F 0B10 0B13 0B14 0B15 0B18 0B1A 0B1D

CD0C0A C0 61 6A 18E8 E7 E0 FACC0A CAF60A CDBF09 CDEF0A 78 B7 C8 CDDF09 212041 46 C39607 2A2141 CDEF0A 7C 55 1E00 0690 C36909 E7 D0 CAF60A FCCC0A 210000 221D41 221F41 3E08 013E04 C39F0A E7 C8 1E18 C3A219 47 4F 57 5F B7 C8 E5 CDBF09 CDDF09 AE 67 FC1F0B 3E98 90 CDD707 7C 17 DCA807 0600 DCC307 E1

CALL RET LD LD JR RST RET JP JP CALL CALL LD OR RET CALL LD LD JP LD CALL LD LD LD LD JP RST RET JP CALL LD LD LD LD LD JP RST RET LD JP LD LD LD LD OR RET PUSH CALL CALL XOR LD CALL LD SUB CALL LD RLA CALL LD CALL POP

0A0CH NZ H,C L,D 0A99H 20H PO M,0ACCH Z,0AF6H 09BFH 0AEFH A,B A Z 09DFH HL,4120H B,(HL) 0796H HL,(4121H) 0AEFH A,H D,L E,00H B,90H 0969H 20H NC Z,0AF6H M,0ACCH HL,0000H (411DH),HL (411FH),HL A,08H BC,043EH 0A9FH 20H Z E,18H 19A2H B,A C,A D,A E,A A Z HL 09BFH 09DFH (HL) H,A M,0B1FH A,98H B 07D7H A,H C,07A8H B,00H C,07C3H HL

-------------------------------------------------------------------------------------------------------------------------

Compare current value to -2**16 If values not identical exit If so, set current value to integer,-2**16 and rtn to caller Rtn type to integer, value to 8000, & return Test data type ************* CSNG routine ******** Already single Jump if integer TM error if Z (string) Load a first half of DP value from WRA1 into BC/DE Flag current value as single precision Get exponent for DP value Set status flags Test exponent, exit if zero (DP value is zero) Turn on MSB of value in WRA1 & register value HL = middle addr of DP value in WRA1 Load middle part of DP. Value becomes LSB Convert reg part of DP no to SP value & rtn Convert integer to single precision ************ Flag WRA1 as SP A = MSB of integer D = LSB of integer E = Rest of value (equals zero) B = initial max exponent Go normalize then rtn to caller Test data type *************** See note --> **** Already double Jump if sting Call if integer (convert integer to SP) Zero last 4 bytes of WRA1 These bytes hold the tail end of a DP value Double precision flag 0AEF LD A,04 Single precision flag Store A in type flag & return Test data type********************************* Return with no error message if a string TM error code if not a string Output TM error message Convert a positive SP number to integer ********** Move exponent from A to BC, D and E Test value of exponent Exit if value of number is zero Save error rtn addr Load current SP value into BC/DE Prepare current value and register value for arithmetic operation see note--> H = sign of value. Bit 8 = 0 if +, 1 if Jmp if value negative A = max. exponent allowed Exponent - bias = no. of bits to right cont--> Get integer equivalent of no. in CDE cont--> A = original sign. Bit 8 = 0 if +, 1 if Shift sign into carry If neg. convert trailing ones to zeroes Zero exponent If number was neg. make it a neg. integer Restore caller's HL

117

0AB1

* *************************************************************

0ACC

* *************************************************************

0ADB

* Convert integer or SP to DP ******************************

0AF4

* *************************************************************

0AFB

* *************************************************************

0B08

: (Turn on most sig. bits and test for same sign).

0B0F 0B10

: shift to get integer : right justified

118

0B1E 0B1F 0B20 0B21 0B22 0B23 0B24 0B25 0B26 0B27 0B28 0B2B 0B2E 0B31 0B34 0B37 0B38 0B39 0B3B 0B3D 0B40 0B43 0B44 0B46 0B49 0B4A 0B4B 0B4E 0B50 0B51 0B52 0B53 0B54 0B57 0B58 0B59 0B5C 0B5D 0B5F 0B62 0B64 0B65 0B66 0B67 0B69 0B6B 0B6C 0B6D 0B6E 0B70 0B71 0B74 0B77 0B78 0B7A 0B7B 0B7C 0B7F 0B82 0B83

C9 1B 7A A3 3C C0 0B C9 E7 F8 CD5509 F2370B CD8209 CD370B C37B09 E7 F8 301E 28B9 CD8E0A 212441 7E FE98 3A2141 D0 7E CDFB0A 3698 7B F5 79 17 CD6207 F1 C9 212441 7E FE90 DA7F0A 2014 4F 2B 7E EE80 0606 2B B6 05 20FB B7 210080 CA9A0A 79 FEB8 D0 F5 CDBF09 CDDF09 AE 2B

RET DEC LD AND INC RET DEC RET RST RET CALL JP CALL CALL JP RST RET JR JR CALL LD LD CP LD RET LD CALL LD LD PUSH LD RLA CALL POP RET LD LD CP JP JR LD DEC LD XOR LD DEC OR DEC JR OR LD JP LD CP RET PUSH CALL CALL XOR DEC

DE A,D E A NZ BC 20H M 0955H P,0B37H 0982H 0B37H 097BH 20H M NC,0B59H Z,0AF6H 0A8EH HL,4124H A,(HL) 98H A,(4121H) NC A,(HL) 0AFBH (HL),98H A,E AF A,C 0762H AF HL,4124H A,(HL) 90H C,0A7FH NZ,0B78H C,A HL A,(HL) 80H B,06H HL (HL) B NZ,0B6BH A HL,8000H Z,0A9AH A,C 0B8H NC AF 09BFH 09DFH (HL) HL

-------------------------------------------------------------------------------------------------------------------------

Rtn to caller Decrement middle and LSB of SP value *** cont--> * then combine new middle & LSB. If they were zero the cont--> Test for FFFF (middle & LSB were 0) Exit if they were not zero Else decrement MSB Then exit Determine data type ********* Fix routine ******** Finished if an integer Test sign of current value (floating point) Jmp if it's positive Clear sign bit of current value (make it +) Convert a SP or DP value to integer. Do not round Convert integer part of no. back to cont--> Convert SP or DP to integer - Determine data type* Done, already an integer Jump if double precision TM error if Z (string) Convert from SP to integer & return to caller HL = addr of current SP value ******************** A = exponent of current value Test if more than 16 bits in integer position A = least sig byte of current value Exit if more than 16 bits in integer position A = exponent see note--> Convert SP to integer. This gives integer equivalent of number. Now, convert number back to SP Move 8 bits of integer value From E to A then save it on stk. Then position sign from bit 8 of C in CARRY then Normalize number & adjust exponent Restore 8 bits of integer value Rtn to caller. Double precision to integer ********************** Get exponent and compare to bias Jump if number will have less than 16 cont--> Jump if number will have more than 16 cont--> C = exponent = 90 Number will have 16 bits of int Backspace to MSB of WRA1 A = most sig byte Complement sign bit of MSB Test for a minus zero. If sum of A plus all successive bytes is zero, then value is zero. Backspace to next byte of DP value Examined all bytes No, loop Set status flags for OR of all bytes in DP value HL = integer - 0 Rtn value to - 0, type to integer and return to DP exponent to A-reg caller Compare to 56(base 10) Error - more than 56 bits in DP no. Save exponent Load BC/DE with first part of a DP number Turn on most sig bit. Determine sign of result Test sign of value. If + then status = +, else HL=4123=MSB current value addr :negative

119

0BlF 0B21

* Round down a SP number ************************************** : result will be FFFF.

0B26

* *************************************************************

0B34 0B37

: SP or DP then return * *************************************************************

0B40

* *************************************************************

: : : :

Isolate the integer portion of a SP number. Leave the integer in the A-register. Convert the integer to a SP number and leave it in WRA1 returns with NO CARRY if called with a DP value in WRA1.

0B59

* *************************************************************

0B5F 0B62

: bits of precision. Use SP to integer conversion routine. : bits of precision

120

0B84 0B86 0B87 0B8A 0B8D 0B8F 0B90 0B93 0B94 0B97 0B98 0B9B 0B9C 0B9D 0BA0 0BA3 0BA4 0BA5 0BA6 0BA7 0BA9 0BAA 0BAB 0BAE 0BAF 0BB0 0BB2 0BB4 0BB5 0BB8 0BB9 0BBA 0BBB 0BBD 0BBE 0BC1 0BC2 0BC4 0BC5 0BC6 0BC7 0BC8 0BC9 0BCA 0BCB 0BCE 0BCF 0BD0 0BD2 0BD3 0BD4 0BD5 0BD6 0BD7 0BD8 0BD9 0BDA 0BDB 0BDC 0BDD

36B8 F5 FCA00B 212341 3EB8 90 CD690D F1 FC200D AF 321C41 F1 D0 C3D80C 211D41 7E 35 B7 23 28FA C9 E5 210000 78 B1 2812 3E10 29 DA3D27 EB 29 EB 3004 09 DA3D27 3D 20F0 EB E1 C9 7C 17 9F 47 CD510C 79 98 1803 7C 17 9F 47 E5 7A 17 9F 19 88 0F AC

LD PUSH CALL LD LD SUB CALL POP CALL XOR LD POP RET JP LD LD DEC OR INC JR RET PUSH LD LD OR JR LD ADD JP EX ADD EX JR ADD JP DEC JR EX POP RET LD RLA SBC LD CALL LD SBC JR LD RLA SBC LD PUSH LD RLA SBC ADD ADC RRCA XOR

(HL),0B8H AF M,0BA0H HL,4123H A,0B8H B 0D69H AF M,0D20H A (411CH),A AF NC 0CD8H HL,411DH A,(HL) (HL) A HL Z,0BA3H HL HL,0000H A,B C Z,0BC4H A,10H HL,HL C,273DH DE,HL HL,HL DE,HL NC,0BC1H HL,BC C,273DH A NZ,0BB4H DE,HL HL A,H A,A B,A 0C51H A,C A,B 0BD5H A,H A,A B,A HL A,D A,A HL,DE A,B H

--- Max exponent to exponent area --- Save sign of value --- If negative, convert trailing ones to zeroes --- HL = addr of MSB of DP value --- A = exponent (max) for DP number --- Subtract current exponent gives no. cont--> --- Unpack and right justify value --- Restore sign --- If negative, convert trailing zeroes to ones --- Clear A --- Ret sign of mantissa --- Restore original exponent --- Error if more than 56 bits in mantissa --- Normalize result and exit --- HL=addr of LSB of DP value ********* see note--> * <---: Fetch a byte from list : Decrement byte in list : Test byte as originally fetched : Bump to next item in list --->: Loop till non-zero byte found --- Rtn to caller --- Save callers HL********************* see note-> ** --- Zero accumulator register --- Test quantity in BC, if --- zero, move zeros to DE & exit ------>: Jump if BC zero : A = 16 = no. of times to shift left <------:--: Shift result left 1 position : : BS error if C : : Prepare to shift multiplicand left : : 1 place. Shift it and : : move it back to DE --->: : : If no carry, has not found a l, don't add : : : Else add multiplier to result thus far : : : BS error if C <---: : : Have we shifted 16 times -------:->: No, loop <------: Move answer to DE --- Restore caller's HL --- Return to caller --- Test sign of value in HL *********** see note--> * --- And save in B. B = 0 --- If HL +, all one's if HL neg. --- Move sign flag to B --- Convert HL to it's one's compliment cont--> --- Zero to A. Setup A for sign of difference. If HL --- was +, then A=+0, if was -, then A=-1 --- Use addition routine. If result cont--> --- Set B = sign of HL ***************** see note--> * --- Sign bit to CARRY --- B = 0 if HL +, else -1 --- Repositioned sign bit to B --- Save HL in case we must convert it to SP --- MSB of register value so we can test sign --- Set A = sign of DE --- A = 0 if HL +, else -1 --- Add the two integers. Add sign of result to sum --- of the signs --- Sign of result to bit 7 and --- combine with sign of HL

121

0B8F

: of places to right shift to get integer

0BA0

* Convert trailing ones to a neg. DP value to zeroes **********

0BAA

* : : :

Binary multiplication of two 16 bit quantities in BC and DE** Result is left in DE. Uses shift and add method. Called from BASIC interpreter when computing addr of a subscripted variable.

0BC7

* Binary subtraction for two 16 bit values in HL and DE.*******

0BCB

: so we use addition routine

0BD0 0BD2

: * : : : : : : : : :

underflows convert to SP. Binary addition for two integers in HL & DE. Result left in** HL. If result overflows convert both quantities to SP and add. Determine overflow as follows: C = carry after addition C = 0 -- No overflow C = 1 --- then if : ---------!---------: : A = 0, B = 0 A <> B then overflow negative no.

122

0BDE 0BE1 0BE2 0BE3 0BE6 0BE7 0BE8 0BEB 0BEC 0BEF 0BF2 0BF3 0BF4 0BF7 0BF8 0BF9 0BFC 0BFD 0BFE 0BFF 0C02 0C04 0C05 0C07 0C08 0C09 0C0A 0C0C 0C0D 0C10 0C11 0C13 0C14 0C15 0C16 0C17 0C1A 0C1B 0C1C 0C1F 0C21 0C22 0C24 0C25 0C28 0C2B 0C2C 0C2F 0C32 0C33 0C34 0C37 0C38 0C39 0C3A 0C3D 0C3E 0C41 0C42 0C45

F2990A C5 EB CDCF0A F1 E1 CDA409 EB CD6B0C C38F0F 7C B5 CA9A0A E5 D5 CD450C C5 44 4D 210000 3E10 29 381F EB 29 EB 3004 09 DA260C 3D 20F1 C1 D1 7C B7 FA1F0C D1 78 C34D0C EE80 B5 2813 EB 01C1E1 CDCF0A E1 CDA409 CDCF0A C1 D1 C34708 78 B7 C1 FA9A0A D5 CDCF0A D1 C38209 7C

JP PUSH EX CALL POP POP CALL EX CALL JP LD OR JP PUSH PUSH CALL PUSH LD LD LD LD ADD JR EX ADD EX JR ADD JP DEC JR POP POP LD OR JP POP LD JP XOR OR JR EX LD CALL POP CALL CALL POP POP JP LD OR POP JP PUSH CALL POP JP LD

P,0A99H BC DE,HL 0ACFH AF HL 09A4H DE,HL 0C6BH 0F8FH A,H L Z,0A9AH HL DE 0C45H BC B,H C,L HL,0000H A,10H HL,HL C,0C26H DE,HL HL,HL DE,HL NC,0C10H HL,BC C,0C26H A NZ,0C04H BC DE A,H A M,0C1FH DE A,B 0C4DH 80H L Z,0C37H DE,HL BC,0E1C1H 0ACFH HL 09A4H 0ACFH BC DE 0847H A,B A BC M,0A9AH DE 0ACFH DE 0982H A,H

--- No overflow. Flag result as integer, cont-->: --- Save sign flag on stk --- Original DE to HL for conversion purposes. --- Convert original value of DE to SP. Save it in --- 4121 - 4124. Clear stk. --- Restore original quantity in HL. It was wiped by --- Move converted value of DE to stack : add. --- Restore HL --- Convert HL to single precision --- Add single precision equivalent of HL & DE --- Test value of HL ******************* see note--> * --- If --- Zero, exit with result (0) in HL --- Save original value in case we need to --- convert them to SP. --- Set result to integer type. Convert any neg. --- value to +. BC = sign of result (pushed one). --- B = MSB of value 2 --- BC = value 2 --- HL = accumulator --- No. of times to shift left. <-------: Shift answer and test for : overflow. CARRY if so. : No overflow, shift DE left : one bit and test for a binary : one (CARRY). ---->: : No CARRY, no binary one : : Add original value in HL to --------:->: Accumulator for each binary one <----: : : in DE. ------->: : Have we shifted DE 16 places, no loop --: Yes, get sign of result --: Original value in DE --: Now test true sign of result --: Set status flags according to result --: Jump if answer is negative. see note--> --: Clear stack, --: get sign of result to A --: Convert HL to proper sign, cont--> --: Clear sign bit & test rest of value for 0 --: If zero, we have a negative number, else --: Convert it to single precision etc. --: :C26 POP BC Clear sign of result note--> <--------- : :C27 POP HL Restore original HL value --- Convert original HL to single precision --- HL = original DE --- Move converted HL to stack --- Convert DE (now in HL) to single precision --- Load converted HL value from stack --- into BC/DE --- Do single precision multiplication --- Get sign flag of result ************************** --- Rtn status flags to sign of result --- Clear stack in case we exit --- If sign was suppose to be negative, exit --- Save original DE --- Convert result to single precision --- Restore original DE --- Rtn sign and return to caller --- Get sign of MSB from 2nd operand **** see note-->*

123

store in 4121 & return.

0BF2

* : : : : : : : : : :

Integer multiplication. DE = first value, HL = 2nd value.*** Result is left in HL. If the signs of both operands are equal, then the result has the same sign. If either sign is different, the result is set negative. Any negative values are converted to their positive equivalents before the multiplication is started. Method used is shift and add. For each 1 found in DE, the original contents of HL are added to an accumulator register (HL in this case) and shifted left. Process is repeated 16 times (must test all 16 bits in DE). If overflow occurs, convert both values to SP and use SP multiplication routine.

0C17

: (May have overflowed.)

0C1C 0C1F

: save result and return to caller. * *************************************************************

0C24

: Number has overflowed. Convert to SP to re-multiply.

0C37

* *************************************************************

0C45

: : If HL is negative convert it to its one's complement. * *** : If DE is negative convert it also. ********************

124

0C46 0C47 0C48 0C4B 0C4C 0C4D 0C4E 0C51 0C52 0C53 0C54 0C55 0C56 0C57 0C58 0C5B 0C5E 0C61 0C62 0C64 0C65 0C66 0C67 0C6A 0C6B 0C6D 0C70 0C73 0C74 0C76 0C77 0C7A 0C7B 0C7C 0C7D 0C7E 0C7F 0C80 0C83 0C84 0C85 0C88 0C89 0C8B 0C8C 0C8D 0C8E 0C90 0C91 0C92 0C93 0C94 0C95 0C96 0C97 0C98 0C99 0C9A 0C9C 0C9D

AA 47 CD4C0C EB 7C B7 F29A0A AF 4F 95 6F 79 9C 67 C39A0A 2A2141 CD510C 7C EE80 B5 C0 EB CDEF0A AF 0698 C36909 212D41 7E EE80 77 212E41 7E B7 C8 47 2B 4E 112441 1A B7 CAF409 90 3016 2F 3C F5 0E08 23 E5 1A 46 77 78 12 1B 2B 0D 20F6 E1 46

XOR LD CALL EX LD OR JP XOR LD SUB LD LD SBC LD JP LD CALL LD XOR OR RET EX CALL XOR LD JP LD LD XOR LD LD LD OR RET LD DEC LD LD LD OR JP SUB JR CPL INC PUSH LD INC PUSH LD LD LD LD LD DEC DEC DEC JR POP LD

D B,A 0C4CH DE,HL A,H A P,0A9AH A C,A L L,A A,C A,H H,A 0A9AH HL,(4121H) 0C51H A,H 80H L NZ DE,HL 0AEFH A B,98H 0969H HL,412DH A,(HL) 80H (HL),A HL,412EH A,(HL) A Z B,A HL C,(HL) DE,4124H A,(DE) A Z,09F4H B NC,0CA1H A AF C,08H HL HL A,(DE) B,(HL) (HL),A A,B (DE),A DE HL C NZ,0C92H HL B,(HL)

-------------------------------------------------------------------------------------------------------------------------

And combine with sign from 1st operand. B = + if signs are equal (+,+) or (-,-), cont--> Test sign of HL operand. If neg. convert to pos. Switch HL/DE so we can test sign of DE cont--> Get sign byte of value in DE. Set status flags according to sign of value in DE Flag as integer, result to 4121. Rtn to caller Clear A, CARRY Zero C : Convert a negative : Convert LSB : integer to its one's : And restore : complement positive : Zero to A : equivalent : Convert MSB And restore Set data type to integer(02), cont--> Get binary value of integer ********************** Convert to a positive value Make sure value is LE 2**15 If bit 15 is not zero, and the remainder of the word is zero then value > 2**15 Rtn if integer = or < 32768 Value is > 2**15. Move it to DE Set SNG precision flag Set exponent to zero Maximum exponent for SP values Convert value to SP and rtn to caller Double precision subtraction routine. ** cont--> * Load MSB of saved value Invert sign And restore HL=addr of exponent in WRA2 ************ cont--> * Load exponent from WRA2 Set status flags for exponent Exit if WRA2 value zero B = Exponent WRA2 value Backspace to MSB of WRA2 C = MSB WRA2 number DE = addr exponent of WRA1 value Load exponent of value in WRA1 Set status flags Jump if WRA1 value is zero Else, compare exponents : WRA1 - WRA2 Jump if WRA1 exponent > WRA2 exponent cont--> Make diff. in exponent positive Current number is larger than saved number Save difference in exponents Now, swap the two numbers so that WRA1 = WRA2 And visa-versa HL = addr of exponent WRA2 Swap WRA1 and WRA2 double precision numbers Load a byte from WRA1 Load a byte from WRA2 : Force larger WRA1 byte to WRA2 : number into WRA2 byte to WRA1 : WRA1 Decrement WRA1 addr. Decrement WRA2 addr. Count 1 byte moved Loop till 8 bytes of SP numbers moved Restore addr. of WRA2 to HL B = exponent of new WRA2 number

125

0C47 0C4B

: negative if unlike (+,-) : Convert to + if its negative.

0C58 0C5B

: Save value in 4121/4122 & return * *************************************************************

0C70

* Addr of saved DP value **************************************

0C77

* Double precision addition routine. Add current value to : saved value.

0C89

: There are less bits in integer portion so it is smaller

126

0C9E 0C9F 0CA0 0CA1 0CA3 0CA4 0CA5 0CA8 0CA9 0CAB 0CAC 0CAD 0CB0 0CB3 0CB6 0CB9 0CBA 0CBB 0CBE 0CC1 0CC4 0CC5 0CC6 0CC9 0CCC 0CCF 0CD2 0CD5 0CD8 0CD9 0CDA 0CDD 0CDE 0CE0 0CE3 0CE5 0CE6 0CE7 0CE8 0CE9 0CEA 0CEC 0CED 0CEF 0CF1 0CF3 0CF6 0CF7 0CFA 0CFD 0CFE 0D01 0D02 0D03 0D05 0D08 0D09 0D0A 0D0D 0D0E

2B 4E F1 FE39 D0 F5 CDDF09 23 3600 47 F1 212D41 CD690D 3A2641 321C41 78 B7 F2CF0C CD330D D20E0D EB 34 CAB207 CD900D C30E0D CD450D 212541 DC570D AF 47 3A2341 B7 201E 211C41 0E08 56 77 7A 23 0D 20F9 78 D608 FEC0 20E6 C37807 05 211C41 CD970D B7 F2F60C 78 B7 2809 212441 86 77 D27807 C8 3A1C41

DEC LD POP CP RET PUSH CALL INC LD LD POP LD CALL LD LD LD OR JP CALL JP EX INC JP CALL JP CALL LD CALL XOR LD LD OR JR LD LD LD LD LD INC DEC JR LD SUB CP JR JP DEC LD CALL OR JP LD OR JR LD ADD LD JP RET LD

HL C,(HL) AF 39H NC AF 09DFH HL (HL),00H B,A AF HL,412DH 0D69H A,(4126H) (411CH),A A,B A P,0CCFH 0D33H NC,0D0EH DE,HL (HL) Z,07B2H 0D90H 0D0EH 0D45H HL,4125H C,0D57H A B,A A,(4123H) A NZ,0CFEH HL,411CH C,08H D,(HL) (HL),A A,D HL C NZ,0CE5H A,B 08H 0C0H NZ,0CD9H 0778H B HL,411CH 0D97H A P,0CF6H A,B A Z,0D0EH HL,4124H A,(HL) (HL),A NC,0778H Z A,(411CH)

--- HL = addr. of MSB of WRA2 value --- C = MSB new WRA2 number --- A = difference in exponents --- Is diff in exponent more than 56 bits --- Exit if difference in exponent more than 56 bits --- Save diff. in exponents --- Turn on most significant bit in MSB of WRA1 --- HL = addr. of bit bucket zeroed --- during normalization. Zero it --- Save sign flag for WRA2 --- Restore exponent diff. --- HI. = addr of MSB for saved value --- Scale (right justify) saved value so its exponent --- = current value then the two numbers can be added --- Get last 8 bits shifted out of WRA2 value --- Get sign flag for WRA2 value --- Set status flags according to WRA2 sign --- Signs are different, must subtract --- Add DP number in (4127-412D) to (411D-4123) --- If no CARRY, adjust sign of result and exit --- There was CARRY, increment exponent of current --- value, error if overflow --- Jump to OV error message routine --- Then right shift coefficient, position --- Adjust sign of result and return --- Subtract saved value from current ****** cont--> * --- HL = Sign flag for result --- If CARRY, then get one's complement of the diff. --- Initial counter value <-----: Zero B for normalization loop below : Fetch MSB and : Test for zero ------->: If non-zero, go shift left until cont--> : : HL = addr of LSB-1 for DP value in WRA1 : : C = no. of bytes to shift <---: : : Get next byte to be moved : : : Save current byte : : : Save byte to be moved to succeeding addr : : : Bump to next byte in WRA1 : : : Have we shifted entire DP no. left one byte --->: : : No, loop : : : Yes, in case no. is zero, don't loop forever : : : Have we shifted the LSB all the way to the : : : exponent (8 bytes) ----->: : No, continue looking for a non-zero MSB --: Yes, zero exponent & return <---: : Maintain count of bytes & bits shifted left * : : Addr of LSB of 8 byte no. to shift left 1 bit : : Shift number left one place : : Test bit 7 of MSB <-->:<--: Continue shifting until bit 7 = 1 --- Test count of places shifted left --- Set status flags for count --- Jmp if value already normalized --- HL=address of exponent --- Add count of bits shifted left to bias --- Save new exponent --- If no overflow, set exponent to zero --- and rtn to caller --- Get MSB of current value

127

0CCF

* Difference replaces current ********************************* : Normalize the difference. Test the MSB, if zero shift entire : number left one byte. When MSB is non-zero shift number : left one bit at a time until a one is shifted into bit 7 : of the MSB.

0CDE

: A 1 appears in bit 7. Else shift entire number left one byte : starting at the LSB shifting towards the exponent.

0CF6

* *************************************************************

128

0D11 0D12 0D15 0D18 0D19 0D1B 0D1C 0D1D 0D1E 0D1F 0D20 0D23 0D25 0D26 0D27 0D28 0D29 0D2B 0D2C 0D2F 0D30 0D32 0D33 0D36 0D39 0D3B 0D3C 0D3D 0D3E 0D3F 0D40 0D41 0D42 0D44 0D45 0D48 0D4B 0D4D 0D4E 0D4F 0D50 0D51 0D52 0D53 0D54 0D56 0D57 0D58 0D59 0D5A 0D5D 0D5F 0D60 0D61 0D62 0D63 0D64 0D65 0D66 0D68

B7 FC200D 212541 7E E680 2B 2B AE 77 C9 211D41 0607 34 C0 23 05 20FA 34 CAB207 2B 3680 C9 212741 111D41 0E07 AF 1A 8E 12 13 23 0D 20F8 C9 212741 111D41 0E07 AF 1A 9E 12 13 23 0D 20F8 C9 7E 2F 77 211C41 0608 AF 4F 79 9E 77 23 05 20F9 C9

OR CALL LD LD AND DEC DEC XOR LD RET LD LD INC RET INC DEC JR INC JP DEC LD RET LD LD LD XOR LD ADC LD INC INC DEC JR RET LD LD LD XOR LD SBC LD INC INC DEC JR RET LD CPL LD LD LD XOR LD LD SBC LD INC DEC JR RET

A M,0D20H HL,4125H A,(HL) 80H HL HL (HL) (HL),A HL,411DH B,07H (HL) NZ HL B NZ,0D25H (HL) Z,07B2H HL (HL),80H HL,4127H DE,411DH C,07H A A,(DE) A,(HL) (DE),A DE HL C NZ,0D3CH HL,4127H DE,411DH C,07H A A,(DE) A,(HL) (DE),A DE HL C NZ,0D4EH A,(HL) (HL),A HL,411CH B,08H A C,A A,C A,(HL) (HL),A HL B NZ,0D61H

--- Set status flags --- If value is negative, reset trailing zeroes to --- Get sign of result :ones --- into A register --- Isolate sign of result flag --- Backspace to sign of mantissa --- gives HL-2 --- Set sign of result to mantissa of result --- Restore MSB with correct sign --- Ret to caller --- HL = Addr of LSB for current DP value ************ --- Current DP value --- Bump LSB --- Exit if no overflow : --- Else add CARRY to : --- Next byte until no : see note--> --- Overflow : --- Bump exponent : --- OV error code --- Number has become negative --- Reset MSB=80, rest of byte=00 --- Rtn --- Addr of augment ********************************** --- Addr of addend --- No. of bytes to add --- Clear CARRY flag : <----: Do addition : : Begin with LSB and work : see note--> : Towards MS B. Move : : result to WRA1 (4121-4124). Number : must be unpacked before starting addition : Count 1 byte added ---->: Loop till all bytes added --- Rtn to caller --- Start of WRA2 value ****************************** --- Start of WRAl value --- No. of bytes to subtract --- Clear CARRY flag <----: Get a current LSB and : : Subtract a saved LSB : : From it. Result replaces : see note--> : Current value. Bump fetch : : addresses for WRA1 & WRA2 : : Count bytes subtracted ---->: Loop till all bytes subtracted --- Then rtn --- Set sign flag to E ******************************* --- Indicating one's complement --- Restore sign flag --- HL = addr of LSB of current DP --- No. of bytes to complement --- Zero A & clear CARRY flag : --- Save zero so it can be reloaded : <----: Reload zero, leave CARRY untouched : see note--> : Complement a byte : : And restore it : : Bump to next byte of number : Done 8 bytes ---->: No, loop --- Yes, exit

129

0D20

* : : : :

************************************************************* Add 1 to a DP number in WRA1 Begin by adding 1 to the LSB. If overflow (result = 0), add the CARRY to next byte, etc. If there is overflow out of the exponent then the number has overflowed.

0D33

* : : : : :

************************************************************* Add two double precision numbers. Add coefficients only, do not add exponents. Address of one number in DE, and other in HL. Sum replaces the number pointed to by HL

0D45

* : : :

************************************************************* Subtract two double precision numbers Contents of (411D - 4123) are subtracted from (4127 - 412D). Result replaces (411D - 4123).

0D57

* ************************************************************* : This routine converts a positive DP value in WRA1 : to its one's complement equivalent

130

0D69 0D6A 0D6B 0D6D 0D6F 0D70 0D71 0D74 0D75 0D76 0D77 0D78 0D79 0D7B 0D7D 0D7F 0D80 0D81 0D82 0D83 0D84 0D85 0D87 0D88 0D89 0D8A 0D8B 0D8C 0D8E 0D90 0D93 0D95 0D97 0D99 0D9A 0D9B 0D9C 0D9D 0D9E 0DA0 0DA1 0DA4 0DA5 0DA8 0DAB 0DAC 0DAD 0DAF 0DB0 0DB1 0DB2 0DB3 0DB5 0DB7 0DB8 0DB9 0DBA 0DBD 0DC0 0DC1

71 E5 D608 380E E1 E5 110008 4E 73 59 2B 15 20F9 18EE C609 57 AF E1 15 C8 E5 1E08 7E 1F 77 2B 1D 20F9 18F0 212341 1601 18ED 0E08 7E 17 77 23 0D 20F9 C9 CD5509 C8 CD0A09 CD390E 71 13 0607 1A 13 B7 D5 2817 0E08 C5 1F 47 DC330D CD900D 78 C1

LD PUSH SUB JR POP PUSH LD LD LD LD DEC DEC JR JR ADD LD XOR POP DEC RET PUSH LD LD RRA LD DEC DEC JR JR LD LD JR LD LD RLA LD INC DEC JR RET CALL RET CALL CALL LD INC LD LD INC OR PUSH JR LD PUSH RRA LD CALL CALL LD POP

(HL),C HL 08H C,0D7DH HL HL DE,0800H C,(HL) (HL),E E,C HL D NZ,0D74H 0D6BH A,09H D,A A HL D Z HL E,08H A,(HL) (HL),A HL E NZ,0D87H 0D80H HL,4123H D,01H 0D84H C,08H A,(HL) (HL),A HL C NZ,0D99H 0955H Z 090AH 0E39H (HL),C DE B,07H A,(DE) DE A DE Z,0DCCH C,08H BC B,A C,0D33H 0D90H A,B BC

--- Save MSB see note--> --- Save starting addr of value starting --- with MSB. Is shift count => 8 --- No, go to bit shift routine --- Restore HL to start of array --- Save start of array --- D = count of bytes to move (shift right 1 byte) <----: Now, right shift array one byte, zero filling : on the left. C = byte being shifted : E = previous byte shifted out (initially zero). : Decrement addr : Decrement count ---->: Loop till 7 bytes shifted --- Loop till shift count < 8 --- Continuation of unpacking routine above cont--> * --- D = number of positions to shift right --- Zero A --- HL = addr of MSB --- Count no. of places shifted --- Exit from unpacking routine if done shifting --- Save addr of MSB --- No. of bytes to shift --- Get a byte, shift it right. Bit 0 to CARRY will --- become bit 7 of following byte --- Restore shifted byte --- Bump to next byte --- Shifted all bytes --- No, loop --- Yes, go test if shifted the correct no. of places --- Addr of exponent *********************** cont--> * --- Number of bits to right shift --- Jump to shift routine. Rtn to caller at D83 --- No. of bytes to shift left ************* cont--> * --- Fetch a LSB --- Shift left 1 so bit 7 goes to CARRY --- And CARRY goes to bit 0. --- Restore shifted value. --- Bump to next most LSB. Count a byte shifted --- Jump if 8 bytes not shifted --- Else rtn --- Double precision multiplication ******** cont--> * --- Exit if value zero --- Adjust exponent. New exponent to 4124. --- Move current value to 414A - 4150 cont---> --- Zero 411C --- DE = 414A = start addr of moved SP value --- B = count of bytes to add --- Fetch a byte - starting at LSB --- Position to next byte --- Test current byte for zero --- Save current byte address : 1 byte position --- If current byte zero, shift entire value right --- No of times to right shift a byte --- Save count of bytes processed, initially B=7,C=8 --- Right shift LSB so we --- can test if current bit 0 is a one, if so --- add two unpacked SP numbers. cont---> --- Right shift sum 1 place. --- Restore shifted LSB so we can test --- rest of bits, then load number of bits

131

0D69

: : : :

Unpack a DP number addr of value (starting with MSB) in HL. C = MSB, A-reg = no. of bits to right shift. Value is right shifted. Shift is byte at a time until shift count < 0 then it becomes bit at a time.

0D7D

* Bit shift portion of right just. for DP value ***************

0D90

* Right shift a DP number pointed to by HL one bit. ***********

0D97

* Left shift a DP number pointed to by HL left one bit.********

0DA1

* Uses repetitive addition. Test exponent of current value. **

0DA8

: (Temp storage), zero current value

0DBA

: Add current value to saved value. Sum left in current value

132

0DC2 0DC3 0DC5 0DC6 0DC7 0DC9 0DCC 0DCF 0DD2 0DD4 0DD5 0DD6 0DD7 0DD8 0DD9 0DDA 0DDC 0DDF 0DE2 0DE5 0DE8 0DE9 0DEC 0DEF 0DF0 0DF1 0DF4 0DF7 0DF8 0DF9 0DFC 0DFF 0E02 0E03 0E04 0E05 0E07 0E0A 0E0D 0E10 0E11 0E14 0E17 0E18 0E19 0E1A 0E1D 0E1E 0E21 0E23 0E26 0E29 0E2C 0E2D 0E2E 0E30 0E33 0E34 0E36 0E39

0D 20F2 D1 05 20E6 C3D80C 212341 CD700D 18F1 00 00 00 00 00 00 2084 11D40D 212741 CDD309 3A2E41 B7 CA9A19 CD0709 34 34 CD390E 215141 71 41 114A41 212741 CD4B0D 1A 99 3F 380B 114A41 212741 CD390D AF DA1204 3A2341 3C 3D 1F FA110D 17 211D41 0E07 CD990D 214A41 CD970D 78 B7 20C9 212441 35 20C3 C3B207 79

DEC JR POP DEC JR JP LD CALL JR NOP NOP NOP NOP NOP NOP JR LD LD CALL LD OR JP CALL INC INC CALL LD LD LD LD LD CALL LD SBC CCF JR LD LD CALL XOR JP LD INC DEC RRA JP RLA LD LD CALL LD CALL LD OR JR LD DEC JR JP LD

C NZ,0DB7H DE B NZ,0DAFH 0CD8H HL,4123H 0D70H 0DC5H

NZ,0D60H DE,0DD4H HL,4127H 09D3H A,(412EH) A Z,199AH 0907H (HL) (HL) 0E39H HL,4151H (HL),C B,C DE,414AH HL,4127H 0D4BH A,(DE) A,C C,0E12H DE,414AH HL,4127H 0D39H A C,0412H A,(4123H) A A M,0D11H HL,411DH C,07H 0D99H HL,414AH 0D97H A,B A NZ,0DF9H HL,4124H (HL) NZ,0DF9H 07B2H A,C

--- to test. Count 1 bit tested --- Loop till all bits in current byte tested --- then load addr of next byte to test --- Have all bytes been right justified --- No, loop --- Yes, normalized result and rtn to caller --- HL = addr of WRA1. A = 0 --- Right shift WRA1 one byte --- Then continue with shift/add loop --- Double precision 10 ****************************** --------------- Addr of double precision 10 --- Destination address --- Move a DP 10 to WRA2 --- *********** Double precision division ** cont--> * --- Prepare test for zero exponent --- /0 error if Z (division by zero) --- Compute new exponent. Set WRA1 negative --- Restore exponent of --- WRA1 to original value --- Move WRA1 value to 414A - 4150 (dividend) --- HL = addr of exponent of moved value --- Zero exponent --- Zero B-reg <---: Addr of LSB of moved WRA1 (dividend) : Addr of LSB of WRA2 (divisor) : Subtract divisor from dividend : Difference moved to 414A-4151 : If value in WRA2 was > 414A-4151 : Decrease MSB of 414A-4151 value : Jmp if divisor greater than dividend cont--> : DE = addr of moved WRA1 value (dividend) : HL = addr of WRA2 (divisor) : Add them together, sum to 414A : Clear all status flags so we don't exit : E12: LD (DE),A Save new exponent (dividend) : E13: INC B Signal 1 subtraction : Then load EBB : for dividend. : CARRY into sign pos. : Done. Go normalize result : Restore CARRY flag : HL = addr of original dividend : No. of bytes to shift : Shift entire dividend left one bit : HL = addr of moved divisor : Shift the moved dividend left one cont--> : Get subtraction count : Set status flags --->: Jmp if divisor < dividend : Else divisor > dividend. Divide divisor : by 2 by decrementing exponent --->: Then repeat subtraction. If divisor goes to --- Zero we have an OV error --- Restore MSB of WRA2 value. We need the C-register!

133

0DD4

* *************************************************************

0DE5

* Get exponent of divisor ************************************* : Divide WRA1 by WRA2 uses subtraction/shift method

0E05

: else, add difference back to moved current value

0E29

: bit left so they are in synch

0E39

* *************************************************************

134

0E3A 0E3D 0E3E 0E41 0E44 0E45 0E46 0E47 0E48 0E49 0E4A 0E4C 0E4D 0E50 0E51 0E52 0E53 0E54 0E55 0E57 0E5A 0E5B 0E5C 0E5F 0E60 0E61 0E62 0E65 0E68 0E6B 0E6D 0E6E 0E71 0E72 0E73 0E76 0E77 0E78 0E7A 0E7B 0E7E 0E80 0E82 0E83 0E84 0E87 0E89 0E8C 0E8E 0E90 0E92 0E95 0E97 0E9A 0E9C 0E9F 0EA1 0EA3 0EA4 0EA7

322D41 2B 115041 010007 7E 12 71 1B 2B 05 20F8 C9 CDFC09 EB 2B 7E B7 C8 C602 DAB207 77 E5 CD770C E1 34 C0 C3B207 CD7807 CDEC0A F6AF EB 01FF00 60 68 CC9A0A EB 7E FE2D F5 CA830E FE2B 2801 2B D7 DA290F FE2E CAE40E FE45 2814 FE25 CAEE0E FE23 CAF50E FE21 CAF60E FE44 2024 B7 CDFB0E E5

LD DEC LD LD LD LD LD DEC DEC DEC JR RET CALL EX DEC LD OR RET ADD JP LD PUSH CALL POP INC RET JP CALL CALL OR EX LD LD LD CALL EX LD CP PUSH JP CP JR DEC RST JP CP JP CP JR CP JP CP JP CP JP CP JR OR CALL PUSH

(412DH),A HL DE,4150H BC,0700H A,(HL) (DE),A (HL),C DE HL B NZ,0E44H 09FCH DE,HL HL A,(HL) A Z A,02H C,07B2H (HL),A HL 0C77H HL (HL) NZ 07B2H 0778H 0AECH 0AFH DE,HL BC,00FFH H,B L,B Z,0A9AH DE,HL A,(HL) 2DH AF Z,0E83H 2BH Z,0E83H HL 10H C,0F29H 2EH Z,0EE4H 45H Z,0EA4H 25H Z,0EEEH 23H Z,0EF5H 21H Z,0EF6H 44H NZ,0EC7H A 0EFBH HL

-------------------------------------------------------------------------------------------------------------------------

Load MSB of WRA2 HL = MSB of current value DE addr of temp storage area for current SP value B=no. of bytes to move. C=value to move to current Get a byte of the current value :value Move it to 4150 - 414A Zero a byte of current value Decrement all addresses. We started at the MSB and must work down towards the LSB. Have we moved 7 bytes No, loop Yes, rtn to caller Move current value ********************* cont--> * HL = end of current value Backup to get exponent Load exponent And test for zero Exit if not a flt. pt. no. or value is zero Adjust exponent for following addition Error if exponent overflow Save adjusted exponent and addr of exponent of saved value Add current to saved value see note--> Restore addr of exponent Adjust it and rtn if no overflow OV error if exponent is zero Zero exponent of SP value ** ASCII TO BINARY ** ** Flag as DP E6C: XOR A Save HL (current input symbol) Initialize HL=00, B=0, C=-0 Zero H and L Flag as integer. Zero accumulator Restore addr of current input symbol to HL, DE=00 Fetch 1st char of digit Test for minus sign Save MSD as sign Jump if minus sign (bump to next char) Test for + Jump if plus sign (bump to next char) Compensate for increment at RST 10 Re-examine current character Jump if character is numeric Test for decimal point Jump if decimal point Test for E Jump if E exponential type SP Test for % Jump if % force integer Test for # Jump if # force double precision Test for ! Jump if ! force single precision Test for D Jump if not D else exponential type DP If D ret A-reg non-zero for E, status = 0 Convert digit to SP or DP :E or D processing Save HL so it can be used to hold cont-->

135

0E4D * to saved location ******************************************* : This routine multiplies the current DP : value by 2 by adding it to itself. First : current value is moved to saved location : then DP add routine adds current value : to saved value.

0E5C

: (DP result left in current location)

****** *************************************************************

0EA7

: addr which will be pushed onto stack.

136

0EA8 0EAB 0EAC 0EAD 0EAE 0EB0 0EB1 0EB3 0EB4 0EB5 0EB7 0EB8 0EBA 0EBB 0EBC 0EBD 0EBE 0EC1 0EC2 0EC4 0EC5 0EC6 0EC7 0EC8 0EC9 0ECA 0ECD 0ED0 0ED2 0ED3 0ED4 0ED5 0ED8 0ED9 0EDA 0EDB 0EDC 0EDF 0EE0 0EE3 0EE4 0EE5 0EE6 0EE8 0EEB 0EEE 0EEF 0EF2 0EF3 0EF5 0EF6 0EF9 0EFB 0EFC 0EFD 0EFE 0EFF 0F02 0F03 0F06

21BD0E E3 D7 15 FECE C8 FE2D C8 14 FECD C8 FE2B C8 2B F1 D7 DA940F 14 2003 AF 93 5F E5 7B 90 F40A0F FC180F 20F8 E1 F1 E5 CC7B09 E1 E7 E8 E5 219008 E5 CDA30A C9 E7 0C 20DF DCFB0E C3830E E7 F29719 23 18D2 B7 CDFB0E 18F7 E5 D5 C5 F5 CCB10A F1 C4DB0A C1

LD EX RST DEC CP RET CP RET INC CP RET CP RET DEC POP RST JP INC JR XOR SUB LD PUSH LD SUB CALL CALL JR POP POP PUSH CALL POP RST RET PUSH LD PUSH CALL RET RST INC JR CALL JP RST JP INC JR OR CALL JR PUSH PUSH PUSH PUSH CALL POP CALL POP

HL,0EBDH (SP),HL 10H D 0CEH Z 2DH Z D 0CDH Z 2BH Z HL AF 10H C,0F94H D NZ,0EC7H A E E,A HL A,E B P,0F0AH M,0F18H NZ,0ECAH HL AF HL Z,097BH HL 20H PE HL HL,0890H HL 0AA3H 20H C NZ,0EC7H C,0EFBH 0E83H 20H P,1997H HL 0EC7H A 0EFBH 0EF2H HL DE BC AF Z,0AB1H AF NZ,0ADBH BC

--- Place rtn addr of EBD on stack and --- Restore HL = next input character. Stack = EBD --- Examine next char in input stream. Look for sign --- If any of the following tests are true. D=-1 --- Control goes to EBD. Else we fall into EBD. --- Return if - (minus) token (D = -1) --- Not minus token, test for ASCII minus --- Return if - character (D = -1) --- D = 0 if + sign follows -1 if - sign follows --- Test for plus (+) token --- Return if + token (D = 0) --- Not a + token, test for ASCII plus --- Return if + character (D = 0) --- Backspace input pointer to E or D --- Remove EBD address from stack --- Examine next character in input stream --- Jmp if next character is numeric --- Finalize exponential number ----:D = 0 if - sign --->: Jmp if exponent positive :D = +1 if + sign : Clear A-reg : A = - value off exponent : E = Exponent <---: Save current position in code string --- E = exponent --- B = count of numbers beyond the dec. pt. cont--> <---: Multiply no. by 10 : Divide no. by 10 for each mult. and cont--> --->: Loop till value scaled according to number --- Restore addr of next symbol :in A reg --- Get possible sign --- Preserve addr of next symbol --- Value was preceded by a minus sign --- Restore code string addr --- Determine type of data conversion --- Return if not single precision --- Save code string addr --- Return addr --- Save on stack --- Make sure value is not exactly -2**16. cont--> --- Goto 0890 --- Determine data type ****************************** --- C = 0 --- Fall thru if integer followed by ., or cont--> --- If not DP convert to single precision --- Go get next digit --- Determine data type ******************** cont--> * --- SN error if P (not an integer) --- Bump to next element in code string --- Go finalize number and return --- Force A-reg non-zero ******** # found ! found ** --- Convert value to SP or DP --- Rtn to caller --- Save current position in input string ************ --- Save integer part of number in input string --- BC = 00 00 --- Save flags indicating data type, A = lng --- Convert current value to single precision --- Restore flags --- Convert current value to double precision --- Restore B = 00/00

137

0EC9 0ECD

: A-reg = no. off times to divide/multiply : addition at 0F6B - 0F6F. A reg automatically : bumped by 0F18

0EE0 0EE4 0EE6

: If so Set type to integer. Value to 8000 * ************************************************************* : dec. pt. first char.

0EEE

* % found - finalize value and exit ***************************

0EF5

* *************************************************************

0EFB

* *************************************************************

138

0F07 0F08 0F09 0F0A 0F0B 0F0C 0F0D 0F0E 0F11 0F12 0F15 0F16 0F17 0F18 0F19 0F1A 0F1B 0F1C 0F1D 0F20 0F21 0F24 0F25 0F26 0F27 0F28 0F29 0F2A 0F2B 0F2C 0F2D 0F2E 0F2F 0F30 0F32 0F33 0F34 0F37 0F3A 0F3D 0F3E 0F40 0F41 0F42 0F43 0F44 0F45 0F46 0F47 0F48 0F49 0F4A 0F4B 0F4E 0F51 0F52 0F53 0F54 0F57 0F58

D1 E1 C9 C8 F5 E7 F5 E43E09 F1 EC4D0E F1 3D C9 D5 E5 F5 E7 F5 E49708 F1 ECDC0D F1 E1 D1 3C C9 D5 78 89 47 C5 E5 7E D630 F5 E7 F25D0F 2A2141 11CD0C DF 3019 54 5D 29 29 19 29 F1 4F 09 7C B7 FA570F 222141 E1 C1 D1 C3830E 79 F5

POP POP RET RET PUSH RST PUSH CALL POP CALL POP DEC RET PUSH PUSH PUSH RST PUSH CALL POP CALL POP POP POP INC RET PUSH LD ADC LD PUSH PUSH LD SUB PUSH RST JP LD LD RST JR LD LD ADD ADD ADD ADD POP LD ADD LD OR JP LD POP POP POP JP LD PUSH

DE HL Z AF 20H AF PO,093EH AF PE,0E4DH AF A DE HL AF 20H AF PO,0897H AF PE,0DDCH AF HL DE A DE A,B A,C B,A BC HL A,(HL) 30H AF 20H P,0F5DH HL,(4121H) DE,0CCDH 18H NC,0F59H D,H E,L HL,HL HL,HL HL,DE HL,HL AF C,A HL,BC A,H A M,0F57H (4121H),HL HL BC DE 0E83H A,C AF

-------------------------------------------------------------------------------------------------------------------------

Restore integer part of number Restore current position in input string Return Multiply a SP or DP number by 10 ******* cont--> * Save caller's AF Determine data type Save data type Single: multiply current value by 10 Reload data type Double: multiply current value by 10 Restore caller's AF and decrement count of times multiplied Rtn to caller Divide current SP or DP value by 10 ************* Save caller's registers DE / HL / AF Determine data type A = type Divide current value by 10 Reload type so we'll skip other call Double: divide current value by 10 Restore users registers AF / HL and DE then increment Count of times divided Rtn to caller DE = 00 00 *************************************** B = 00 CARRY is always set when entered, see note--> B = 0 for integer conversion. Count of cont--> Save 0 or count Save position in input string Ref etch current character A= 0 - 9 Save binary value for current digit Determine data type we're converting to Jump if not an integer. A = current digit ASCII to integer conversion DE = 3277 Compare current value to 3277 Jump, value >= 3277 DE = current value Multiply by 10 * 2 * 4 * 5 * 10 Reload current digit Binary value of current digit Add units digit Now test sign of value thus far Ret status flags Jump if value exceeds 2 ** 15 Save binary value Restore HL, BC, and DE B= count of digits after dec. pt. cont--> Possible sign flags Get next digit A = current digit Save so it can be converted to SP then cont-->

139

0F0A

* Exit if integer *********************************************

0F18

* ************************************************************

0F29 0F2B 0F2C

* ************************************************************ : C = 00 for SP, = FF for integer : integers for SP conversion after decimal point

0F52

: C=FF until a dec. pt. encountered

0F58

: added to current value after current value is converted to SP

140

0F59 0F5C 0F5D 0F5F 0F62 0F65 0F68 0F6B 0F6E 0F6F 0F72 0F74 0F77 0F7A 0F7D 0F7E 0F81 0F84 0F87 0F89 0F8C 0F8F 0F90 0F91 0F94 0F95 0F97 0F99 0F9A 0F9B 0F9C 0F9D 0F9E 0FA0 0FA1 0FA4 0FA7 0FA8 0FAB 0FAE 0FAF 0FB2 0FB3 0FB6 0FB7 0FBA 0FBD 0FBE 0FC1 0FC3 0FC5 0FC7 0FC8 0FCB 0FCC 0FCF 0FD1 0FD2 0FD3 0FD6

CDCC0A 37 3018 017494 110024 CD0C0A F2740F CD3E09 F1 CD890F 18DD CDE30A CD4D0E CDFC09 F1 CD6409 CDE30A CD770C 18C8 CDA409 CD6409 C1 D1 C31607 7B FE0A 3009 07 07 83 07 86 D630 5F FA1E32 C3BD0E E5 212419 CDA728 E1 CD9A0A AF CD3410 B6 CDD90F C3A628 AF CD3410 E608 2802 362B EB CD9409 EB F2D90F 362D C5 E5 CD7B09 E1

CALL SCF JR LD LD CALL JP CALL POP CALL JR CALL CALL CALL POP CALL CALL CALL JR CALL CALL POP POP JP LD CP JR RLCA RLCA ADD RLCA ADD SUB LD JP JP PUSH LD CALL POP CALL XOR CALL OR CALL JP XOR CALL AND JR LD EX CALL EX JP LD PUSH PUSH CALL POP

0ACCH NC,0F77H BC,9474H DE,2400H 0A0CH P,0F74H 093EH AF 0F89H 0F51H 0AE3H 0E4DH 09FCH AF 0964H 0AE3H 0C77H 0F51H 09A4H 0964H BC DE 0716H A,E 0AH NC,0FA2H

A,E A,(HL) 30H E,A M,321EH 0EBDH HL HL,1924H 28A7H HL 0A9AH A 1034H (HL) 0FD9H 28A6H A 1034H 08H Z,0FC7H (HL),2BH DE,HL 0994H DE,HL P,0FD9H (HL),2DH BC HL 097BH HL

--- Convert current value to SP --- So we'll bypass calls to convert to DP --- Jump if double --- ASCII to SP Load a SP 16X10E6 into BC/DE --- 16X10E6 to current SP no. in (4121 - 4124) --- Compare --- Jmp if current value >2E16 go convert to DP --- Multiply current value by 10 cont--> --- A = current digit --- Convert current digit to SP format cont--> --- Go get next digit. Count of digits cont--> --- Initialize DP 411D, 411F. Flag value as DP --- Multiply current SP value by 10 --- Move DP no. in (4121 - 4126) to (4127 - 412E) --- A = binary value for current digit --- Convert current digit to SP --- Initialize DP cells 411D, 411E to zero --- Add current SP digit to current SP value --- Go get next digit --- Save current value (4121-4123) on stk ** note--> * --- Convert value in A-reg to a single prec. value --- Load current SP value into BC/DE --- B = exponent, C = MSB, D = next MSB, C = LSB --- Add value in registers to current cont--> --- A = exponent thus far ************** see note--> * --- Compare with 10 --- If => 10. Force it to a constant 32 --- Then multiply current value by 10 --- *4 --- +1 gives times 5 --- *2 gives times 10 --- Fetch current digit (in ASCII) --- Convert it to its binary equivalent cont--> --- Current digit to E --- 0FA2 = LD E,32 --- Get next digit from input string. Rtn to F94 --- Save code string addr **************************** --- Load addr of IN message --- Output message --- Restore code string addr --- Save value in HL as current value ****** cont--> * --- Signal no editing when converting --- Initialize print buffer --- Set status to NON-ZERO for test at OF E7 --- Convert current value to ASCII --- Output value & rtn to caller --- Clear edit flags ******************* see note--> * --- Output buffer addr to HL. Edit flags to 40D8 --- Test if sign requested in output --->: Jmp if no leading + sign required -- : Plus sign <---: Save addr of output buffer in DE --- Determine sign of current value --- Restore output buffer addr to HL --- Jmp if value is positive --- Minus sign to PBUF --- Save count of #'s before & after decimal point --- Current position in print buffer --- Convert a neg. number to its positive equivalent --- Restore print buffer address

141

0F6B 0F6F 0F72

: We'll divide out multiplication later : & add to number thus far : after dec. pt. in B-reg

0F89

* ***** Converts the 8 bit value in the A-reg to a SP ******* : number and adds it to the current value in WRA1

0F91 0F94

: value (4121 - 4124). Rtn to caller * ***** Accumulate value for exponent in E-reg. Do not ******* : let it exceed 50 (base 10). Called when processing : exponents for E or D type values.

: and add to current value

0F94

* *************************************************************

0FAF

* Set type to integer ********* Convert no. in HL to ASCII **** : and write to video

0FBD

* ***** Convert binary to ASCII. Build print buffer using **** : edit flags in A. On entry : B = count of #'s before : C = count of #'s after

142

0FD7 0FD8 0FD9 0FDA 0FDC 0FDF 0FE0 0FE1 0FE4 0FE7 0FEA 0FEC 0FEF 0FF2 0FF5 0FF8 0FF9 0FFB 0FFE 0FFF 1001 1003 1004 1005 1007 1009 100A 100B 100C 100E 1010 1012 1014 1016 1018 101A 101C 101E 1020 1022 1023 1025 1026 1028 102A 102B 102D 102E 1030 1031 1032 1033 1034 1037 103A 103C 103D 103F 1040 1042

C1 B4 23 3630 3AD840 57 17 3AAF40 DA9A10 CA9210 FE04 D23D10 010000 CD2F13 213041 46 0E20 3AD840 5F E620 2807 78 B9 0E2A 2001 41 71 D7 2814 FE45 2810 FE44 280C FE30 28F0 FE2C 28EC FE2E 2003 2B 3630 7B E610 2803 2B 3624 7B E604 C0 2B 70 C9 32D840 213041 3620 C9 FE05 E5 DE00 17

POP OR INC LD LD LD RLA LD JP JP CP JP LD CALL LD LD LD LD LD AND JR LD CP LD JR LD LD RST JR CP JR CP JR CP JR CP JR CP JR DEC LD LD AND JR DEC LD LD AND RET DEC LD RET LD LD LD RET CP PUSH SBC RLA

BC H HL (HL),30H A,(40D8H) D,A A,(40AFH) C,109AH Z,1092H 04H NC,103DH BC,0000H 132FH HL,4130H B,(HL) C,20H A,(40D8H) E,A 20H Z,100AH A,B C C,2AH NZ,100AH B,C (HL),C 10H Z,1022H 45H Z,1022H 44H Z,1022H 30H Z,100AH 2CH Z,100AH 2EH NZ,1025H HL (HL),30H A,E 10H Z,102DH HL (HL),24H A,E 04H NZ HL (HL),B (40D8H),A HL,4130H (HL),20H 05H HL A,00H

-------------------------------------------------------------------------------------------------------------------------

Restore counter Combine 41 with positive MSB HL = 4131H ASCII zero to next position in print buffer A = edit flags Save edit flags in D Prepare to test bit 2**15 (print using) call A = type/length of current variable Jmp if called from PRINT USING Jmp to exit if edit flag is zero Test data type Jmp if SNG or DOUBLE BC = flag for no commas or dec. pts. Convert integer number to ASCII in work area Start of ASCII buffer :(current value) B = first ASCII character in buffer Blank Get editing parameter word. See if we must test for and identify numbers out of range. Test if leading *'s wanted Do not test for out of range numbers. If first char in PBUF <> blank, cont--> Compare PBUF(1) with blank, if not equal replace PBUF(1) with an *. C = * Number has not overflowed Number has overflowed Replace PBUF(1) with * If no range checks, unconditionally cont--> Jump if binary zero (end of buffer) Test for E Jump if E Test for D : Scan print buffer Jump if D : looking for an E, 0, Test for 0 : ., or end of print Jump if ASCII zero : buffer. Replace zeroes Test for comma : with blanks. Jump if comma Test for decimal point Jump if not decimal point We have a decimal point, end of line or a D or E Backspace to previous byte and replace it with an A = edit flags :ASCII 0 Test for leading $ insertion No Yes, backspace one more byte And insert a $ Re-fetch edit flags Test if sign follows value No, rtn Yes, backspace print buffer Save sign then rtn Save edit flags ********************************** HL = Starting addr of line buffer (PBUF) Blank if first char. in print buffer Rtn to caller Convert SP or DP to ASCII ************** cont--> * Save current position in PBUF A = 4 if SP, A = 8 if DP A = 8 if SP, A = 10 if DP

143

1003

: then number has overflowed

100B

: replace 1st char in buffer with a blank.

1034

* *************************************************************

103D

* Set CARRY if double precision *******************************

144

1043 1044 1045 1048 104B 104C 104F 1050 1051 1053 1054 1055 1057 1059 105A 105B 105E 1060 1063 1066 1067 1068 106A 106C 106E 1071 1072 1074 1075 1076 1078 1079 107A 107B 107C 107E 1081 1083 1084 1085 1087 1088 108A 108C 108E 108F 1090 1091 1092 1093 1095 1096 1099 109A 109B 109C 109E 109F 10A2 10A3

57 14 CD0112 010003 82 FA5710 14 BA 3004 3C 47 3E02 D602 E1 F5 CD9112 3630 CCC909 CDA412 2B 7E FE30 28FA FE2E C4C909 F1 281F F5 E7 3E22 8F 77 23 F1 362B F28510 362D 2F 3C 062F 04 D60A 30FB C63A 23 70 23 77 23 3600 EB 213041 C9 23 C5 FE04 7A D20911 1F DAA311

LD INC CALL LD ADD JP INC CP JR INC LD LD SUB POP PUSH CALL LD CALL CALL DEC LD CP JR CP CALL POP JR PUSH RST LD ADC LD INC POP LD JP LD CPL INC LD INC SUB JR ADD INC LD INC LD INC LD EX LD RET INC PUSH CP LD JP RRA JP

D,A D 1201H BC,0300H A,D M,1057H D D NC,1057H A B,A A,02H 02H HL AF 1291H (HL),30H Z,09C9H 12A4H HL A,(HL) 30H Z,1066H 2EH NZ,09C9H AF Z,1093H AF 20H A,22H A,A (HL),A HL AF (HL),2BH P,1085H (HL),2DH A B,2FH B 0AH NC,1087H A,3AH HL (HL),B HL (HL),A HL (HL),00H DE,HL HL,4130H HL BC 04H A,D NC,1109H C,11A3H

--- D = Adjust type flag --- D = 9 (SP), D = B (DP) --- Scale no. to 99,999 < X < 999,999 --- After scaling, A = count of times DP value scaled --- Up (positive), or down (negative) --->: Jmp if scaled down more than 9 or 11 places -- : D = A (SP) or C (DP) -- : Test if value was not scaled at all --->: Jmp if scaled up or down -- : A = no. of digits in value -- : Save in B -- : Force exponent to zero <---: Compute exponent value --- Restore PBUF addr --- Save exponent --- Initialize commas & dec. pt. routine --- Put an ASCII zero into current pos. in print --- Increment HL if no scaling was done :buffer --- Convert binary to ASCII. Result to PBUF --- Backspace PBUF to previous char see note--> --- Load previous char --- Compare to an ASCII zero --- Loop till a non-zero char. found --- Test for dec. pt. --- Call if not decimal point (increment cont--> --- Restore exponent --- Jump if exponent is zero --- Save exponent --- Test data type --- This will become a D or --- E depending on whether value is SP or DP --- Save exponent designation --- Bump to first pos. of exponent in buffer --- Reload exponent value --- + (exponent) --- Jmp if exponent is positive --- - (exponent) --- Convert negative exponent --- to its positive equivalent --- B = start of ASCII values 0, 1, 2 ..... 9 --- Start of divide by 10 using compound cont--> --- Subtract 10 until --- Remainder < 10. B = quotient --- Convert remainder to an ASCII digit --- Bump to next pos. in PBUF --- 1st digit of exponent --- Bump to next pos. in PBUF --- 2nd digit of exponent --- Bump to next pos. in PBUF --- 00 marks end of ASCII number --- DE = ending addr. of PBUF --- HL = starting addr. of PBUF --- Ret. to caller --- Bump to next location in PBUF ********** cont--> * --- B = count of #'s before. C = count of #'s after --- A = data type. Test for integer/floating point --- A = edit flags --- Jmp if single or double precision --- Position exponential notation flag --- Jmp if current variable is string, else cont-->

145

1066

: Backspace PBUF to first non-zero value

106E

: HL to first char after dec. pt.)

1087

: subtraction loop: : :

Convert value in A-register to a true digit ASCII value. Divide by 10 using compound subtraction

109A

* Edit operations for PRINT USING *****************************

10A3

: must be integer

146

10A6 10A9 10AC 10AD 10AE 10B0 10B3 10B6 10B7 10B8 10BB 10BC 10BF 10C0 10C3 10C4 10C6 10C7 10C8 10CA 10CD 10CE 10D1 10D2 10D3 10D4 10D5 10D7 10D9 10DB 10DD 10DE 10DF 10E0 10E3 10E4 10E5 10E7 10E8 10EA 10EB 10ED 10EE 10EF 10F1 10F3 10F4 10F5 10F7 10F8 10FB 10FC 10FE 10FF 1102 1103 1105 1106 1108 1109

010306 CD8912 D1 7A D605 F46912 CD2F13 7B B7 CC2F09 3D F46912 E5 CDF50F E1 2802 70 23 3600 212F41 23 3AF340 95 92 C8 7E FE20 28F4 FE2A 28F0 2B E5 F5 01DF10 C5 D7 FE2D C8 FE2B C8 FE24 C8 C1 FE30 200F 23 D7 300B 2B 012B77 F1 28FB C1 C3CE10 F1 28FD E1 3625 C9 E5

LD CALL POP LD SUB CALL CALL LD OR CALL DEC CALL PUSH CALL POP JR LD INC LD LD INC LD SUB SUB RET LD CP JR CP JR DEC PUSH PUSH LD PUSH RST CP RET CP RET CP RET POP CP JR INC RST JR DEC LD POP JR POP JP POP JR POP LD RET PUSH

BC,0603H 1289H DE A,D 05H P,1269H 132FH A,E A Z,092FH A P,1269H HL 0FF5H HL Z,10C8H (HL),B HL (HL),00H HL,412FH HL A,(40F3H) L D Z A,(HL) 20H Z,10CDH 2AH Z,10CDH HL HL AF BC,10DFH BC 10H 2DH Z 2BH Z 24H Z BC 30H NZ,1102H HL 10H NC,1102H HL BC,772BH AF Z,10F9H BC 10CEH AF Z,1102H HL (HL),25H HL

--- B = no. of leading digits C = comma cont--> --- Test comma flag. If not set zero C --- D = count of #'s before dec. pt. --- Count to A --- Compare to 5 (max no. digits allowed in integer) --- Fill PBUF with leading zeroes. If cont--> --- Convert current value (integer) to cont--> --- Load count of #'s after dec. pt. into A --- and set status flags --- If no trailing #'s, backspace PBUF --- Test if no count given --- Else add count trailing zeros --- Save current PBUF addr --- Edit ASCII buffer w/ converted number in it --- Restore HL to PBUF addr --->: Jmp if sign follows value -- : No. store a blank after value -- : Bump to next pos. in PBUF <---: Terminate buffer with a byte of zeros --- Start of ASCII print buffer minus 1 --- Bump to next pos. in PBUF note--> --- A = LSB of addr of dec. pt. in PBUF --- Compare to LSB of current PBUF --- Then subtract length of field --- Exit if start of field located --- Not start of field, then fetch char and --- Test for blank --- Loop till start of field or +, -, $ found --- Test for * --- Ignore blanks and --- Backspace to previous char so it can be re-tested --- Save PBUF addr --- Save current char --- Return addr in case of -, +, $ --- to stack --- Re-examine char --- Compare with a --- Exit to 10DF if a minus --- Not - try a + --- Exit to 10DF if a plus --- Not + or -, try $ --- Exit to 10DF if $ --- Clear rtn addr. of 10DF --- Test for ASCII 0 (leading 0) --->: Jump if not leading 0 -- : Skip next char -- : and examine following one -- : Jump if not numeric -- : Backspace to last char examined -- : 10F9: DEC HL :Backspace one more char -- : 10FA: LD (HL),A :Shift digits up 1 pos. -- : Loop till end of field reached -- : Clear stack -- : Restart scan <---: Restore char at start of field --- Loop till beginning of field found --- Restore starting addr of field --- Replace it with a --- Rtn to caller --- Save current PBUF addr. ************ see note--> *

147

10A6

: counter Integer editing for PRINT USING

10B0 10B3

: more than 5 digits : ASCII. Result to PBUF

: : : : : :

Locate start of field in PBUF and rtn to caller. If field starts with a +, -, or $ goto 10DF before returning to caller. Search for field by starting at addr. of dec. pt. and backspacing size of field (D-reg)

1109

* *********** Floating point editing **************************

148

110A 110B 110E 1110 1113 1116 1118 111B 111C 111D 1120 1121 1123 1124 1127 112A 112D 1130 1132 1135 1138 1139 113A 113D 113E 113F 1140 1141 1142 1145 1148 114B 114C 114F 1150 1153 1154 1157 1158 1159 115A 115D 115E 1161 1162 1163 1164 1167 116A 116B 116C 116D 116E 116F 1170 1171 1174 1175 1176 1179

1F DAAA11 2814 118413 CD490A 1610 FA3211 E1 C1 CDBD0F 2B 3625 C9 010EB6 11CA1B CD0C0A F21B11 1606 CD5509 C40112 E1 C1 FA5711 C5 5F 78 92 93 F46912 CD7D12 CDA412 B3 C47712 B3 C49112 D1 C3B610 5F 79 B7 C4160F 83 FA6211 AF C5 F5 FC180F FA6411 C1 7B 90 C1 5F 82 78 FA7F11 92 93 F46912 C5

RRA JP JR LD CALL LD JP POP POP CALL DEC LD RET LD LD CALL JP LD CALL CALL POP POP JP PUSH LD LD SUB SUB CALL CALL CALL OR CALL OR CALL POP JP LD LD OR CALL ADD JP XOR PUSH PUSH CALL JP POP LD SUB POP LD ADD LD JP SUB SUB CALL PUSH

C,11AAH Z,1124H DE,1384H 0A49H D,10H M,1132H HL BC 0FBDH HL (HL),25H BC,0B60EH DE,1BCAH 0A0CH P,111BH D,06H 0955H NZ,1201H HL BC M,1157H BC E,A A,B D E P,1269H 127DH 12A4H E NZ,1277H E NZ,1291H DE 10B6H E,A A,C A NZ,0F16H A,E M,1162H A BC AF M,0F18H M,1164H BC A,E B BC E,A A,D A,B M,117FH D E P,1269H BC

--- Test bit 0 of edit flags see note--> --- Jmp if exponential notation on flt. pt. number --->: Jump if value is SP : DE = addr of DP 1X10**16 : Compare value to 1X10**16 : D = no. of digits in a DP field ----:--:>: Jmp if value < 1X10**16 else <---:--: : Restore current location in print buffer : : : B=count of #'s before, C=count of #'S after : : : Reenter edit routine till value < 1X10**16 : : : Restore buffer addr. current position : : : Store a % (start of spaces field) : : : Rtn to caller <---: : : BC/DE = 1 X 10E16 *********** see note--> : : : : Compare edit value to 1 X 10E16 ------>: : Jmp if edit value > 1X10E16 --: D = no. of digits to print (size of field) <--------: Test sign of current value --- Scale SP value to 99,999<X<999,999 cont--> --- HL = origin of ASCII buffer --- B=count of #'s before, C=count of #'s afterwards --->: Jmp if value was scaled up (multiplied by 10) -- : Save count of #'s before and after dec. pt. -- : E=count of times value was divided -- : B=no. of user specified #'s before note--> -- : D=6 -- : E = no. of times edit value divided by 10 -- : Put leading ASCII zeroes into PBUF -- : Compute count of dec. pts. and commas -- : Convert integer of SP number to ASCII -- : Test count of times value scaled -- : Add trailing zeroes for each time value scaled -- : Set status flag -- : Place decimal point/commas in numeric buffer -- : Restore edit counts -- : Go convert fractional portion of no. to ASCII <---: E=count of times value scaled up (mult. by 10) * -- C=count of digits following dec. pt cont--> --- Test count --- Decrement count of trailing #'s by cont--> --- A=((no. trailing #'s)-1) + cont--> --->: Jmp if value needs to be scaled down -- : Signal no down-scaling <---: Save before & after counters --- Save scale count <---: Divide current value by 10 (A) times --->: After each division, A-reg is incremented --- Original scale count --- A = count of times value multiplied by 10 --- Minus scale value --- Restore before and after dec. pt. counter --- Adjusted scale factor --- Plus size of field (set sign flag) --- A = count of #'s before dec. pt. --- Jmp no leading digits --- Else subtract field size (6 for SP, cont--> --- Then subtract adjusted scale --- Add trailing zeroes --- Save count of #'s before and after dec. pt.

149

For PRINT USING

1124

* ***** Edit SP value or a DP value <1Xl0E16 ****************

1135

: On rtn A = times value scaled up or down as + or -

: : :

Value was scaled down or not scaled at all. Adjust scale for no. of places before dec. Pt.

1157 1158 115A 115D

* ************************************************************* : to print. Value was scaled up. Adjust scale : for no. of places following dec. pt. : one if its non-zero : (-no. of times value scaled up)

1174

: 10 for DP) from adjusted size

150

117A 117D 117F 1182 1183 1186 1187 1188 1189 118A 118D 118E 118F 1190 1193 1194 1195 1197 119A 119B 119C 119F 11A0 11A3 11A4 11A5 11A8 11A9 11AA 11AD 11AF 11B2 11B5 11B6 11B9 11BA 11BB 11BC 11BD 11BE 11BF 11C2 11C3 11C4 11C5 11C7 11C9 11CA 11CB 11CC 11CD 11CE 11CF 11D0 11D3 11D6 11D7 11D8 11D9 11DA

CD7D12 1811 CD6912 79 CD9412 4F AF 92 93 CD6912 C5 47 4F CDA412 C1 B1 2003 2AF340 83 3D F46912 50 C3BF10 E5 D5 CDCC0A D1 AF CAB011 1E10 011E06 CD5509 37 C40112 E1 C1 F5 79 B7 F5 C4160F 80 4F 7A E604 FE01 9F 57 81 4F 93 F5 C5 FC180F FAD011 C1 F1 C5 F5 FADE11

CALL JR CALL LD CALL LD XOR SUB SUB CALL PUSH LD LD CALL POP OR JR LD ADD DEC CALL LD JP PUSH PUSH CALL POP XOR JP LD LD CALL SCF CALL POP POP PUSH LD OR PUSH CALL ADD LD LD AND CP SBC LD ADD LD SUB PUSH PUSH CALL JP POP POP PUSH PUSH JP

127DH 1190H 1269H A,C 1294H C,A A D E 1269H BC B,A C,A 12A4H BC C NZ,119AH HL,(40F3H) A,E A P,1269H D,B 10BFH HL DE 0ACCH DE A Z,11B0H E,10H BC,061EH 0955H NZ,1201H HL BC AF A,C A AF NZ,0F16H A,B C,A A,D 04H 01H A,A D,A A,C C,A E AF BC M,0F18H M,11D0H BC AF BC AF M,11DEH

--- Setup B/C for dec. pt. and comma counters --- Go edit number before dec. pt. --- insert a zero into PBUF ************************** --- Save comma counter Will be wiped by call 1294 --- Add dec. pt. to PBUF gives 0 --- Restore comma counter to C-reg --- Zero to A-reg --- Now, get diff. between requested --- field size and scaled field size --- Then add that many zeroes to PBUF --- Save count or #'s before and after dec. pt. --- Zero B --- Zero C --- Convert integer portion of SP value to integer --- Restore counters :ASCII --- Set status for count of #'s after dec. pt. --- Jmp if digits follow dec. pt. --- Else load addr. of dec. pt. in PBUF --- Gives no. of digits before dec. pt. --- Minus 1 --- Add that many zeros to PBUF --- Set D = no. of #'s before --- Go edit ASCII value --- Save current position in PBUF ******* see note--> * --- Save edit flags --- Convert integer to single precision --- Restore edit flags --- Clear status flags. Force Jmp for SP --- Jmp if single precision SP/DP entry pt. --- E = no. digits to print if DP --- 11B0: LD E,6 E = no. digits to print if SP --- Test sign of current value --- Force Jmp at 11F3 on first pass --- If current value not zero, go scale it --- Restore PBUF addr. --- Restore count of # s before and after --- Decimal point, save flag for test at 11F3 --- A = count of # s after --- Set status so we can test for zero --- Save original trailing digit count --- If trail count non-zero, decrement it --- Combine count of before & after --- Save total digit count --- Load edit flags --- Isolate sign follows value flag --- Gives no CARRY if sign follows --- A = 0 if no sign, FE otherwise --- Save new edit flag --- Adjust count of digits to print if sign follows --- Save adjusted count --- A = number of times to divide by 10 --- Save divisor count --- Save char. count <---: Divide value by 10 (A) times --->: Loop till division completed --- Restore counter of #'s --- Restore division count --- Then resave --- Registers and --- Jmp if any trailing zeros

151

117F

: ************************************************************

11A3

* Exponential formatting for PRINT USING ********************** : 11A3 - Entry pt. INTEGER : 11AA - Entry pt. SP/DP

152

11DD 11DE 11DF 11E0 11E1 11E2 11E3 11E4 11E6 11E9 11EA 11ED 11EE 11EF 11F2 11F3 11F5 11F6 11F7 11F8 11F9 11FC 11FD 11FE 1201 1202 1203 1204 1205 1208 120B 120D 1210 1213 1216 1219 121C 121D 121F 1220 1222 1225 1226 1229 122C 122F 1232 1234 1237 123A 123D 123E 1241 1242 1244 1245 1248 1249 124C 124D

AF 2F 3C 80 3C 82 47 0E00 CDA412 F1 F47112 C1 F1 CC2F09 F1 3803 83 90 92 C5 CD7410 EB D1 C3BF10 D5 AF F5 E7 E22212 3A2441 FE91 D22212 116413 212741 CDD309 CDA10D F1 D60A F5 18E6 CD4F12 E7 EA3412 014391 11F94F CD0C0A 1806 116C13 CD490A F24C12 F1 CD0B0F F5 18E1 F1 CD180F F5 CD4F12 F1 D1

XOR CPL INC ADD INC ADD LD LD CALL POP CALL POP POP CALL POP JR ADD SUB SUB PUSH CALL EX POP JP PUSH XOR PUSH RST JP LD CP JP LD LD CALL CALL POP SUB PUSH JR CALL RST JP LD LD CALL JR LD CALL JP POP CALL PUSH JR POP CALL PUSH CALL POP POP

A A A,B A A,D B,A C,00H 12A4H AF P,1271H BC AF Z,092FH AF C,11F8H A,E B D BC 1074H DE,HL DE 10BFH DE A AF 20H PO,1222H A,(4124H) 91H NC,1222H DE,1364H HL,4127H 09D3H 0DA1H AF 0AH AF 1208H 124FH 20H NC,1234H BC,9143H DE,4FF9H 0A0CH 1239H DE,136CH 0A49H P,124CH AF 0F0BH AF 1226H AF 0F18H AF 124FH AF DE

--- Clear A, status flags --- Make trailing zero count positive --- 2's complement --- Add size of field before dec. pt. --- Plus one more --- Add size of field (6/SP, 10/DP) --- B = number of digits before dec. pt. --- Signal no commas --- Convert value to ASCII --- Restore original count of #'s before --- Add trailing zeros --- Restore counts of nos. before and after dec. pt. --- Get count of nos. before dec. pt. --- None before, backspace PBUF addr 1 byte --- Get first time flag. If set, clear stack, --- Add exponent, and join common edit code. --- Otherwise, add default field size to + 1 if pos. --- Or a - 1 if neg.. Then subtract actual --- Number of chars in field to get size of exponent --- Save BC --- Compute and add exponent to PBUF --- Restore HL --- Clear stack --- Go edit ASCII value --- Test magnitude of SP and DP numbers **** cont--> * --- Zero A and flags, save zero --- On stack see note--> --- Test data type --- Jump if single --- Must be double, get the exponent into A --- Compute no. of bits in integer portion of number --- Jmp if 17 or more bits in integer portion of --- DE=addr of DP 5.5X10E2 :DP value --- Destination addr --- Move 5.5X10E8 to saved value location --- Multiply 5.5X10E8 times current value --- A = count of times DP value multiplied to scale --- A = count - 10 :it up --- Save for testing -- Loop till integer portion exceeds 2E16 --- Compare current value to 999,999, ****** cont--> * <------: Test data type : Jump if not single : BC/DE = SP 99,999 decimal : : Compare current value to 99,999 --->: : Go test results of comparison : : DE addr of SP 1.44X10E17 : : Compare current value to 1.44X10E17 <---:--:-->: Jmp if value > 99,999 see note--> : : : A = scaled counter : : : Multiply current value by 10 : : : A = - no. of times value multiplied ------>: : Loop till between 999,999 and 99,999 --: A = scaled count --: Divide value by 10. It's > 999,999 --: Keep count of times divided --: Loop till value < 999,999 <----------: A = + times divided : - times multiplied --- Restore callers DE

153

1201

* Clear times value scaled ************************************ : : : : Scale a single or double precision number so it lies between 99,999 and 999,999. On exit A = +(times value divided), or -(times multiplied).

1222

* Rtn in line if value smaller ******************************** : Scale SP and DP numbers so that 99,999<SP<999,999

123A

: (more than 5 digits in integer or less than 17 digits in DP)

154

124E 124F 1250 1253 1256 1259 125C 125E 1261 1264 1265 1268 1269 126A 126B 126C 126E 126F 1271 1273 1274 1277 1279 127A 127B 127D 127E 127F 1280 1281 1282 1284 1286 1288 1289 128C 128E 128F 1290 1291 1292 1294 1296 1299 129A 129B 129C 129D 129E 12A0 12A1 12A3 12A4 12A5 12A6 12A9 12AA 12AB 12AE 12B1

C9 E7 EA5E12 017494 11F823 CD0C0A 1806 117413 CD490A E1 F24312 E9 B7 C8 3D 3630 23 18F9 2004 C8 CD9112 3630 23 3D 18F6 7B 82 3C 47 3C D603 30FC C605 4F 3AD840 E640 C0 4F C9 05 2008 362E 22F340 23 48 C9 0D C0 362C 23 0E03 C9 D5 E7 E2EA12 C5 E5 CDFC09 217C13 CDF709

RET RST JP LD LD CALL JR LD CALL POP JP JP OR RET DEC LD INC JR JR RET CALL LD INC DEC JR LD ADD INC LD INC SUB JR ADD LD LD AND RET LD RET DEC JR LD LD INC LD RET DEC RET LD INC LD RET PUSH RST JP PUSH PUSH CALL LD CALL

20H PE,125EH BC,9474H DE,23F8H 0A0CH 1264H DE,1374H 0A49H HL P,1243H (HL) A Z A (HL),30H HL 126AH NZ,1277H Z 1291H (HL),30H HL A 1273H A,E A,D A B,A A 03H NC,1282H A,05H C,A A,(40D8H) 40H NZ C,A B NZ,129CH (HL),2EH (40F3H),HL HL C,B C NZ (HL),2CH HL C,03H DE 20H PO,12EAH BC HL 09FCH HL,137CH 09F7H

--- Rtn to caller --- Test data type *********************************** --- Jump if double precision --- BC/DE = 999,999 decimal ----- Compare current value to 999,999 decimal --- Test result of comparison --- DE = address ************************************* --- Compare current value --- Clear rtn addr so we can go to 1244 --- Jmp if current value has more than 6 digits in --- Else rtn to caller :integer --- Test zero flag ********************* see note--> * <---: in HL. : Count 1 ASCII zero moved to print buffer : Move an ASCII zero : Bump destination address --->: Loop till 'A' ASCII zeroes moved --- If not done adding trailing zeroes else exit **** --- Rtn to caller if trailing zeros added --- Decimal point/commas in numeric buffer --- Add a trailing ASCII zero to print buffer --- Bump print buffer add --- Count of trailing zeroes to add --- Go test for completion --- A = count of times value scaled up or down ******* --- D = no. of digits to print --- Plus 1 gives no. of digits before dec. pt. --- B = leading digit count --- Gives leading digits +2 note--> --- Divide modulo 3 <---: Loop till A = -1, -2, or -3 --->: Add 5 (get positive remainder) gives 4, 3, or 2 --- C = comma counter --- A = edit flags. Test for comma flag --- Isolate comma bit in edit flag word --- Exit with C = comma count if commas requested --- Else force comma count to zero --- Rtn to caller --- Count 1 leading digit **************************** --->: Jmp if all leading digits not stored cont--> -- : Leading digit stored. Add decimal pt. -- : Save addr of dec. pt. in buffer -- : Bump to first char of fractional part of number -- : Set C and B to zero to inhibit any more dec. pts. -- : and commas. Rtn to caller <---: Count one char stored ************************** --- Rtn if not end of 3 character group --- ',' every third digit --- Bump to next position in buffer --- Reset comma counter --- Rtn to caller --- Save edit flags ********************************** --- Test data type --- Jump if single precision see note--> --- Save leading digit count/comma counter --- Save buffer addr --- Move WRA1 to WRA2 --- HL = address of DP .5 --- Move to WRA1

155

124F

* *************************************************************

125E

* *************************************************************

1269

* Move 'A' ASCII zeroes to a print buffer. Address of buffer

1271

* *************************************************************

127D

* ************************************************************* : Compute the number of digits before the decimal : point, and the number of commas to be included : in first part of number. On entry D = size of : field (6 or 10), E = scale count. On exit B = : number of digits before dec. pt., C = number of : commas to include in first part of number.

1291 1292

* ************************************************************* : in PBUF Count leading digits before dec. pt.

129C

* *************************************************************

12A4

* ************************************************************* : Convert a DP value to its ASCII equivalent in integer : portion only

156

12B4 12B7 12B8 12BB 12BC 12BD 12C0 12C2 12C5 12C6 12C7 12C8 12C9 12CB 12CC 12CD 12CE 12D1 12D3 12D4 12D7 12D8 12D9 12DA 12DB 12DC 12DD 12DE 12E0 12E1 12E2 12E5 12E8 12EA 12EB 12EC 12EF 12F0 12F3 12F6 12F7 12F8 12F9 12FC 12FD 1300 1301 1302 1303 1304 1307 1308 130A 130B 130C 130D 130E 130F 1310 1311

CD770C AF CD7B0B E1 C1 118C13 3E0A CD9112 C5 F5 E5 D5 062F 04 E1 E5 CD480D 30F8 E1 CD360D EB E1 70 23 F1 C1 3D 20E2 C5 E5 211D41 CDB109 180C C5 E5 CD0807 3C CDFB0A CDB409 E1 C1 AF 11D213 3F CD9112 C5 F5 E5 D5 CDBF09 E1 062F 04 7B 96 5F 23 7A 9E 57

CALL XOR CALL POP POP LD LD CALL PUSH PUSH PUSH PUSH LD INC POP PUSH CALL JR POP CALL EX POP LD INC POP POP DEC JR PUSH PUSH LD CALL JR PUSH PUSH CALL INC CALL CALL POP POP XOR LD CCF CALL PUSH PUSH PUSH PUSH CALL POP LD INC LD SUB LD INC LD SBC LD

0C77H A 0B7BH HL BC DE,138CH A,0AH 1291H BC AF HL DE B,2FH B HL HL 0D48H NC,12CBH HL 0D36H DE,HL HL (HL),B HL AF BC A NZ,12C2H BC HL HL,411DH 09B1H 12F6H BC HL 0708H A 0AFBH 09B4H HL BC A DE,13D2H 1291H BC AF HL DE 09BFH HL B,2FH B A,E (HL) E,A HL A,D A,(HL) D,A

--- Add .5 to value in WRA2. Result to WRA1 --- Clear status flags --- Unpack DP value in WRA1. Save in current area. --- Restore buffer addr --- and counters --- DE=table of powers of 10 from 1.0X10E15 - 1.0X10E6 --- A=no. of times to dvd current val by a power of 10 <-----: Go add a dec point or a comma to buffer -: Save count of digits before & after dec point -: Save division count : Save current buffer addr : Addr of power table to stack : B = quotient in ASCII for each division <---: : B start at 30 (ASCII zero) : : HL = addr of power table = divisor : : Save it so it can be restored during loop : : Dvd current value (integer) by cont--> --->: : Loop till reminder < current power : Restore starting addr of current power of 10 : Add current power to remainder - make it pos : Save current power addr in DE : HL = current print buffer addr : Digit to buffer : Bump to next print position : Restore status flags so we can test cont--> : Restore counts : Count 1 time thru loop ----->: Done 10 times , no loop --- Restore counts --- and current buffer addr --- then move last half of DP value --- into WRA1 as a SP value --- and convert it to ASCII --- Convert a SP value to its integer ****** cont--> * --- Save counts & buffer addr --- Add a .5 to current value. Result left in BC/DE --- Bump MSB --- Convert a + SP number to integer. Result in BC/DE --- Move SP value in BC/DE to current value. Integer --- portion of original SP value. Restore HL --- Restore buffer addr --- Restore counts --- DE = addr of integer equivalent of 100,000 --- CARRY=first time switch for division loop 12FC--- Decimal point/commas to numeric buffer :1327 --- Save counts --- Save CARRY flag for count of times thru loop --- Save buffer addr --- Save division table addr --- Load current SP value into BC/DE --- HL = addr of integer value of 100,000 --- B = ASCII (30-1) = (0-1 --- Gives 30,31,...... which equal ASCII 0,1,2,... --- Least Sig byte of integer equivalent --- Minus least Sig. byte of 100,000 --- Restore difference for next subtraction --- Bump to next byte of 100,000 --- Middle byte of integer equivalent see note--> --- Minus middle byte of 100,000 --- Restore diff. for next subtraction

157

12CE

: a power of 10 starting at 10E15 and working down to 10E6

12DB

: for 10 times thru

12EA

* equivalent. Divide integer equivalent by 100,000 and ******* : 10,000. Use code at 1335 to convert last 1000 to ASCII

: This code divides the integer portion of the current value : by 100,000 using compound subtraction. A quotient is kept : in the B-reg as an ASCII value

158

1312 1313 1314 1315 1316 1317 1318 131A 131D 131E 1321 1322 1323 1324 1325 1326 1327 1329 132A 132B 132D 132F 1330 1333 1335 1338 1339 133A 133B 133C 133D 133E 133F 1340 1341 1342 1343 1346 1348 1349 134A 134B 134C 134D 134E 134F 1351 1352 1355 1356 1357 1358 1359 135A 135B 135C 135E 1361 1362 1363

23 79 9E 4F 2B 2B 30F0 CDB707 23 CDB409 EB E1 70 23 F1 C1 38D3 13 13 3E04 1806 D5 11D813 3E05 CD9112 C5 F5 E5 EB 4E 23 46 C5 23 E3 EB 2A2141 062F 04 7D 93 6F 7C 9A 67 30F7 19 222141 D1 E1 70 23 F1 C1 3D 20D7 CD9112 77 D1 C9

INC LD SBC LD DEC DEC JR CALL INC CALL EX POP LD INC POP POP JR INC INC LD JR PUSH LD LD CALL PUSH PUSH PUSH EX LD INC LD PUSH INC EX EX LD LD INC LD SUB LD LD SBC LD JR ADD LD POP POP LD INC POP POP DEC JR CALL LD POP RET

HL A,C A,(HL) C,A HL HL NC,130AH 07B7H HL 09B4H DE,HL HL (HL),B HL AF BC C,12FCH DE DE A,04H 1335H DE DE,13D8H A,05H 1291H BC AF HL DE,HL C,(HL) HL B,(HL) BC HL (SP),HL DE,HL HL,(4121H) B,2FH B A,L E L,A A,H A,D H,A NC,1348H HL,DE (4121H),HL DE HL (HL),B HL AF BC A NZ,1335H 1291H (HL),A DE

--- Bump to most sig. byte of 100,000 --- Most sig. byte of integer equivalent --- Minus most sig. byte of 100,000 --- Restore for next subtraction --- Reset HL to least --- Sig byte of 100,000 constant --- Loop till integer equivalent < 100,000 --- Add 100,000 to value in C/DE, make remainder pos --- Bump HL to addr of 10,000 constant --- Save remainder as current value --- Addr of constant 10,000 to DE --- HL = current PBUF addr --- Save ASCII quotient --- Bump to next position in print buffer --- Restore CARRY flag (switch) --- Restore BC so it can be saved later --- If CARRY set, reset it and divide cont--> --- When we fall thru we have divided cont--> --- Bump DE to point to constant 1000 --- A = no. of digits --- Go convert remainder to 4 ASCII digits --- Convert integer to ASCII *********** see note--> * --- DE = table of descending powers of 10 cont--> --- A = no. of ASCII digits to build --- Add decimal point or commas to buffer --- Save counts --- Save number of digits counter --- Save buffer addr --- HL = addr of power table --- Load a power of 10 in BC --- Bump to MSB or power --- Load MSB or power --- Save power --- Bump to next value in power table --- HL=value just loaded, addr of next value to stack -- DE = value loaded - division --- HL = current value (integer) <--: Divide current value by a power of 10 starting at : 10,000 dec. and working down to 10. Remainder : from each division is added to the division and : the sum becomes the dividend for the next : division etc. Division is by compound subtraction : Quotient +2F(hex) = ASCII equivalent of quotient. : B - reg = quotient. : HL = next dividend -->: Loop till quotient (HL) less than current power --- Remainder + divisor = dividend :of 10 --- Save next dividend --- DE = addr of next power of 10 --- Restore addr of output buffer --- ASCII digit to buffer --- Next loc. in print buffer --- A = count of digits to convert --- Restore counter of #'s before & after dec point --- Have we got 5 digits yet --- no, loop --- Decimal point/commas to numeric buffer --- Zero terminator PBUF --- Restore callers DE --- Rtn to caller ************************************

159

1327 1329

: remainder by 10,000 : integer part of SP value by 100,000 and 10,000. The : remainder is positive and has been saved as current value.

132F 1330

* Save edit flags ********************************************* : starting at 10,000 dec.

1363

* *************************************************************

160

1364 1365 1366 1367 1368 1369 136A 136B 136C 136E 136F 1372 1373 1374 1376 1377 1378 1379 137A 137C 137D 137E 137F 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 138A 138C 138D 138E 1390 1391 1392 1393 1394 1395 1396 1398 1399 139A 139B 139C 139D 139E 13A0 13A1 13A2 13A4 13A7 13A8 13A9 13AA 13AB

00 00 00 00 F9 02 15 A2 FDFF 9F 31A95F 63 B2 FEFF 03 BF C9 1B 0EB6 00 00 00 00 00 00 00 80 00 00 04 BF C9 1B 0EB6 00 80 C6A4 7E 8D 03 00 40 7A 10F3 5A 00 00 A0 72 4E 1809 00 00 10A5 D4E800 00 00 E8 76 48

NOP NOP NOP NOP LD LD DEC AND INDEX SBC LD LD OR CP INC CP RET DEC LD NOP NOP NOP NOP NOP NOP NOP ADD NOP NOP INC CP RET DEC LD NOP ADD ADD LD ADC INC NOP LD LD DJNZ LD NOP NOP AND LD LD JR NOP NOP DJNZ CALL NOP NOP RET HALT LD

-------------------------------------------------------------------------------------------------------------------------

1364 = 10 X 10E9 DP

136C = 1 X 10E15 DP

1374 - 137A = 1 X 10E16 DP

137C - 1383 = .5 (double)

1380 - 1383 = .5 (single)

1384 - 138B = 1 X 10E16 (double)

138A - 1380 = .502778 (single) 138C - 1392 = 1 X 100E15 (integer portion of DP value

1393 - 1399 = 1.0 X 10E14 (integer portion of DP value

139A - 13 A0 = 1.0 X 10E13 (integer portion of DP value

13A1 - 13 A7 = 1.0 X 10E12 (integer portion of DP value

13A8 - 13AE = 1.0 X 10E11 (integer portion of DP value

161

162

13AC 13AD 13AE 13AF 13B0 13B3 13B4 13B5 13B6 13B7 13BA 13BB 13BC 13BD 13BE 13BF 13C0 13C1 13C2 13C3 13C4 13C5 13C6 13C7 13C8 13C9 13CA 13CB 13CC 13CD 13CE 13CF 13D0 13D1 13D2 13D3 13D4 13D7 13D8 13DA 13DB 13DC 13DD 13DE 13DF 13E0 13E3 13E4 13E5 13E6 13E7 13EA 13ED 13F0 13F2 13F5 13F6 13F7 13FA 13FB

17 00 00 00 E40B54 02 00 00 00 CA9A3B 00 00 00 00 E1 F5 05 00 00 00 80 96 98 00 00 00 00 40 42 0F 00 00 00 00 A0 86 011027 00 1027 E8 03 64 00 0A 00 010021 82 09 E3 E9 CDA409 218013 CDB109 1803 CDB10A C1 D1 CD5509 78 283C

RLA NOP NOP NOP CALL LD NOP NOP NOP JP NOP NOP NOP NOP POP PUSH DEC NOP NOP NOP ADD SUB SBC NOP NOP NOP NOP LD LD RRCA NOP NOP NOP NOP AND ADD LD NOP DJNZ RET INC LD NOP LD NOP LD ADD ADD EX JP CALL LD CALL JR CALL POP POP CALL LD JR

09A4H HL,1380H 09B1H 13F5H 0AB1H BC DE 0955H A,B Z,1439H

-------------------------------------------------------------------------------------------------------------------------

13AF - 13 B5 = 1.0 X 10E10 (integer part of DP value)

13B6 - 13BC = 1.0 X 10E9 (integer part of DP value)

13BD - 13C3 = 1.0 X 10E8 (integer part of DP value)

13C4 - 13CA = 1.0 X 10E7 (integer part of DP value)

13CB - 13D1 = 1,000,000 (integer part of DP value)

13D2 = 100,000 13D5 = 10,000 13D8 13DA 13DC 13DD 2710: 10000 decimal ********** see note--> * 03E8: 1000 decimal 0064: 000A: 100 decimal 10 decimal

13E1: NOP **************************************** 13E2: LD HL,982 Addr of peg to pos cont--> 13E5: EX (SP), HL Addr of conv routine to stack 13E6: JP (HL) Rtn to caller Move current SP value to stack******************** HL = addr of a SP .5 (exponent) Load a .5 into BC/DE and move it to WRA1 Join common code used for X ** Y Convert integer in 4121-4122 to SP & cont--> Load value to be raised into BC/DE. Test sign of exponent A = MSB of number to be raised Jmp if exponent zero

163

13D8

* Integer table of powers of 10 *******************************

13E0 13E3

* ************************************************************* : conversion for floating point numbers

13E7

* ********** SQR routine ************************************ * Compute X ** .5 ( uses general power routine at 13F2)

: store in 4121-4124 ******** X ** Y Routine ****************** : method used is : e ** (y 1n x)

164

13FD 1400 1401 1404 1405 1408 1409 140A 140B 140D 1410 1413 1414 1415 1418 1419 141A 141B 141E 141F 1420 1421 1422 1425 1426 1429 142C 142F 1430 1431 1434 1435 1436 1439 143C 143F 1442 1445 1448 144A 144D 1450 1452 1454 1457 1458 145B 145E 1461 1462 1463 1464 1465 1468 146B 146E 1471 1474 1475 1476

F20414 B7 CA9A19 B7 CA7907 D5 C5 79 F67F CDBF09 F22114 D5 C5 CD400B C1 D1 F5 CD0C0A E1 7C 1F E1 222341 E1 222141 DCE213 CC8209 D5 C5 CD0908 C1 D1 CD4708 CDA409 013881 113BAA CD4708 3A2441 FE88 D23109 CD400B C680 C602 DA3109 F5 21F807 CD0B07 CD4108 F1 C1 D1 F5 CD1307 CD8209 217914 CDA914 110000 C1 4A C34708

JP OR JP OR JP PUSH PUSH LD OR CALL JP PUSH PUSH CALL POP POP PUSH CALL POP LD RRA POP LD POP LD CALL CALL PUSH PUSH CALL POP POP CALL CALL LD LD CALL LD CP JP CALL ADD ADD JP PUSH LD CALL CALL POP POP POP PUSH CALL CALL LD CALL LD POP LD JP

P,1404H A Z,199AH A Z,0779H DE BC A,C 7FH 09BFH P,1421H DE BC 0B40H BC DE AF 0A0CH HL A,H HL (4123H),HL HL (4121H),HL C,13E2H Z,0982H DE BC 0809H BC DE 0847H 09A4H BC,8138H DE,0AA3BH 0847H A,(4124H) 88H NC,0931H 0B40H A,80H A,02H C,0931H AF HL,07F8H 070BH 0841H AF BC DE AF 0713H 0982H HL,1479H 14A9H DE,0000H BC C,D 0847H

--- Jmp if exponent is positive --- Test value to be raised --- Exit if raising 0 to a neg. power --- Another test of value to be raised --- Raising 0 to a positive power --- Move value to be raised to stack --- both parts --- A = MSB of value to be raised --- Test sign of base. Set bits 0-6 in case it is --- Load exponent (power) into BC/DE :negative --->: Jump if base is positive -- : Save the exponent on the stack -- : both parts -- : Get integer portion of exponent cont--> -- : Then restore exponent as a -- : SP value in BC/DE -- : Save integer portion of exponent -- : Compare original exp. to truncated cont--> -- : H = exp (integer) -- : A = exp -- : Set carry if exp. is odd <---: Load SP version of exp --- Move to WRA1 --- Get rest of exponent --- and move to WRA1 --- Call if exponent is odd and base is negative --- Call if exponent is integer & base negative --- Save exponent --- both parts --- Find log of base value. Gives 'ILLEGAL FUNCTION --- Restore exponent : CALL' if negative base raised --- Restore exponent : to a power with a fraction --- Multiply 1n(value) * exponent, then cont--> --- Move exponent to stack *** Compute e ** x ******** --- BC/DE = 1.4427 (approx In 2 + In 2) ----- Multiply exponent value by 1.4427 (2 In 2) --- A = exponent of product --- Test exponent to see if more than 8 cont--> --- Jmp if more than 8 bits in integer part of # --- Integer portion has less than 8 bits. Get --- integer part & put in A reg --- then test it --- Jmp if exponent * 2 In 2 => 126(dec.) --- Save integer + 82 --- Addr. of SP 1.0 --- Add to INT (EXP * 2 In 2) --- Multiply by In 2 --- Clear stack (integerized EXP * 2 In 2) --- then load original --- exponent into BC/DE --- Save integerized EXP * 2 In 2 --- Subtract original exponent from integerized one --- Force difference to be positive --- Addr of 8 coefficients --- Compute series --- Load integerized equivalent --- of EXP * 2 In 2 into BC/DE --- Zero C --- Multiply by sum from series & rtn to caller

165

1415

: into A. Truncated flt. pt. portion into WRA1.

141B

: exp. This tells if exp. is a whole number

1436 : compute a**1n(value) * exponent 1439 * *************************************************************

1448

: bits in integer portion : Method: 1. Compute x=x * 2 1n 2 : 2. Isolate the integer portion of x. If it is > than : 88 then exit with an overflow error. : 3. Using the integer from step 2 compute : y = (2 ** integer) * 2 : 4. Add 1 to the integer from step 2 : 5. Multiply the result of step 4 by In 2 : 6. Subtract step 5 result from original value of x, : and invert the sign of result : 7. Using the value computed in step 7 for x, evaluate : the series: : (((((((x*c0+c1)x+c2)x+c3)x+c4)x+c5)x+c6)x+c7) : 8. Multiply the final term of the series by the value : computed in step 3

166

1479 147A 147B 147D 147E 147F 1480 1482 1483 1484 1485 1486 1488 148B 148C 148D 148E 148F 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 149A 149D 14A0 14A1 14A2 14A5 14A8 14A9 14AC 14AD 14AE 14B1 14B3 14B4 14B5 14B6 14B7 14B8 14B9 14BA 14BB 14BE 14BF 14C2 14C3 14C6 14C7 14C9 14CC 14CD 14CE 14D1

08 40 2E94 74 70 4F 2E77 6E 02 88 7A E6A0 2A7C50 AA AA 7E FF FF 7F 7F 00 00 80 81 00 00 00 81 CDA409 11320C D5 E5 CDBF09 CD4708 E1 CDA409 7E 23 CDB109 06F1 C1 D1 3D C8 D5 C5 F5 E5 CD4708 E1 CDC209 E5 CD1607 E1 18E9 CD7F0A 7C B7 FA4A1E B5

EX LD LD LD LD LD LD LD LD ADC LD AND LD XOR XOR LD RST RST LD LD NOP NOP ADD ADD NOP NOP NOP ADD CALL LD PUSH PUSH CALL CALL POP CALL LD INC CALL LD POP POP DEC RET PUSH PUSH PUSH PUSH CALL POP CALL PUSH CALL POP JR CALL LD OR JP OR

09A4H DE,0C32H DE HL 09BFH 0847H HL 09A4H A,(HL) HL 09B1H B,0F1H BC DE A Z DE BC AF HL 0847H HL 09C2H HL 0716H HL 14B2H 0A7FH A,H A M,1E4AH L

-------------------------------------------------------------------------------------------------------------------------

Count of numbers in list (08) 147A = -1.41316 * 10E-4 : coefficients used : in series to compute : e ** x 147E = 1.32988 * 10E-3 = 1/6

1482 = -8.30136 * 10E-3 = -1/5

1486 = .0416574 =1/4 148A = - .166665 =1/3

148E = .5

1492 = -1.0

1496 = 1.0

Move x value to stack ************** see note--> * Then push a return address of C32 onto the stack It will compute the last term before returning Save addr. of no. of term, coefficients Load value into BC/DE Square x value Restore addr of coefficient Move x value or x ** 2 value to stack A = no. of terms HL = addr of next coeff. Load a coeff pointed to HL & move it to cont--> 14B2: POP AF. Get count of coefficients left BC/DE = x value Saved at 14A9 Count 1 term computed Exit if all terms computed BC/DE = x value Save x value on stk so it can be reused Save count of terms remaining to compute HL pointer to next coeff. Compute: C(I)*x value Restore coeff. table addr. Load next coeff. from list in HL into cont--> Save addr of next coeff. Compute: C(I) * x value + C(I+1) Restore coefficient table addr. Continue series. WRA1 = current term Convert value to Integer ***** RND routine ******* A = MSB argument Set status flags FC error if negative if RND(A) where A is negative Combine MSB & LSB, set status flags

167

149A

* *** General purpose summation routine computes the ********* : series SUM ((((x**2 * c0+c1)x**2 +c2)x**2 +...cN)x : for I=0 to N when entered at 149A. A second entry : point at 14A9 may be used for the series : SUM ((((x*c0+c1)x+c2)x+c3)x+...cN : for I=0 to N. On entry, the x term is in BC/DE. : HL points to a list containing the number of terms : followed by the coefficients.

14AE

: WRA1. HL points to the next value coefficient

14BF

: BC/DE. HL points to next value afterwards

14C9

* *************************************************************

168

14D2 14D5 14D6 14D9 14DC 14DD 14DE 14DF 14E2 14E3 14E4 14E7 14EA 14ED 14F0 14F3 14F4 14F7 14F8 14FA 14FC 14FD 14FE 14FF 1500 1501 1502 1503 1504 1505 1506 1507 150A 150B 150E 150F 1510 1513 1514 1515 1516 1517 151A 151B 151C 151D 151E 1521 1522 1525 1526 1529 152C 152E 152F 1532 1533 1535 1538 1539

CAF014 E5 CDF014 CDBF09 EB E3 C5 CDCF0A C1 D1 CD4708 21F807 CD0B07 C3400B 219040 E5 110000 4B 2603 2E08 EB 29 EB 79 17 4F E3 7E 07 77 E3 D21615 E5 2AAA40 19 EB 3AAC40 89 4F E1 2D C2FC14 E3 23 E3 25 C2FA14 E1 2165B0 19 22AA40 CDEF0A 3E05 89 32AC40 EB 0680 212541 70 2B

JP PUSH CALL CALL EX EX PUSH CALL POP POP CALL LD CALL JP LD PUSH LD LD LD LD EX ADD EX LD RLA LD EX LD RLCA LD EX JP PUSH LD ADD EX LD ADC LD POP DEC JP EX INC EX DEC JP POP LD ADD LD CALL LD ADC LD EX LD LD LD DEC

Z,14F0H HL 14F0H 09BFH DE,HL (SP),HL BC 0ACFH BC DE 0847H HL,07F8H 070BH 0B40H HL,4090H HL DE,0000H C,E H,03H L,08H DE,HL HL,HL DE,HL A,C C,A (SP),HL A,(HL) (HL),A (SP),HL NC,1516H HL HL,(40AAH) HL,DE DE,HL A,(40ACH) A,C C,A HL L NZ,14FCH (SP),HL HL (SP),HL H NZ,14FAH HL HL,0B065H HL,DE (40AAH),HL 0AEFH A,05H A,C (40ACH),A DE,HL B,80H HL,4125H (HL),B HL

--- Jmp if parameter is zero i.e. RND(0) --- Save parameter (X from RND(X)) --- Compute RND(0) --- Load the random number into BC/DE --- Now, save the random number on the --- stack, and load the original parameter into HL --- Save RND (0) value. --- Convert original parameter to SP --- Load value from RND(0) --- Call at 14D6 --- Then, multiply RND(0)*parameter --- HL = addr of a SP 1.0 --- Add 1.0 to current value --- Convert to integer and return to caller --- HL = addr of 3 byte flag table ******** RND(0) ** --- Save flag table addr on stack --- DE = middle and LSB of starting value --- C = MSB of starting value --- H = count of times thru outer loop <-------------: L = times thru inner loop <------: : Move middle of LSB current cont --> : : Double them : : Then move them back : : Now, get MSB of current value : : Double it : : And move back to its source reg : : Save counters. Get addr of cont --> : : A = flag word : : Multiply by 2 : : And restore : : Counters back to HL --->: : : Jmp if flag word has not cont --> : : : Flag word overflowed. Save counter : : : Least two significant bytes of seed : : : Add seed to starting value : : : Move new seed to DE : : : MSB of seed : : : Add to MSB of starting value : : : MSB starting value back to cont --> : : : Restore counters <---: : : Count of times thru inner loop ------>: : Jmp if not 8 times : Save counters HL = addr of flag word : Bump to next flag word : And restore counters. cont --> : Count of times thru outer loop ------------->: Jmp if not 3 times --- Clear flag table addr from stack --- HL = middle and LSB of original seed --- Add to current value and save --- As new seed value --- Set current data type to single precision --- Now, add a 5 to MSB --- Of current value and --- Save as MSB of seed --- Move middle and LSB to DE so we have BC/DE --- B = sign flag and exponent :arrangement --- HL = sign flag word --- Set sign flag positive --- Bump down to exponent

169

14F0

* ************************************************************

value to HL

flag word into HL

overflowed initially

source register

New flag word addr to stack.

170

153A 153B 153C 153E 1541 1544 1547 154A 154D 1550 1553 1554 1555 1558 155B 155E 155F 1560 1563 1566 1569 156C 156D 1570 1573 1576 1577 1578 157B 157E 1581 1582 1585 1588 158B 158D 158E 158F 1590 1591 1592 1593 1594 1595 1596 1598 1599 159B 159C 159D 159E 159F 15A0 15A1 15A2 15A3 15A4 15A7 15A8 15AB

70 4F 0600 C36507 218B15 CD0B07 CDA409 014983 11DB0F CDB409 C1 D1 CDA208 CDA409 CD400B C1 D1 CD1307 218F15 CD1007 CD5509 37 F27715 CD0807 CD5509 B7 F5 F48209 218F15 CD0B07 F1 D48209 219315 C39A14 DB0F 49 81 00 00 00 7F 05 BA D7 1E86 64 2699 87 58 34 23 87 E0 5D A5 86 DA0F49 83 CDA409 CD4715

LD LD LD JP LD CALL CALL LD LD CALL POP POP CALL CALL CALL POP POP CALL LD CALL CALL SCF JP CALL CALL OR PUSH CALL LD CALL POP CALL LD JP IN LD ADD NOP NOP NOP LD DEC CP RST LD LD LD ADD LD INC INC ADD RET LD AND ADD JP ADD CALL CALL

(HL),B C,A B,00H 0765H HL,158BH 070BH 09A4H BC,8349H DE,0FDBH 09B4H BC DE 08A2H 09A4H 0B40H BC DE 0713H HL,158FH 0710H 0955H P,1577H 0708H 0955H A AF P,0982H HL,158FH 070BH AF NC,0982H HL,1593H 149AH

09A4H 1547H

-------------------------------------------------------------------------------------------------------------------------

Set exponent to 80 so value will be < 1 C = new MSB (computed at 152E) B = 0 : rtn to caller Normalize value & Jmp to 14D9 unless RND(0) then Addr. of 1.57 (pi/2) ************* COS routine *** Add 1.5 to current value Save current value on stack ******** SIN routine ** BC/DE = SP = 6.28 (2 pi) Move 2 pi to WRA1 Load value to find SIN of into BC/DE Value / 2 Pi gives x/360 Move value / 2 Pi to stack Convert result to integer so we can isolate BC/DE = quotient & remainder of :remainder value / 2 pi Subtract integer part of value from cont--> Addr of a SP (.250) Subtract .250 from fractional part. Test if < or = Test sign of the difference : to 90 deg Skip sign inversion call at 1582 if positive Jmp if < than 90 deg. Go add back the .250 Add 0.5 to difference : subtracted Test sign of current value. See if > 0.75 Set status flags : (< 270 deg) And save sign indicator (+ = +1, - = -1) If positive, make it negative (gives x - 1.0) Addr of SP (.250) Add 0.250 to current value in WRA1 Get sign reversal flag Set sign of x term according to quadrant Addr of coefficient Compute series and rtn to caller 158B = SP (1.5) **********************************

158F - 1592 = .25

1593: count of values that follow (05) 1594 - 1597 = SP ( 39.7107) : Coefficients used : in power series : to compute SIN 1598 - 159B = SP (-76.575)

159C - 159F = SP ( 81.6022)

15A0 - 15A3 = SP (-41.3417)

15A4 - 15A7 = SP ( 6.28319) Move WRA1 to stack ********* TAN routine ********* Compute SIN(x) see note-->

171

1541 * *********************************************************** 1547 * ************************************************************* * Method: 1. Assume x < or = 360 deg * 2. Re-compute x as x = x/360 so that x =< 1 * 3. If x < or = 90 deg goto step 7 * 4. If x < or = 180 deg then x = 0.5 - x. Goto step 7 * 5. If x < or = 270 deg then x = 0.5 - x * 6. Re-compute x as x = x - 1.0 * 7. Compute SIN using power series

1560

: original value (isolate fractional part of x)

158B

* **************************************************************

15A8

* ************************************************************** : Uses the identity TAN(x) = sink) / cos(x)

172

15AE 15AF 15B0 15B3 15B4 15B7 15BA 15BD 15C0 15C3 15C6 15C9 15CB 15CD 15D0 15D1 15D2 15D5 15D8 15D9 15DC 15DF 15E2 15E3 15E4 15E5 15E6 15E7 15E8 15E9 15EA 15EB 15EC 15EE 15EF 15F0 15F1 15F4 15F5 15F6 15F7 15F8 15F9 15FA 15FB 15FC 15FF 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 160A 160B 160C

C1 E1 CDA409 EB CDB409 CD4115 C3A008 CD5509 FCE213 FC8209 3A2441 FE81 380C 010081 51 59 CDA208 211007 E5 21E315 CD9A14 218B15 C9 09 4A D7 3B 78 02 6E 84 7B FEC1 2F 7C 74 319A7D 84 3D 5A 7D C8 7F 91 7E E4BB4C 7E 6C AA AA 7F 00 00 00 81 8A 09 37 0B 77

POP POP CALL EX CALL CALL JP CALL CALL CALL LD CP JR LD LD LD CALL LD PUSH LD CALL LD RET ADD LD RST DEC LD LD LD ADD LD CP CPL LD LD LD ADD DEC LD LD RET LD SUB LD CALL LD LD XOR XOR LD NOP NOP NOP ADD ADC ADD SCF DEC LD

BC HL 09A4H DE,HL 09B4H 1541H 08A0H 0955H M,13E2H M,0982H A,(4124H) 81H C,15D9H BC,8100H D,C E,C 08A2H HL,0710H HL HL,15E3H 149AH HL,158BH

--- Restore the original value --- to BC / DE --- Move SIN(x)to stack --- Gives original value in BC/DE --- Original value to WRA1 --- Compute COS(x) --- Compute SIN(x)/COS(x) & rtn value as TAN(x) --- Test sign of tangent ********** AIN Routine ***** --- If neg. put pos. to neg, conv. addr cont---> --- Convert current value from neg to pos --- Load exponent of tangent --- Test for value greater than one --->: Jmp if value less than 1 : Setup BC/DE as a : floating point + 1 : to BC / DE : Get reciprocal of tangent : Addr of subtract routine be called after series : Will subtract last term from Pi/2 <---: HL = addr of SP coefficients --- Evaluate series --- Addr of 1.5708 (Pi/2) : step 2 --- Subtract last term from Pi/2 & rtn. On rtn see --- 15E3 = count of SP numbers that follow (09) ****** --- 15E4 = 2.86623 * 10E-3 --: Coefficients used in --: power series for ATN ----- 15E8 = - .0161657 --------- 15EC = .0429096 --------- 15F0 = - .0752896 ----- 15F4 = .105586 --------- 15F8 = - .142089 --------- 15FC = .199936 ----- 1600 = - .333331 --------- 1604 = 1.0000 --------- ************************************ see note--> * ----- INT 0B37 --- ABS 0977

173

15BD 15C0

* **************************************************************** : on stack to give proper result : Method: : : : : : : : : : : : 1. Test sign of tangent, if negative angle is in 2nd or 4th quadrant. Set flag to force result positive on exit. If value is negative invert the sign 2. Test magnitude of tangent. If < 1 goto step 3, otherwise compute its reciprocal and put rtn addr on stack that will calculate Pi/2 - series value 3. Evaluate the series (((x**2 *c0+c1)x**2 +c2)...c8)x 4. If flag from step 1 not set then invert sign of series result. 5. If original value <1 then rtn to caller, or else compute Pi/2 - value from step 4 - then rtn

15E3

* ****************************************************************

1608

* Address of embedded functions *******************************

174

160D 160E 1611 1614 1615 1616 1617 1618 1619 161A 161B 161C 161D 161E 161F 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 162A 162B 162C 162D 162E 162F 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 163A 163B 163C 163E 1640 1641 1644 1645 1648 1649 164C 164D 1650 1651 1652 1653 1655 1656 1659

09 D427EF 2AF527 E7 13 C9 14 09 08 39 14 41 15 47 15 A8 15 BD 15 AA 2C 52 41 58 41 5E 41 61 41 64 41 67 41 6A 41 6D 41 70 41 7F 0A B1 0A DB0A 260B 03 2A3628 C5 2A0F2A 1F 2A612A 91 2A9A2A C5 4E 44 C64F 52 D24553 45

ADD CALL LD RST INC RET INC ADD EX ADD INC LD DEC LD DEC XOR DEC CP DEC XOR INC LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD OR LD IN LD INC LD PUSH LD RRA LD SUB LD PUSH LD LD ADD LD JP LD

-------------------------------------------------------------------------------------------------------------------------

160E: 1611:1613 1614: 1616: 1618: 161A: 161C: 161E: 1620: 1622: 1624: 1626: 1628: 162A: 162C: 162E: 1630: 1632: 1634: 1636: 1638: 163A: 163C: 163E: 1640:1642 1644:1646 1648:164A 164C:164F 80

FRE (27D4) INP (2AEF), POS (27F5) SQR (13E7) RND (14C9) LOG (0809) EXP (1439) COS (1541) SIN (1547) TAN (15A8) ATN (15BD) PEEK (2CAA) CVI (4152) CVS (4158) CVD (415E) EOF (4161) LOC (4164) LOF (4167) MKI$ (416A) MKS$ (416D) MKD$ (4170) CINT (0A7F) CSNG (0AB1) CDBL (0DAB) FIX (0B26) LEN (2A03), STR$(2836) VAL (2AC5), ASC(2A0F) CHR$(2A1F), LEFT$(2A61) RIGHT$ (2A91), MID$(2A9A) END *****************************

81 82

FOR RESET

175

1650

* Reserved word list ******************************************

176

165A 165B 165D 165E 1661 1664 1667 1668 1669 166A 166C 166D 166E 1671 1672 1673 1674 1675 1676 1677 167A 167D 167E 1681 1682 1683 1684 1685 1688 1689 168A 168D 168E 168F 1690 1691 1692 1693 1694 1695 1696 1699 169A 169B 169C 169F 16A1 16A2 16A3 16A4 16A5 16A6 16A7 16AA 16AB 16AE 16AF 16B0 16B3 16B4

54 D345 54 C34C53 C34D44 D2414E 44 4F 4D CE45 58 54 C44154 41 C9 4E 50 55 54 C4494D D24541 44 CC4554 C7 4F 54 4F D2554E C9 46 D24553 54 4F 52 45 C7 4F 53 55 42 D24554 55 52 4E D2454D D354 4F 50 C5 4C 53 45 D4524F 4E D4524F 46 46 C44546 53 54

LD OUT LD JP JP JP LD LD LD ADC LD LD CALL LD RET LD LD LD LD CALL JP LD CALL RST LD LD LD JP RET LD JP LD LD LD LD RST LD LD LD LD JP LD LD LD JP OUT LD LD PUSH LD LD LD CALL LD CALL LD LD CALL LD LD

-------------------------------------------------------------------------------------------------------------------------

Token 83 84 85 86

Word *** Reserved word list *** SET CLS CMD RANDOM

87

NEXT

88 89

DATA INPUT

8A 8B 8C 8D

DIM READ LET GOTO

8E 8F 90

RUN IF RESTORE

91

GOSUB

92

RETURN

93 94

REM STOP

95

ELSE

96 97

TRON TROFF

98

DEFSTR

177

178

16B5 16B6 16B9 16BA 16BB 16BC 16BF 16C0 16C1 16C2 16C5 16C6 16C7 16C8 16CB 16CC 16CD 16CE 16CF 16D0 16D1 16D2 16D3 16D4 16D5 16D8 16D9 16DA 16DB 16DC 16DD 16DE 16DF 16E0 16E1 16E2 16E3 16E4 16E6 16E7 16E8 16E9 16EA 16EB 16EC 16ED 16EE 16EF 16F2 16F3 16F4 16F7 16F8 16FB 16FC 16FD 16FF 1700 1701 1703

52 C44546 49 4E 54 C44546 53 4E 47 C44546 44 42 4C CC494E 45 C5 44 49 54 C5 52 52 4F 52 D24553 55 4D 45 CF 55 54 CF 4E CF 50 45 4E C649 45 4C 44 C7 45 54 D0 55 54 C34C4F 53 45 CC4F41 44 CD4552 47 45 CE41 4D 45 CB49 4C

LD CALL LD LD LD CALL LD LD LD CALL LD LD LD CALL LD PUSH LD LD LD PUSH LD LD LD LD JP LD LD LD RST LD LD RST LD RST LD LD LD ADD LD LD LD RST LD LD RET LD LD JP LD LD CALL LD CALL LD LD ADC LD LD BIT LD

-------------------------------------------------------------------------------------------------------------------------

Token 99

Word *** Reserved word list cont DEFINT

9A

DEFSNG

9B

DEFDBL

9C 9D

LINE EDIT

9E

ERROR

9F

RESUME

A0

OUT

A1 A2

ON OPEN

A3

FIELD

A4

GET

A5

PUT

A6

CLOSE

A7 A8

LOAD MERGE

A9

NAME

AA

KILL

179

180

1704 1705 1708 1709 170C 170D 170F 1710 1711 1713 1714 1715 1716 1717 171A 171B 171C 171D 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 172C 172D 1730 1731 1734 1735 1736 1739 173A 173B 173C 173D 173E 173F 1740 1743 1744 1745 1748 1749 174A 174D 174E 174F 1751 1752 1755 1757 1758 175A 175B 175C

4C CC5345 54 D25345 54 D341 56 45 D359 53 54 45 4D CC5052 49 4E 54 C44546 D0 4F 4B 45 D0 52 49 4E 54 C34F4E 54 CC4953 54 CC4C49 53 54 C4454C 45 54 45 C1 55 54 4F C34C45 41 52 C34C4F 41 44 C35341 56 45 CE45 57 D44142 28D4 4F C64E D5 53 49

LD CALL LD JP LD OUT LD LD OUT LD LD LD LD CALL LD LD LD CALL RET LD LD LD RET LD LD LD LD JP LD CALL LD CALL LD LD CALL LD LD LD POP LD LD LD JP LD LD JP LD LD JP LD LD ADC LD CALL JR LD ADD PUSH LD LD

-------------------------------------------------------------------------------------------------------------------------

Token AB AC AD

Word *** Reserved word list cont LSET RSET SAVE

AE

SYSTEM

AF

LPRINT

B0 B1

DEF POKE

B2

PRINT

B3 B4 B5

CONT LIST LLIST

B6

DELETE

B7

AUTO

B8

CLEAR

B9

CLOAD

BA

CSAVE

BB BC BD BE BF

NEW TAB( TO FN USING

181

182

175D 175E 175F 1761 1762 1763 1764 1765 1766 1767 1768 1769 176A 176B 176C 176D 176E 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 177A 177B 177C 177D 177E 177F 1782 1783 1784 1787 1788 1789 178A 178B 178C 178D 1790 1791 1793 1794 1796 1797 1798 1799 179A 179B 179C 179E 179F 17A0 17A1 17A2 17A3

4E 47 D641 52 50 54 52 D5 53 52 C5 52 4C C5 52 52 D354 52 49 4E 47 24 C9 4E 53 54 52 D0 4F 49 4E 54 D4494D 45 24 CD454D C9 4E 4B 45 59 24 D44845 4E CE4F 54 D354 45 50 AB AD AA AF DBC1 4E 44 CF 52 BE BD

LD LD SUB LD LD LD LD PUSH LD LD PUSH LD LD PUSH LD LD OUT LD LD LD LD INC RET LD LD LD LD RET LD LD LD LD CALL LD INC CALL RET LD LD LD LD INC CALL LD ADC LD OUT LD LD XOR XOR XOR XOR IN LD LD RST LD CP CP

-------------------------------------------------------------------------------------------------------------------------

Token C0

Word *** Reserved word list cont VARPTR

C1

USR

C2

ERL

C3

ERR

C4

STRING$

C5

INSTR

C6

POINT

C7

TIME$

C8 C9

MEM INKEY$

CA CB CC

THEN NOT STEP

D CE CF D0 D1

+ * / up arrow

D2 D3 D4 D5

AND OR > =

183

184

17A4 17A5 17A7 17A8 17A9 17AA 17AB 17AC 17AD 17AE 17B0 17B1 17B2 17B3 17B4 17B5 17B6 17B7 17B9 17BA 17BD 17C0 17C1 17C2 17C3 17C6 17C8 17C9 17CC 17CD 17CE 17CF 17D0 17D1 17D2 17D3 17D6 17D9 17DC 17DD 17DE 17DF 17E2 17E5 17E8 17E9 17EC 17ED 17F0 17F1 17F4 17F5 17F8 17F9 17FC 17FD 17FF 1800 1803 1805

BC D347 4E C9 4E 54 C1 42 53 C652 45 C9 4E 50 D0 4F 53 D351 52 D24E44 CC4F47 C5 58 50 C34F53 D349 4E D4414E C1 54 4E D0 45 45 4B C35649 C35653 C35644 C5 4F 46 CC4F43 CC4F46 CD4B49 24 CD4B53 24 CD4B44 24 C3494E 54 C3534E 47 C34442 4C C649 58 CC454E D354 52

CP OUT LD RET LD LD POP LD LD ADD LD RET LD LD RET LD LD OUT LD JP CALL PUSH LD LD JP OUT LD CALL POP LD LD RET LD LD LD JP JP JP PUSH LD LD CALL CALL CALL INC CALL INC CALL INC JP LD JP LD JP LD ADD LD CALL OUT LD

-------------------------------------------------------------------------------------------------------------------------

D6 D7 Token D8

< SGN Word *** Reserved word list cont INT

D9

ABS

DA DB

FRE (String) INP

DC

POS

DD DE DF E0

SQR RND LOG EXP

E1 E2 E3 E4

COS SIN TAN ATN

E5

PEEK

E6 E7 E8 E9

CVI CVS CVD EOF

EA EB EC ED EE EF F0 F1 F2 F3 F4

LOC LOF MKI$ MKS$ MKD$ CINT CSNG CDBL FIX LEN STR$(Exp)

185

186

1806 1807 1809 180A 180B 180C 180D 1810 1811 1814 1815 1816 1819 181A 181B 181C 181F 1820 1821 1822 1823 1824 1825 1826 1828 1829 182C 182D 182E 1830 1831 1834 1835 1838 1839 183C 183F 1841 1843 1844 1845 1847 1849 184A 184B 184C 184D 184E 184F 1850 1851 1852 1853 1855 1857 1859 185B 185C 185D 185F

24 D641 4C C1 53 43 C34852 24 CC4546 54 24 D24947 48 54 24 CD4944 24 A7 80 AE 1D A1 1C 3801 35 01C901 73 41 D301 B6 22051F 9A 210826 EF 21211F C21EA3 1E39 2091 1D B1 1EDE 1E07 1F A9 1D 07 1F F7 1D F8 1D 00 1E03 1E06 1E09 1EA3 41 60 2EF4 1F

INC SUB LD POP LD LD JP INC CALL LD INC JP LD LD INC CALL INC AND ADD XOR DEC AND INC JR DEC LD LD LD OUT OR LD SBC LD RST LD JP LD JR DEC OR LD LD RRA XOR DEC RLCA RRA RST DEC RET DEC NOP LD LD LD LD LD LD LD RRA

------------------------------------------------------------------------------------------------------------------------

Token F5 F6

Word *** Reserved word list cont VAL (string) ASC (string)

F7 F8

CHR$ (exp) LEFT$ (string, n)

F9

RIGHT$ (string, n)

FA

MID$ (string, pos, n)

FB ' End of syntax list ***--Addr verb **************** 1822: 1DAE - END ********************************* 1824: 1CA1 - FOR 1826: 1828: 182A: 182C: 0138 0135 01C9 4173 RESET SET CLS CMD RANDOM NEXT DATA INPUT DIM READ LET (1EC2 - GOTO, 1EA3 - RUN) IF RESTORE

182E: 01DC 1830: 22B6 1832: 1F05 1834: 219A 1836: 2608 1838: 21EF 183A: 1F21 183C - 183E: 1840: 2039 1842: 1D91 -

1844: 1EB1 - GOSUB 1846: 1EDE - RETURN 1848: 1F07 - REM 184A: 1DA9 - STOP 184C: 1F07 - ELSE 184E: 1DF7 - TRON 1850: 1DF8 - TROFF 1852: 1854: 1856: 1858: 185A: 1E00 1E03 1E06 1E09 41A3 DEFSTR DEFINT DEFSNG DEFDBL LINE

185C: 2E60 - EDIT 185E: 1FF4 - ERROR

187

1821 1822

* ************************************************************* * Routine vector addresses 2 bytes each ***********************

188

1860 1861 1862 1863 1866 1867 1868 1869 186A 186B 186C 186D 186E 186F 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 187A 187B 187C 187D 187E 187F 1880 1881 1883 1884 1885 1886 1887 1889 188A 188C 188D 188E 1890 1891 1893 1895 1896 1897 1898 1899 189A 189B 189C 189D 189E 189F 18A0 18A1 18A3 18A4

AF 1F FB 2A6C1F 79 41 7C 41 7F 41 82 41 85 41 88 41 8B 41 8E 41 91 41 97 41 9A 41 A0 41 B2 02 67 205B 41 B1 2C 6F 20E4 1D 2E2B 29 2B C62B 08 207A 1E1F 2C F5 2B 49 1B 79 79 7C 7C 7F 50 46 DB0A 00 00

XOR RRA EI LD LD LD LD LD LD LD ADD LD ADD LD ADC LD ADC LD ADC LD SUB LD SUB LD SBC LD AND LD OR LD LD JR LD OR INC LD JR DEC LD ADD DEC ADD EX JR LD INC PUSH DEC LD DEC LD LD LD LD LD LD LD IN NOP NOP

-------------------------------------------------------------------------------------------------------------------------

1860: 1FAF - RESUME 1862: 26FB - OUT 1864: 1F6C - ON 1866: 4179 - OPEN 1868: 417C - FIELD 186A: 417E - GET 186C: 4182 - PUT 186E: 4185 - CLOSE 1870: 4188 - LOAD 1872: 418B - MERGE 1874: 418E - NAME 1876: 4191 - KILL 1878: 4197 - LSET 187A: 419A - RSET 187C: 41A0 - SAVE 187E: 02B2 - SYSTEM 1880: 2067 - LPRINT 1882: 415B - CEF 1884: 2CB1 - POKE 1886: 206E - PRINT 1888: 1DE4 - CONT 188A: 2B2E - LIST 188C: 2B29 - LLIST 188E: 1890: 1892: 1894: 2BC6 2008 1E7A 2C1F DELETE AUTO CLEAR CLOAD

1896: 2BF5 - CSAVE 1898: 1B49 - NEW + ********************* Precedent operators ***** * / up arrow AND OR 18A1: 0ADB - convert to double precision ********* 18A3: 0000 - This location not used

189

189A

* ***********************************************************

18A1

* Used by arithmetic routines to do data conversion & ********* : arithmetic.

190

18A5 18A6 18A7 18AA 18AB 18AC 18AD 18AE 18AF 18B0 18B1 18B2 18B3 18B4 18B5 18B7 18B8 18B9 18BA 18BB 18BC 18BD 18BE 18BF 18C2 18C3 18C6 18C7 18C8 18C9 18CA 18CB 18CC 18CD 18CE 18CF 18D0 18D1 18D2 18D3 18D4 18D5 18D6 18D7 18D8 18D9 18DA 18DB 18DC 18DD 18DE 18E0 18E1 18E2 18E3 18E4 18E5 18E6 18E7 18E8

7F 0A F40AB1 0A 77 0C 70 0C A1 0D E5 0D 78 0A 1607 13 07 47 08 A2 08 0C 0A D20BC7 0B F20B90 24 39 0A 4E 46 53 4E 52 47 4F 44 46 43 4F 56 4F 4D 55 4C 42 53 44 44 2F 3049 44 54 4D 4F 53 4C 53 53 54

LD LD CALL LD LD INC LD INC AND DEC PUSH DEC LD LD LD INC RLCA LD EX AND EX INC LD JP DEC JP INC ADD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD LD CPL JR LD LD LD LD LD LD LD LD LD

-------------------------------------------------------------------------------------------------------------------------

18A5: 0AF7 - Convert to Integer 18A7: 0AF4 - Test data type. TM error if not string 18A9: 0AB1 - Convert to single precision 18AB: 0C77 - Double precision add routine 18AD: 0C70 - Double precision subtract routine 18AF: 0DA1 - Double precision multiply routine 18B1: 0DE5 - Double precision divide routine 18B3: 0A78 - Double precision exponential routine 18B5: 0716 - Single precision add routine 18B7: 0713 - Single precision subtract routine 18B9: 0847 - Single precision multiply routine 18BB: 08A2 - Single precision divide routine 18BD: 0A0C - Single precision exponential routine 18BF-18C1: 0BD2/0BC2 Integer add/subtract routines 18C3-18C5: 0BF2/2490 Int multiply/divide routines 18C7: 0A39 - Integer exponential routine

0 - NF (NEXT without FOR ) ** Error codes ******* 2 - SN (Syntax error) 4 - RG (RETURN without GOSUB) 6 - OD (Out of DATA) 8 - FC (Illegal function call) 10 - OV (Overflow) 12 - OM (Out of memory) 14 - UL (Undefined linenumber) 16 - BS (Subscript out of range) 18 - DD (Redimensioned array) 20 - /0 (Division by zero) 22 - ID (Illegal direct operation) 24 - TM (Type mismatch) 26 - OS (Out of string space) 28 - LS (String too long) 30 - ST (String formula too complex)

191

18C9

* *************************************************************

192

18E9 18EA 18EB 18EC 18ED 18EE 18EF 18F0 18F1 18F2 18F3 18F4 18F5 18F6 18F7 18F9 18FA 18FB 18FD 18FE 18FF 1901 1902 1904 1905 1906 1908 190A 190C 190D 190F 1910 1911 1912 1913 1914 1915 1917 1918 1919 191B 191C 191D 191F 1920 1921 1922 1923 1924 1926 1927 1929 192A 192B 192C 192D 192E 192F 1930 1931

43 4E 4E 52 52 57 55 45 4D 4F 46 44 4C 33 D600 6F 7C DE00 67 78 DE00 47 3E00 C9 4A 1E40 E64D DB00 C9 D300 C9 00 00 00 00 40 3000 4C 43 FEFF E9 42 2045 72 72 6F 72 00 2069 6E 2000 52 45 41 44 59 0D 00 42 72

LD LD LD LD LD LD LD LD LD LD LD LD LD INC SUB LD LD SBC LD LD SBC LD LD RET LD LD AND IN RET OUT RET NOP NOP NOP NOP LD JR LD LD CP JP LD JR LD LD LD LD NOP JR LD JR LD LD LD LD LD DEC NOP LD LD

00H L,A A,H A,00H H,A A,B A,00H B,A A,00H

A,(00H) (00H),A

-------------------------------------------------------------------------------------------------------------------------

32 - CN (Can't continue) 34 - NR (No RESUME) 36 - RW (RESUME without error) 38 - UE (Unprintable error) 40 - MO (Missing operand) 42 - FD (Bad file data) 44 - L3 (Disk BASIC command) Subtract LSB * Division Support routine * note-> * and restore value to L Get middle byte Subtract middle byte and move difference to H Get MSB Subtract MSB and move it back Clear A Rtn to caller 408E : Addr of user subroutine 4090 : 4093 : 4093 : 4096 : 4098 : 4099 : 409A : 409B : 409C : 409D : 40A0 : (434C) 40A2 : 3 byte table used by RND to keep track Used for INP (XX) : of previous RND RET : value Used for OUTP (XX) RET 00 00 00 00 40 Contains initial stack addr used : for non-disk IPL Initial BASIC line number (FFFE)

40A4 : Initial addr for PST (42E9) Space, E ******************** ERROR Message ****** R R 0 R Terminator Space, I ********************* IN Message ******** N Space, 0 - terminator Space, R ********************* READY Message ***** E A D Y Carriage ret Terminator B ***************************** BREAK Message **** R

193

18F7

* : : : : : : : :

Code from 18F7 to 191D is moved ***************************** to locations 4080 - 40A5 during the non-disk IPL sequence. This section of code contains the division support routine used for single precision division, and initial values for the communications region locations 408E - 40A4

191D

* *************************************************************

1924

* *************************************************************

1929

* *************************************************************

1930

* *************************************************************

194

1932 1933 1934 1935 1936 1939 193A 193B 193C 193E 193F 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 194B 194C 194D 1950 1951 1952 1953 1955 1958 1959 195A 195B 195C 195D 195E 195F 1960 1961 1963 1964 1967 1969 196A 196B 196D 196F 1970 1971 1973 1974 1976 1977 1978 1979 197A 197C 197E 1981 1982

65 61 6B 00 210400 39 7E 23 FE81 C0 4E 23 46 23 E5 69 60 7A B3 EB 2802 EB DF 010E00 E1 C8 09 18E5 CD6C19 C5 E3 C1 DF 7E 02 C8 0B 2B 18F8 E5 2AFD40 0600 09 09 3EE5 3EC6 95 6F 3EFF 9C 3804 67 39 E1 D8 1E0C 1824 2AA240 7C A5

LD LD LD NOP LD ADD LD INC CP RET LD INC LD INC PUSH LD LD LD OR EX JR EX RST LD POP RET ADD JR CALL PUSH EX POP RST LD LD RET DEC DEC JR PUSH LD LD ADD ADD LD LD SUB LD LD SBC JR LD ADD POP RET LD JR LD LD AND

HL,0004H HL,SP A,(HL) HL 81H NZ C,(HL) HL B,(HL) HL HL L,C H,B A,D E DE,HL Z,194DH DE,HL 18H BC,000EH HL Z HL,BC 193AH 196CH BC (SP),HL BC 18H A,(HL) (BC),A Z BC HL 195BH HL HL,(40FDH) B,00H HL,BC HL,BC A,0E5H A,0C6H L L,A A,0FFH A,H C,197AH H,A HL,SP HL C E,0CH 19A2H HL,(40A2H) A,H L

--- E --- A --- K --- Message terminator --- HL = 4 so we can backspace ********* see note--> * -- Current stack pointer 4 bytes <---: A = current stack ptr (-4) : Backspace one more byte in case FOR token : Does current stack ptr(-4) = FOR token :located : No, exit with A non-zero if no FOR push : C = LSB addr of index variable : Backspace current stack ptr one more byte : B = MSB addr of index variable : HL = addr of FOR index on stack : Save addr of FOR index pointer on stack : L = LSB of index addr : H = MSB of index addr see note--> : Test user specified variable addr : Set status flags : DE = addr of index from stack : Jmp, if user specified addr of zero : HL = addr of index from stack : Compare caller's DE to addr of cont--> : Amt to backspace to next FOR token : HL = stack addr of sign of increment flag : Exit if FOR index = NEXT index : Else, backspace to next possible FOR push --->: Keep looking --- Make sure there's room in ********** see note--> * --- Source addr (end of list) to stack --- Source addr (end of list) to HL --- BC = destination addr (end) <---: Test for end of move : Fetch a byte from source list : Store in destination list : Exit if list moved : Decrement source address : Decrement destination address --->: Loop until list moved --- Save code string addr ************** see note--> * --- Start of free memory ptr. --- B=00, C=no. of double bytes needed --- Add 2*no. of bytes required to start of free area --- HL = end free area --- 196C: PUSH HL, save new free area ptr (starting) --- Now, compute amt. of memory between --- FFC6 (65478) start of the stack and new starting --- Free memory pointer by subtracting new starting --- Free mem. addr from FFC6. If free mem. overflows --- Beyond start of stack we are out of space. --- OM error if C-Free space list exceeds 65478, FFC6H --- Now attempt to determine --- If free space list has --- Overflowed stack area. --- No overflow if CARRY --- OM error code --- Output OM error message --- HL = current line number ************************* --- Combine MSB --- With LSB

195

1936

* (Locate FOR push which matches caller's index specified *****

: : : : :

Called w/DE = addr of NEXT index. Scans stk backwards looking for a FOR push. If one found get addr of index and compare w/caller's DE. If equal exit with A = 0, HL = addr of variable. If unequal keep scanning till no FOR push found & exit w/A<>0.

194C

: <---:-: index from the stack

1955

* string area : : : : : : :

*******

On entry DE = upper limit ************** This routine moves a variable (string usually) into another area specified by the caller. On entry: BC = end addr of list to move DE = start addr of list to move HL = end of area to move list to.

1963

* Compute amt of space between HL and end of memory FFC6. *****

197E

* ************************************************************

196

1983 1984 1986 1989 198A 198C 198E 1991 1994 1997 1999 199C 199F 19A2 19A5 19A8 19AB 19AE 19B1 19B4 19B5 19B6 19B7 19BA 19BD 19C0 19C1 19C4 19C5 19C6 19C7 19C9 19CC 19CD 19D0 19D3 19D4 19D5 19D6 19D9 19DB 19DC 19DE 19DF 19E0 19E3 19E4 19E5 19E6 19E9 19EC 19EF 19F0 19F2 19F5 19F6 19F7 19FA 19FB 19FE

3C 2808 3AF240 B7 1E22 2014 C3C11D 2ADA40 22A240 1E02 011E14 011E00 011E24 2AA240 22EA40 22EC40 01B419 2AE840 C39A1B C1 7B 4B 329A40 2AE640 22EE40 EB 2AEA40 7C A5 3C 2807 22F540 EB 22F740 2AF040 7C B5 EB 21F240 2808 A6 2005 35 EB C3361D AF 77 59 CDF920 21C918 CDA641 57 3E3F CD2A03 19 7E CD2A03 D7 CD2A03 211D19

INC JR LD OR LD JR JP LD LD LD LD LD LD LD LD LD LD LD JP POP LD LD LD LD LD EX LD LD AND INC JR LD EX LD LD LD OR EX LD JR AND JR DEC EX JP XOR LD LD CALL LD CALL LD LD CALL ADD LD CALL RST CALL LD

A Z,198EH A,(40F2H) A E,22H NZ,19A2H 1DC1H HL,(40DAH) (40A2H),HL E,02H BC,141EH BC,001EH BC,241EH HL,(40A2H) (40EAH),HL (40ECH),HL BC,19B4H HL,(40E8H) 1B9AH BC A,E C,E (409AH),A HL,(40E6H) (40EEH),HL DE,HL HL,(40EAH) A,H L A Z,19D0H (40F5H),HL DE,HL (40F7H),HL HL,(40F0H) A,H L DE,HL HL,40F2H Z,19E3H (HL) NZ,19E3H (HL) DE,HL 1D36H A (HL),A E,C 20F9H HL,18C9H 41A6H D,A A,3FH 032AH HL,DE A,(HL) 032AH 10H 032AH HL,191DH

-------------------------------------------------------------------------------------------------------------------------

If current line = FFFF then we have cont--> Jmp if BASIC pgm has not been executed. cont--> Get error override flag Set status flags Code for NO RESUME error Output NR error message if no RESUME addr Error while in Input Phase. Re-enter cont--> Load line number for last DATA statement Store it in current line ptr SN error code 199A: LD E,14 /0 Error code 199D: LD E,0 NF Error code 19A1: LD E,24 RW error code HL = addr of line with error ********************* Save error line number Twice BC = continuation addr after re-initialization HL = stack ptr for start of statement Go re-initialize system variables. Rtn to 19B4 BC = 00 00 A = error number C = error number Save error number HL = addr of last byte executed in current line Save addr of last byte executed Save HL HL = addr of last line executed Combine LSB of last line Executed with MSB of last line Then test, if line number = FFFF Line number = FFFF, still in Input Phase Save error addr Restore last byte executed Save last byte executed Get ON ERROR address Combine LSB with MSB so it can be tested for zero DE = ON ERROR address Addr of flag word during ON ERROR processing Jmp if no ON ERROR address Test if RESUME processing in program Yes, cannot have nested RESUMES Flag an error so RESUME will work HL = addr of statement to branch to Goto Execution Driver Zero A ******************************************* Clear error override flag Error number to E Position video to next line HL = table of error codes DOS Exit (load & execute BASIC error routine) Zero D A = ASCII '?' Print '?' HL = addr Get a char. of error code Print one char of error code Get next char of error code And print it Error message

197

1983 1984

: not started execution of BASIC program : Still in Input Phase

198E

: BASIC 'READY' routine. --- Load current data line number

19A2

* *************************************************************

19E3

* ***********************************************************

198

1A01 1A02 1A05 1A06 1A09 1A0A 1A0D 1A0E 1A11 1A12 1A13 1A14 1A17 1A19 1A1C 1A1F 1A22 1A25 1A28 1A2B 1A2E 1A30 1A33 1A36 1A39 1A3C 1A3D 1A3F 1A42 1A43 1A46 1A47 1A48 1A4B 1A4D 1A4F 1A51 1A54 1A57 1A58 1A5A 1A5B 1A5E 1A60 1A63 1A64 1A66 1A67 1A6A 1A6B 1A6C 1A6E 1A71 1A73 1A76 1A78 1A7B 1A7E 1A81 1A82

E5 2AEA40 E3 CDA728 E1 11FEFF DF CA7406 7C A5 3C C4A70F 3EC1 CD8B03 CDAC41 CDF801 CDF920 212919 CDA728 3A9A40 D602 CC532E 21FFFF 22A240 3AE140 B7 2837 2AE240 E5 CDAF0F D1 D5 CD2C1B 3E2A 3802 3E20 CD2A03 CD6103 D1 3006 AF 32E140 18B9 2AE440 19 38F4 D5 11F9FF DF D1 30EC 22E240 F6FF C3EB2F 3E3E CD2A03 CD6103 DA331A D7 3C

PUSH LD EX CALL POP LD RST JP LD AND INC CALL LD CALL CALL CALL CALL LD CALL LD SUB CALL LD LD LD OR JR LD PUSH CALL POP PUSH CALL LD JR LD CALL CALL POP JR XOR LD JR LD ADD JR PUSH LD RST POP JR LD OR JP LD CALL CALL JP RST INC

HL HL,(40EAH) (SP),HL 28A7H HL DE,0FFFEH 18H Z,0674H A,H L A NZ,0FA7H A,0C1H 038BH 41ACH 01F8H 20F9H HL,1929H 28A7H A,(409AH) 02H Z,2E53H HL,0FFFFH (40A2H),HL A,(40E1H) A Z,1A76H HL,(40E2H) HL 0FAFH DE DE 1B2CH A,2AH C,1A51H A,20H 032AH 0361H DE NC,1A60H A (40E1H),A 1A19H HL,(40E4H) HL,DE C,1A5AH DE DE,0FFF9H 18H DE NC,1A5AH (40E2H),HL 0FFH 2FEBH A,3EH 032AH 0361H C,1A33H 10H A

--- Save addr of 'ERROR' message --- HL = line number of statement causing error --- Line no. to stk. HL = addr of 'ERROR' message --- Print message here addr is in HL --- HL = binary line no. of STOP/END or line w/error --- DE = 65534 (10) --- Is current line no. = 65534 --- Yes, IPL system --- No, test for line no. = 0 --- Combine MSB and LSB --- of current line no. --- If non-zero, print current line no. --- 1A18: POP BC --- Set output device to video ***** Flush current *** --- line buffer. DOS Exit (JP 5FFC) --- Off cassette --- Skip to next line on video --- Ready message --- Print 'READY' message --- Get error number --- Test for syntax error --- If syntax error, enter EDIT routine --- HL = current line no. --- Set current line no. to -1. Signal cont--> --- Auto input flag field - Non zero if auto, 00H --- Set status flags :if not auto --- Jmp & Print '>' prompt if no auto increment --- Else, fetch current line no. into HL --- Save line number on stack --- Output a line --- Load current line no. into DE for search routine --- And leave it on the stack --- Search for matching line number --- '*' (matching line number) --- Jmp if matching line number found --- Else print a blank -- Print a ' ' or '*' --- Accept input into buffer --- DE = current line no. --->: Jmp if BREAK not hit <---:-: Else clear AUTO increment flag -- : : Turn off AUTO increment -- : : Go to 'READY' <---:-: Get increment value ************************* -- : : Add to current line no. and test for overflow ----->: Jmp if line no. exceeds 2**15. Clear AUTO --- Save unincremented line no. on stack :increment --- DE = 65529 --- Compare bumped line no. to 65529 --- DE = unincremented line no. --- Jmp if bumped line no. => 65529 --- Save unincremented value as current line no. --- Set A = -1 --- Use EDIT code to load buffer addr cont--> --- A = '>' (prompt) ******************* see note--> * --- Print '>' --- Accept input, on return HL = buffer addr --- Jmp if BREAK key hit. Go get next line --- Get a char from buffer, skip blanks & control --- Set status flags but save carry :codes

199

1A19

* *************************************************************

1A36

: that execution has not started

1A60

* ***********************************************************

1A73 1A76

: into HL. Then Jmp to 1A98 * Input line no. w/o AUTO increment ***************************

200

1A83 1A84 1A87 1A88 1A8B 1A8C 1A8D 1A8F 1A91 1A92 1A93 1A95 1A98 1A99 1A9C 1A9D 1A9E 1AA1 1AA4 1AA7 1AA8 1AA9 1AAA 1AAD 1AAE 1AAF 1AB0 1AB1 1AB4 1AB5 1AB8 1AB9 1ABC 1ABD 1ABE 1ABF 1AC1 1AC2 1AC5 1AC6 1AC7 1AC8 1AC9 1ACC 1ACD 1AD0 1AD1 1AD2 1AD3 1AD4 1AD5 1AD6 1AD7 1AD8 1AD9 1ADA 1ADB 1ADE 1ADF 1AE0

3D CA331A F5 CD5A1E 2B 7E FE20 28FA 23 7E FE20 CCC909 D5 CDC01B D1 F1 22E640 CDB241 D25A1D D5 C5 AF 32DD40 D7 B7 F5 EB 22EC40 EB CD2C1B C5 DCE42B D1 F1 D5 2827 D1 2AF940 E3 C1 09 E5 CD5519 E1 22F940 EB 74 D1 E5 23 23 73 23 72 23 EB 2AA740 EB 1B 1B

DEC JP PUSH CALL DEC LD CP JR INC LD CP CALL PUSH CALL POP POP LD CALL JP PUSH PUSH XOR LD RST OR PUSH EX LD EX CALL PUSH CALL POP POP PUSH JR POP LD EX POP ADD PUSH CALL POP LD EX LD POP PUSH INC INC LD INC LD INC EX LD EX DEC DEC

A Z,1A33H AF 1E5AH HL A,(HL) 20H Z,1A8BH HL A,(HL) 20H Z,09C9H DE 1BC0H DE AF (40E6H),HL 41B2H NC,1D5AH DE BC A (40DDH),A 10H A AF DE,HL (40ECH),HL DE,HL 1B2CH BC C,2BE4H DE AF DE Z,1AE8H DE HL,(40F9H) (SP),HL BC HL,BC HL 1955H HL (40F9H),HL DE,HL (HL),H DE HL HL HL (HL),E HL (HL),D HL DE,HL HL,(40A7H) DE,HL DE DE

--- So we can test for end of statement --- Jmp if end of statement --- Save status (CARRY)-Get line in binary into DE --- Backspace input buffer over any trailing blanks <---: that follow line number : Get next character : Check for blank --->: Loop till last digit of line number found --- HL = addr of first char following line number --- Fetch first char after line number --- If its a blank then --- Bump buffer addr to next char --- Save binary line number --- Encode input into tokens-BC=length of encoded stmt --- DE = line number in binary --- Get CARRY flag from fetch at 1A81 --- Encoded statement pointer --- DOS Exit (JP 6033) --- Jmp if no line number. Must be Direct Statement --- Save binary line number : or System command --- Save length of code string --- Clear A and --- Set INPUT PHASE entered flag --- Scan for 1st token --- Set status flag --- Save them --- HL = binary equivalent of line number --- Save line number in communications area --- DE = line number for search routine --- Search for matching line number --- After search, BC = addr of line number cont--> --- If matching line not found shift closest line up --- in memory to make room for new line. cont--> --- Restore status from token scan at 1AAD --- Save addr of line in buffer --- If matching line found, otherwise new cont--> --- DE = addr of last line or line > new line --- HL = end of pgm line ptr --- HL = length of code string. cont--> --- BC = length of new line --- HL = new end of pgm line ptr --- Save end of pgm addr --- Make sure enough room for new line. Test for PST --- HL = end of PST :overflow in stack area --- New end of PST addr --- HL = addr of line to be moved up --- Save MSB of addr of line to moved as cont--> --- DE = new line number in binary --- Save addr if line to be moved up --- Bump to LSB of line number entry --- Bump to MSB of line number entry --- DE = binary value of line no for new line. Save --- Bump to MSB :LSB --- Save MSB of new line in old line nos. position --- HL = stmt ptr (past line number) --- DE = first data byte addr following line number --- HL = input area ptr --- DE = input area ptr (fetch addr). cont--> --- DE = input area ptr - 1 --- DE = input area ptr - 2

201

1AB8 1ABC

: in buffer if it exists : DE = addr of line in buffer

1ABF

: line is to be added

1AC5

: Stack = addr of line to be moved

1AD1

: first byte of line

1ADE

: HL = addr of first data position in pgm area (store addr)

202

1AE1 1AE2 1AE3 1AE4 1AE5 1AE6 1AE8 1AE9 1AEC 1AEF 1AF2 1AF5 1AF8 1AFB 1AFC 1AFD 1AFE 1AFF 1B00 1B01 1B02 1B03 1B04 1B05 1B06 1B07 1B08 1B0A 1B0B 1B0C 1B0D 1B0E 1B10 1B13 1B14 1B16 1B17 1B1A 1B1B 1B1D 1B1E 1B20 1B23 1B24 1B26 1B27 1B28 1B29 1B2A 1B2B 1B2C 1B2F 1B30 1B31 1B32 1B33 1B34 1B35 1B36 1B37

1A 77 23 13 B7 20F9 D1 CDFC1A CDB541 CD5D1B CDB841 C3331A 2AA440 EB 62 6B 7E 23 B6 C8 23 23 23 AF BE 23 20FC EB 73 23 72 18EC 110000 D5 2809 D1 CD4F1E D5 280B CF CE11 FAFFC4 4F 1EC2 97 19 EB D1 E3 E5 2AA440 44 4D 7E 23 B6 2B C8 23 23

LD LD INC INC OR JR POP CALL CALL CALL CALL JP LD EX LD LD LD INC OR RET INC INC INC XOR CP INC JR EX LD INC LD JR LD PUSH JR POP CALL PUSH JR RST ADC JP LD LD SUB ADD EX POP EX PUSH LD LD LD LD INC OR DEC RET INC INC

A,(DE) (HL),A HL DE A NZ,1AE1H DE 1AFCH 41B5H 1B5DH 41B8H 1A33H HL,(40A4H) DE,HL H,D L,E A,(HL) HL (HL) Z HL HL HL A (HL) HL NZ,1B06H DE,HL (HL),E HL (HL),D 1AFCH DE,0000H DE Z,1B1FH DE 1E4FH DE Z,1B28H 08H A,11H M,0C4FFH C,A E,0C2H A HL,DE DE,HL DE (SP),HL HL HL,(40A4H) B,H C,L A,(HL) HL (HL) HL Z HL HL

<---: Get a byte of pgm from input buffer : Move it to pgm storage area (PST) : Bump store addr : Bump fetch addr : Test for end of code string --->: Jmp if not end of statement to be moved --- DE = addr of line in pgm table --- Update line ptrs for all line following new line --- DOS Exit (JP 5BD7) --- Update 40FB, 40FD line ptrs = 40F9 --- DOS Exit (JP 5B8C) --- Loop back to repeat input sequence --- HL = start addr of PST (entered from Disk BASIC) --- Move PST addr to HL <---: HL = current line ptr ************ see note--> * : First 2 bytes of each line contains addr of next : line. An addr of 00 00 terminates cont--> : Look for end byte : of pgm (0000) : Return if end : HL = beginning of stmt ptr cont--> : Skip over 3 & 4th bytes of : current line which hold its line no. : A = 0, status flags cleared <--:: Scan for end of current line its cont--> :: When end found, HL+1 will be addr of next line -->:: Loop till end of stmt found : DE=end of stmt + 1 (ptr to next stmt) cont-> : Move addr of next line to 1st 2 bytes of current : Save LSB of next line addr :line : Save MSB of next line addr --->: Loop till end of pgm found --- Initialize starting line to 0 in case * cont--> * --- none is specified. Save on stack --- Jmp if no line nos. given --- Clear temp. starting value --- Get starting line no. in DE --- Save starting line no. --->: Jmp if no ending line specified -- : Test for dash following line number -- : 1B1E : DC CE dash token -- : 1B1F : LD DE,FFAF default ending line number -- : 1B22 : CALL NZ,1E4F get ending line no into DE -- : 1B25 : JP NZ,1997 SN Error if no terminator -- : -- : <---: HL = ending line no. --- DE = starting line no. --- Ending line no to stack. Rtn addr to HL --- Rtn addr to stack so we can exit below --- HL = starting addr of PST ************** cont--> * --- DE = Line number to locate --- BC = address of current line in PST --- A = LSB of addr of next line --- Bump to MSB of addr of next line --- Combine MSB/LSB and set status flags --- Restore HL to start of current line --- Exit if end of PST, else --- Bump HL to point to line number --- for current line

203

1AFC 1AFE

* Update line pointers for all lines after new line. ********** * DE = Addr of Program Statement Table : the program. Get 1st byte of current line and combine w/2nd

1B02

: (Past next stmt ptr and line number)

1B06

: terminated by 00

1B0A

: HL = current line ptr

1B10

* **** Called by LIST/DELETE ********************************** : Converts starting and ending line numbers (X - Y) to : binary and saves ending line number on stack. : Then falls into code below to locate pgm table addr for : starting line. Leaves addr of starting line in BC : ending line number on stack

1B2C

* : : : : : : : :

Search for matching line routine *************************** Exit conditions Line not found. End of PST encountered: NC/Z/HL = BC Line found: DE=HL/C/Z, BC = addr of line in PST HL = addr of next line Line not found. Line number > asked for line number DE>HL/NC/NZ, BC = addr of current line HL = addr of next line

204

1B38 1B39 1B3A 1B3B 1B3C 1B3D 1B3E 1B3F 1B40 1B41 1B42 1B43 1B44 1B45 1B46 1B47 1B49 1B4A 1B4D 1B50 1B53 1B56 1B57 1B58 1B59 1B5A 1B5D 1B60 1B61 1B64 1B66 1B69 1B6B 1B6C 1B6E 1B6F 1B72 1B73 1B74 1B77 1B7A 1B7D 1B80 1B83 1B86 1B89 1B8C 1B8F 1B90 1B93 1B94 1B95 1B98 1B99 1B9A 1B9B 1B9E 1BA1 1BA4 1BA7

7E 23 66 6F DF 60 69 7E 23 66 6F 3F C8 3F D0 18E6 C0 CDC901 2AA440 CDF81D 32E140 77 23 77 23 22F940 2AA440 2B 22DF40 061A 210141 3604 23 10FB AF 32F240 6F 67 22F040 22F740 2AB140 22D640 CD911D 2AF940 22FB40 22FD40 CDBB41 C1 2AA040 2B 2B 22E840 23 23 F9 21B540 22B340 CD8B03 CD6921 AF

LD INC LD LD RST LD LD LD INC LD LD CCF RET CCF RET JR RET CALL LD CALL LD LD INC LD INC LD LD DEC LD LD LD LD INC DJNZ XOR LD LD LD LD LD LD LD CALL LD LD LD CALL POP LD DEC DEC LD INC INC LD LD LD CALL CALL XOR

A,(HL) HL H,(HL) L,A 18H H,B L,C A,(HL) HL H,(HL) L,A Z NC 1B2FH NZ 01C9H HL,(40A4H) 1DF8H (40E1H),A (HL),A HL (HL),A HL (40F9H),HL HL,(40A4H) HL (40DFH),HL B,1AH HL,4101H (HL),04H HL 1B69H A (40F2H),A L,A H,A (40F0H),HL (40F7H),HL HL,(40B1H) (40D6H),HL 1D91H HL,(40F9H) (40FBH),HL (40FDH),HL 41BBH BC HL,(40A0H) HL HL (40E8H),HL HL HL SP,HL HL,40B5H (40B3H),HL 038BH 2169H A

-------------------------------------------------------------------------------------------------------------------------

A = LSB of line no. for current line Bump to MSB HL = MSB of line no. for current line L = LSB of current line number Subtract line no. in DE from line no. for current Set HL = starting addr of current line :statement L = LSB of start addr of current line Now, get addr of next line into HL Bump to MSB of addr of next line H = MSB of addr for next line Form addr of next line in HL CARRY set if current line cont--> Line numbers match. Exit C, Z, cont--> No match, reverse CARRY & exit if line no. in DE < current line number cont--> Loop till end of pgm or line number cont--> Syntax error if NEW XX ************** NEW routine * Clear screen HL = start of Program Statement Table (PST) Turn TRACE OFF Clear AUTO INCREMENT flag Initialize PST as empty by zeroing first two bytes Zero 2nd byte then initialize the start of the variable cont--> Reload HL with PST addr *** RUN starts here *** and backspace 1. This will be the beginning execution addr for the program 26 alpha characters ** RUN line no. starts here *** Def alpha table entries initialized to 004H Load one value :(single precision) Bump to next entry Loop till DEC ALPHA table initialized Clear A-reg Signal no error for RESUME verb then Zero HL Set ON ERROR address to zero Points to next statement following a cont--> Highest memory pointer String working area pointer Restore HL = end of basic pgm Simple variable ptrs Array ptrs DOS Exit (JP 5B8C) Load return addr because we will be cont--> HL = Start of string data ptr HL = Start of string data ptr - 1 -2 Stack ptr = start of string data ptr - 2 HL = start of string data ptr +1 +2 SP = start of string data ptr Initialize literal string pool table as empty Start of LSPT to 40 B3 Output device = video: Print line printer buffer Turn off cassette and set output device = video Zero A then

205

1B43 1B44 1B46 1B47 1B49

: number < value in DE. After CCF CARRY is cleared. : BC = addr of current line, HL = addr next line : BC = addr of current line, HL = addr next line : Greater than requested one found * *************************************************************

1B5A

: list table as the end of the PST

1B77

: BREAK, STOP or END.

1B8F

: changing stack pointer

206

1BA8 1BA9 1BAA 1BAD 1BAE 1BAF 1BB2 1BB3 1BB5 1BB8 1BBA 1BBD 1BC0 1BC1 1BC4 1BC5 1BC6 1BC9 1BCA 1BCB 1BCC 1BCD 1BCF 1BD2 1BD3 1BD5 1BD8 1BD9 1BDC 1BDF 1BE0 1BE1 1BE4 1BE6 1BE8 1BEB 1BEC 1BEE 1BF0 1BF2 1BF5 1BF6 1BF9 1BFA 1BFD 1BFE 1C00 1C01 1C03 1C05 1C07 1C09 1C0B 1C0C 1C0D 1C0E 1C0F 1C10 1C13 1C14

67 6F 32DC40 E5 C5 2ADF40 C9 3E3F CD2A03 3E20 CD2A03 C36103 AF 32B040 4F EB 2AA740 2B 2B EB 7E FE20 CA5B1C 47 FE22 CA771C B7 CA7D1C 3AB040 B7 7E C25B1C FE3F 3EB2 CA5B1C 7E FE30 3805 FE3C DA5B1C D5 114F16 C5 013D1C C5 067F 7E FE61 3807 FE7B 3003 E65F 77 4E EB 23 B6 F20E1C 04 7E

LD LD LD PUSH PUSH LD RET LD CALL LD CALL JP XOR LD LD EX LD DEC DEC EX LD CP JP LD CP JP OR JP LD OR LD JP CP LD JP LD CP JR CP JP PUSH LD PUSH LD PUSH LD LD CP JR CP JR AND LD LD EX INC OR JP INC LD

H,A L,A (40DCH),A HL BC HL,(40DFH) A,3FH 032AH A,20H 032AH 0361H A (40B0H),A C,A DE,HL HL,(40A7H) HL HL DE,HL A,(HL) 20H Z,1C5BH B,A 22H Z,1C77H A Z,1C7DH A,(40B0H) A A,(HL) NZ,1C5BH 3FH A,0B2H Z,1C5BH A,(HL) 30H C,1BF5H 3CH C,1C5BH DE DE,164FH BC BC,1C3DH BC B,7FH A,(HL) 61H C,1C0CH 7BH NC,1C0CH 5FH (HL),A C,(HL) DE,HL HL (HL) P,1C0EH B A,(HL)

--- Clear HL for 'RUN' push --- Zero L --- Clear 'FOR' statement flag --- Signal 'RUN' push --- Return addr to continue executing code string --- Restore code string addr to HL --- Rtn to caller --- A = ASCII ? ************************************** --- Print ? --- A = ASCII space --- Print space --- Wait for keyboard input and rtn to caller --- Zero A ******************************************* --- Clear DATA statement flag --- Zero C-reg --- DE = addr of first char after line number --- HL = input area ptr = tokenized string addr --- Backspace --- twice --- DE = input string addr - 2 --- HL = current input string addr --- Fetch next char. from input string --- Test for space --- Jump if blank --- Save input character --- Test for quote --- If quote, move entire field between quotes to code --- Set status flags :string --- Jmp if end of string --- A = DATA statement flag --- Set status flags --- Load next char from input string --- Jump if DATA stmt encountered --- '?' abbreviation for print --- Print token replaces question mark --- Jmp if '?' (print token) --- Re-fetch current character --- Test for numeric as alpha-numeric --- Char < 30 - that means it's not a letter or digit --- Char < 3C - that means 0-9,:,;,< cont--> --- Save pointer to buffer origin -2, -1, . . --- DE addr of syntax tree --- Save BC --- Rtn add after matching syntax tree --- W/input string --- B = syntax tree control char count --- Current input character --- Test for upper case --->: Jump if not lower case -- : Test for upper case --->: Jump if not lower case -- : Make upper case -- : Save converted character <---: Reload current character --- HL = syntax list, DE = addr of current string <---: Bump to next char in syntax list :Set status flags for current char cont--> --->: Scan syntax list till control char found --- Count of syntax control char passed --- Get syntax element

207

1BB3

* *************************************************************

1BC0

* *************************************************************

1BF2

: Constant or special char. Move it to token area.

1C0F

: from syntax list

208

1C15 1C17 1C18 1C19 1C1B 1C1C 1C1D 1C1E 1C1F 1C20 1C23 1C24 1C25 1C27 1C29 1C2A 1C2B 1C2C 1C2D 1C2F 1C31 1C33 1C34 1C36 1C37 1C39 1C3A 1C3B 1C3C 1C3D 1C3E 1C3F 1C40 1C41 1C42 1C44 1C46 1C48 1C49 1C4A 1C4C 1C4E 1C50 1C51 1C53 1C54 1C55 1C56 1C57 1C58 1C5A 1C5B 1C5C 1C5D 1C5E 1C5F 1C61 1C63 1C65 1C67

E67F C8 B9 20F3 EB E5 13 1A B7 FA391C 4F 78 FE8D 2002 D7 2B 23 7E FE61 3802 E65F B9 28E7 E1 18D3 48 F1 EB C9 EB 79 C1 D1 EB FE95 363A 2002 0C 23 FEFB 200C 363A 23 0693 70 23 EB 0C 0C 181D EB 23 12 13 0C D63A 2804 FE4E 2003 32B040

AND RET CP JR EX PUSH INC LD OR JP LD LD CP JR RST DEC INC LD CP JR AND CP JR POP JR LD POP EX RET EX LD POP POP EX CP LD JR INC INC CP JR LD INC LD LD INC EX INC INC JR EX INC LD INC INC SUB JR CP JR LD

7FH Z C NZ,1C0EH DE,HL HL DE A,(DE) A M,1C39H C,A A,B 8DH NZ,1C2BH 10H HL HL A,(HL) 61H C,1C33H 5FH C Z,1C1DH HL 1C0CH C,B AF DE,HL DE,HL A,C BC DE DE,HL 95H (HL),3AH NZ,1C4AH C HL 0FBH NZ,1C5AH (HL),3AH HL B,93H (HL),B HL DE,HL C C 1C77H DE,HL HL (DE),A DE C 3AH Z,1C67H 4EH NZ,1C6AH (40B0H),A

--- Clear sign bit --- Zero terminates syntax list, goto 1C3D --- Compare input element w/syntax element --- No match, scan till past control element --- HL = start of current symbol in input string --- Save starting addr of current symbol <-----: Bump to next char in syntax list :Get next syntax list element : Set status flags for end of name test ------:->: Jmp if control element, we have a : : Complete match. Save next syntax element : : If count of keyword being examined is : : 8D then we are testing for a GOTO --->: : : Jump if not 'GOTO' token : : : Skip following char if its blank : : : Decrement for following skip <---: : : Skip to next char : : Get next element from input string : : Test for upper case --->: : : Jump if not lower case : : : Force upper case <---: : : Compare input element & syntax element ----->: : Jmp if equal --: Unequal, restart scan from last --: Point in syntax list <--------: Syntax list index --- Get rid of HL push at 1C1C --- HL = syntax tree addr for this string, DE = --- current string Goto 1C3D --- HL = current string --- A = syntax list index --- Clear rtn addr from stack --- DE = input string buffer origin-2 cont--> --- HL = buffer origin-2, DE = current string addr --- Test if ELSE token --- ':' buffer origin-2 --->: Jump if not 'ELSE' token -- : Count 1 char in token buffer -- : Bump to next position in token buffer <---: Test for REM token --->: Jump if not ''' (abbreviation for 'REM') token -- : ':' to tokenized buffer -- : next pos. in token buffer -- . 'REM' token -- : To tokenized buffer -- : Next pos. in token buffer -- : HL = input string addr. DE = token buffer addr. -- : Count 2 -- : More chars to token buffer -- : Go move comment to token buffer <---: DE = buffer area-2, HL = current string addr --- Bump to next char in input string --- Syntax tree index to buffer origin-2 : or if blank --- DE = buffer origin-1 : move the --- C = index for next syntax element : blank --- Test for multi-statement line --->: Jmp if multi-statement line -- : Test for DATA stmt -- : Jump if not 'DATA' token <---: Syntax list index to flag 'data' statement

209

1C40

: loaded at 1CF5

210

1C6A 1C6C 1C6F 1C70 1C71 1C72 1C74 1C75 1C77 1C78 1C79 1C7A 1C7B 1C7D 1C80 1C81 1C82 1C83 1C84 1C87 1C88 1C89 1C8A 1C8B 1C8C 1C8D 1C8E 1C8F 1C90 1C91 1C92 1C93 1C94 1C95 1C96 1C97 1C98 1C99 1C9A 1C9B 1C9E 1CA1 1CA3 1CA6 1CA9 1CAA 1CAD 1CAE 1CB0 1CB1 1CB2 1CB5 1CB6 1CB8 1CBB 1CBC 1CBF 1CC0 1CC1 1CC4

D659 C2CC1B 47 7E B7 2809 B8 28E4 23 12 0C 13 18F3 210500 44 09 44 4D 2AA740 2B 2B 2B 12 13 12 13 12 C9 7C 92 C0 7D 93 C9 7E E3 BE 23 E3 CA781D C39719 3E64 32DC40 CD211F E3 CD3619 D1 2005 09 F9 22E840 EB 0E08 CD6319 E5 CD051F E3 E5 2AA240 E3

SUB JP LD LD OR JR CP JR INC LD INC INC JR LD LD ADD LD LD LD DEC DEC DEC LD INC LD INC LD RET LD SUB RET LD SUB RET LD EX CP INC EX JP JP LD LD CALL EX CALL POP JR ADD LD LD EX LD CALL PUSH CALL EX PUSH LD EX

59H NZ,1BCCH B,A A,(HL) A Z,1C7DH B Z,1C5BH HL (DE),A C DE 1C70H HL,0005H B,H HL,BC B,H C,L HL,(40A7H) HL HL HL (DE),A DE (DE),A DE (DE),A A,H D NZ A,L E A,(HL) (SP),HL (HL) HL (SP),HL Z,1D78H 1997H A,64H (40DCH),A 1F21H (SP),HL 1936H DE NZ,1CB5H HL,BC SP,HL (40E8H),HL DE,HL C,08H 1963H HL 1F05H (SP),HL HL HL,(40A2H) (SP),HL

--- Test for REM token --- Jump if not 'REM' token. Analyze rest of statement --- B = 00 <---: Get next char from input string : Set status flags so we can test for EOS ----:>: Jmp if EOS : : Move statement from input buffer to input : : buffer - 2. Loop till EOS detected. Count : : of characters moved in BC. Also entered if : : a ' ' string is detected. : : Count 1 char added to token buffer : : Bump token buffer addr. --->: : Loop till EOS or ending quote found <-----: Now, add --- Five to the length of the --- token buffer thus far --- then leave --- New count in BC --- Get start of input string area --- Backspace once --- Backspace twice --- Three times --- Then zero --- Last 3 words of tokenized string --- Second zero --- Bump addr --- Third zero --- Rtn to caller --- Compute *********** RST 18 sends you here ******* --- H - D Computes HL-DE --- Exit if unequal Z if equal --- Compute C if DE>HL --- L - E --- and rtn to caller --- Get value to be compared * RST 08 routine ******* --- Save rtn addr. --- Compare (HL) with value following RST 8 --- Bump rtn addr --- Restore rtn addr to stack, cont--> --- CALL RST 10 If expected character found --- SN error if expected char not found --- FOR signal value ******************* FOR routine * --- Signal FOR statement. --- Evaluates x = y (index) --- Save code string addr. DE=addr of index variable --- Scan stack backwards looking for other cont--> --- DE = current code string addr (addr of TO token) --->: Jmp if nested 'FOR' not on stack cont--> -- : BC = Offset to end of stack frame cont--> -- : Reset CSP to this addr. Regain the cont--> -- : NF error next. Save CSP addr in 40E8 <---: HL = current code string addr --- C = 1/2 amt. of space needed --- Make sure there's 16 bytes of free space --- Save code string addr before 'TO' --- Scan till end of statement --- Stack = end of statement, cont--> --- Code string addr to stk. should point to TO token --- HL = current line no. in binary. --- Stack = end of line addr. FOR line no. cont-->

211

1C90

* *************************************************************

1C96

* RST 08 sends you here ***************************************

1C9A

: HL = current code string pointer

1CA1

* *************************************************************

1CAA 1CAE 1CB0 1CB1

: FOR/NEXT token with same index (Error if found) : If one is found, on exit HL = starting addr of FOR push : After addition we are at end of 1st FOR frame push : stack space and force a NF error

1CBF

: HL = current position in statement

1CC4

: in binary for FOR statement

212

1CC5 1CC6 1CC7 1CC8 1CCB 1CCE 1CCF 1CD2 1CD3 1CD4 1CD7 1CDA 1CDB 1CDE 1CDF 1CE1 1CE4 1CE5 1CE6 1CE7 1CEA 1CEC 1CEF 1CF2 1CF3 1CF4 1CF5 1CF8 1CF9 1CFA 1CFB 1CFD 1CFF 1D01 1D04 1D05 1D08 1D0B 1D0E 1D0F 1D10 1D11 1D12 1D13 1D14 1D15 1D16 1D19 1D1A 1D1C 1D1D 1D1E 1D21 1D22 1D25 1D28 1D2C 1D2D 1D2F 1D31

CF BD E7 CAF60A D2F60A F5 CD3723 F1 E5 F2EC1C CD7F0A E3 110100 7E FECC CC012B D5 E5 EB CD9E09 1822 CDB10A CDBF09 E1 C5 D5 010081 51 5A 7E FECC 3E01 200E CD3823 E5 CDB10A CDBF09 CD5509 E1 C5 D5 4F E7 47 C5 E5 2ADF40 E3 0681 C5 33 CD5803 B7 C4A01D 22E640 ED73E840 7E FE3A 2829 B7

RST CP RST JP JP PUSH CALL POP PUSH JP CALL EX LD LD CP CALL PUSH PUSH EX CALL JR CALL CALL POP PUSH PUSH LD LD LD LD CP LD JR CALL PUSH CALL CALL CALL POP PUSH PUSH LD RST LD PUSH PUSH LD EX LD PUSH INC CALL OR CALL LD LD LD CP JR OR

08H L 20H Z,0AF6H NC,0AF6H AF 2337H AF HL P,1CECH 0A7FH (SP),HL DE,0001H A,(HL) 0CCH Z,2B01H DE HL DE,HL 099EH 1D0EH 0AB1H 09BFH HL BC DE BC,8100H D,C E,D A,(HL) 0CCH A,01H NZ,1D0FH 2338H HL 0AB1H 09BFH 0955H HL BC DE C,A 20H B,A BC HL HL,(40DFH) (SP),HL B,81H BC SP 0358H A NZ,1DA0H (40E6H),HL (40E8H),SP A,(HL) 3AH Z,1D5AH A

--- Test for TO token --- DC BD TO token --- Test data type of index variable --- TM error if Z (string) --- TM error if NC (double) --- Save type flags --- Evaluate TO side of FOR statement --- Restore index type flags --- Save current position in code string after TO --->: Jmp if index is single precision :token : Current TO value to integer : Integer value to stack. Reload HL : DE = increment in case STEP not specified : Get next element from code string : Compare with STEP token : Call if 'STEP' token - Get step value into DE : Save step value : Save code string position : STEP value to HL so we test its size : Get sign of STEP into A. A=+1 if pos., -1 if neg ----:>: Skip over single precision code for counter <---: : Convert TO value to single precision :& step -: Load counter into BC/DE -: HL = end of TO expression -: Save TO value (limit) -: All four bytes of it -: BC = single precision 1 = default STEP value -: 0000 = DE -: E as well -: A = next element from code string -: Test for STEP token -: Default step = 1 --->: : Jump if not 'STEP' token -- : : Evaluate STEP expression -- : : Save code string addr -- : : Convert value to single precision -- : : Load STEP expression value into BC/DE -- : : Get sign of STEP value into A. +1=pos,-1=neg <---:-: HL = current code string addr <---: Save STEP expression --- On stack --- Sign flag for STEP value to C --- Test data type for STEP value --- B = type for STEP value. cont--> --- Save type adjusted / sign flag --- Save current code string addr on stack --- HL = addr of index from FOR x = y --- HL = code string addr. Stack = addr of x variable --- B = FOR token --- Save FOR token / sign of STEP increment --- Leave a one byte gap on the stack cont--> --- Set status flags for input --- If key was hit, check for shift @ --- Save address of last byte executed in current line --- Save CSP --- Fetch next character from input string --- and test for a compound statement --- Jump if ':' - Multiple statement this line --- Else, make sure code string terminates --- Set status flags

213

1D13

: -1 (int), +1 (sing) C = STEP sign flag

1D1E

: Continue execution of code string. Test for keyboard input

214

1D32 1D35 1D36 1D37 1D38 1D39 1D3C 1D3D 1D3E 1D3F 1D40 1D41 1D44 1D47 1D48 1D4A 1D4B 1D4D 1D50 1D53 1D55 1D58 1D59 1D5A 1D5B 1D5E 1D5F 1D60 1D62 1D65 1D67 1D6A 1D6B 1D6C 1D6E 1D6F 1D72 1D73 1D74 1D75 1D76 1D77 1D78 1D79 1D7A 1D7C 1D7D 1D7F 1D82 1D84 1D86 1D88 1D8B 1D8D 1D8E 1D8F 1D90 1D91 1D92 1D95

C29719 23 7E 23 B6 CA7E19 23 5E 23 56 EB 22A240 3A1B41 B7 280F D5 3E3C CD2A03 CDAF0F 3E3E CD2A03 D1 EB D7 111E1D D5 C8 D680 DA211F FE3C D2E72A 07 4F 0600 EB 212218 09 4E 23 46 C5 EB 23 7E FE3A D0 FE20 CA781D FE0B 3005 FE09 D2781D FE30 3F 3C 3D C9 EB 2AA440 2B

JP INC LD INC OR JP INC LD INC LD EX LD LD OR JR PUSH LD CALL CALL LD CALL POP EX RST LD PUSH RET SUB JP CP JP RLCA LD LD EX LD ADD LD INC LD PUSH EX INC LD CP RET CP JP CP JR CP JP CP CCF INC DEC RET EX LD DEC

NZ,1997H HL A,(HL) HL (HL) Z,197EH HL E,(HL) HL D,(HL) DE,HL (40A2H),HL A,(411BH) A Z,1D59H DE A,3CH 032AH 0FAFH A,3EH 032AH DE DE,HL 10H DE,1D1EH DE Z 80H C,1F21H 3CH NC,2AE7H C,A B,00H DE,HL HL,1822H HL,BC C,(HL) HL B,(HL) BC DE,HL HL A,(HL) 3AH NC 20H Z,1D78H 0BH NC,1D8BH 09H NC,1D78H 30H A A DE,HL HL,(40A4H) HL

--- SN error if NC with a byte of zeroes --- Get LSB of pointer to next statement --- Test for non-zero by combining --- with MSB byte --- of pointer to the next statement --- Jmp if last executable statement, else --- Get line number of next statement --- into DE --- Bump to MSB of line number for next statement --- DE = binary line number of next statement --- HL = Line number for next statement --- Update last executed line to current line number --- Get TRACE flag --- Set status flags --->: Jmp if TROFF, fall through if TRON -- : Save DE since display routine uses it -- : ASCII '<' -- : Print '<' -- : Convert line number to binary & print it -- : ASCII '>' -- : Print '>' (This gives dine number>) -- : Restore DE <---: HL = code string current line --- Get next token ***** Execution phase starts here ** --- Rtn addr after executing one verb --- Rtn addr onto stack --- Exit if EOS (end of statement) - Go back to 1D1E --- (tokens range from 80 - FB) Compute rel. token --- Not a token - must be assignment stmt :index --- Test if token below TAB token --- Jmp if token => BC (TAB - MID$,') --- Double remainder for routine address offset --- BC = routine offset --- BC = 00 / 2 * token --- Save HL (current location in code string) --- Address table of verb action routines --- HL = routine table address ptr --- C = LSB of verb action routine addr --- Bump to MSB --- B = MSB of verb action routine addr --- Save routine address on stack see note --> --- Restore code string address <---:-: Bump to next character *** RST 10 action rtne * : : Get next character : : Compare it with a colon (:) : : Rtn if character is :,;,<,.....A - Z : : else test for a blank --->: : Get next character if this one is a blank -: Compare it with a vertical TAB --->: : Jump if A >= 0B (not a control code) : : Test for a horizontal TAB ----:>: Jmp if not horizontal TAB or line feed <---: Compare with ASCII '0' --- Set CARRY if numeric (>=30) --- Clear CARRY if not numeric (<30) --- Set status flags (except CARRY) according to --- Rtn to caller : character just loaded --- Save HL *********************** RESTORE routine ** --- HL = start of program ptr --- Backspace 1 byte, save HL

215

1D5A

: : : : : : : : :

Find next non-blank character in code string **************** Method: 1. Locate next token in current statement and branch to verb action routine. Force return to 1D1E after verb routine. 2. After each completed verb action routine test for BREAK, end of line (bump to next line), end of program (rtn to INPUT PHASE),or TRON option goto step 1

: (It will be popped below) 1D78 * RST 10 routine addr sends you here **************************

1D91

* *************************************************************

216

1D96 1D99 1D9A 1D9B 1D9E 1D9F 1DA0 1DA2 1DA5 1DA8 1DA9 1DAA 1DAB 1DAE 1DAF 1DB0 1DB3 1DB4 1DB7 1DBA 1DBD 1DC0 1DC1 1DC4 1DC5 1DC6 1DC7 1DC8 1DC9 1DCB 1DCE 1DD1 1DD4 1DD7 1DDA 1DDB 1DDE 1DE1 1DE4 1DE7 1DE8 1DE9 1DEB 1DEE 1DEF 1DF2 1DF5 1DF6 1DF7 1DF9 1DFC 1DFD 1DFE 1DFF 1E00 1E02 1E05 1E08 1E0B 1E0E

22FF40 EB C9 CD5803 B7 C8 FE60 CC8403 329940 3D C0 3C C3B41D C0 F5 CCBB41 F1 22E640 21B540 22B340 21F6FF C1 2AA240 E5 F5 7D A4 3C 2809 22F540 2AE640 22F740 CD8B03 CDF920 F1 213019 C2061A C3181A 2AF740 7C B5 1E20 CAA219 EB 2AF540 22A240 EB C9 3EAF 321B41 C9 F1 E1 C9 1E03 011E02 011E04 011E08 CD3D1E 019719

LD EX RET CALL OR RET CP CALL LD DEC RET INC JP RET PUSH CALL POP LD LD LD LD POP LD PUSH PUSH LD AND INC JR LD LD LD CALL CALL POP LD JP JP LD LD OR LD JP EX LD LD EX RET LD LD RET POP POP RET LD LD LD LD CALL LD

(40FFH),HL DE,HL 0358H A Z 60H Z,0384H (4099H),A A NZ A 1DB4H NZ AF Z,41BBH AF (40E6H),HL HL,40B5H (40B3H),HL HL,0FFF6H BC HL,(40A2H) HL AF A,L H A Z,1DD4H (40F5H),HL HL,(40E6H) (40F7H),HL 038BH 20F9H AF HL,1930H NZ,1A06H 1A18H HL,(40F7H) A,H L E,20H Z,19A2H DE,HL HL,(40F5H) (40A2H),HL DE,HL A,0AFH (411BH),A AF HL E,03H BC,021EH BC,041EH BC,081EH 1E3DH BC,1997H

--- Data ptr = start of program - 1 --- Restore HL --- Rtn to caller --- Scan keyboard once ******************************* --- Set status flags for character strobed --- Return if no key --- Shift @ ? --- if so, wait until user types a character --- Save character typed --- A + 1 if break key --- Stop routine ************************************* --- Set A = 1, status non-zero --- Use END code --- Syntax error if END XX ************ END routine ** --- Save zero status (END processing) --- DOS Exit (JP 60A1) --- Restore END status to A status register --- Current code string addr for STOP or END --- HL = start of literal string area --- Reset pointer to start of literal string area --- 1DBE: OR FF --- Clear stack --- Current line no. in binary --- Save binary line no. for STOP/END stmt --- A = 0 (END), 1 (STOP) --- Combine LSB of current line with --- MSB of current line no.. so we can --- test for uninitialized line no. (FFFF) --->: Jmp if line no. = FFFF pgm execution not started -- : Else, save line number we ended on -- : HL = current line number -- : Save in 40F7 <---: Initialize output DCB to the video --- Print a CR --- Restore A = 0 (END), 1 (STOP) --- Addr of break message --- Jmp if STOP encountered --- Jmp if END statement or error in command mode --- HL = last stmt byte scanned *** Cont routine *** --- Combine LSB/MSB of addr --- for last statement executed --- CN error code --- Output CN if no continuation addr --- Continuation line number to DE --- HL = last line number executed --- Save line number with error --- then set HL = addr of continuation line no. --- Go begin execution at continuation line --- Set A-reg non-zero for TRON *** TRON routine ***** --- 1DF8: XOR A Set A-reg zero for TROFF --- Save TRON/TROFF flag and return to interpreter These instructions are not used by Level II --- E = type for string values ** DEFSTR routine ***** --- lE03 LD E,02 DEFINT routine --- lE06 LD E,04 DEFSNG routine --- 1E09 LD E,08 DEFDBL routine --- Test next element in code string. Make sure its a --- Error addr in case its not :letter

217

1D9B

* *************************************************************

1DA0

* *************************************************************

1DA9

* *************************************************************

1DAE

* *************************************************************

1DE4

* ************************************************************

1DF7

* *************************************************************

1E00

* *************************************************************

218

1E11 1E12 1E13 1E15 1E16 1E17 1E18 1E1A 1E1C 1E1D 1E20 1E21 1E23 1E24 1E25 1E26 1E27 1E28 1E29 1E2A 1E2D 1E2F 1E30 1E31 1E32 1E33 1E35 1E36 1E37 1E39 1E3A 1E3B 1E3D 1E3E 1E40 1E41 1E43 1E44 1E45 1E46 1E49 1E4A 1E4C 1E4F 1E50 1E52 1E53 1E56 1E57 1E5A 1E5B 1E5E 1E5F 1E60 1E61 1E62 1E65 1E66 1E69 1E6A

C5 D8 D641 4F 47 D7 FECE 2009 D7 CD3D1E D8 D641 47 D7 78 91 D8 3C E3 210141 0600 09 73 23 3D 20FB E1 7E FE2C C0 D7 18CE 7E FE41 D8 FE5B 3F C9 D7 CD022B F0 1E08 C3A219 7E FE2E EB 2AEC40 EB CA781D 2B 110000 D7 D0 E5 F5 219819 DF DA9719 62 6B

PUSH RET SUB LD LD RST CP JR RST CALL RET SUB LD RST LD SUB RET INC EX LD LD ADD LD INC DEC JR POP LD CP RET RST JR LD CP RET CP CCF RET RST CALL RET LD JP LD CP EX LD EX JP DEC LD RST RET PUSH PUSH LD RST JP LD LD

BC C 41H C,A B,A 10H 0CEH NZ,1E25H 10H 1E3DH C 41H B,A 10H A,B C C A (SP),HL HL,4101H B,00H HL,BC (HL),E HL A NZ,1E30H HL A,(HL) 2CH NZ 10H 1E0BH A,(HL) 41H C 5BH

10H 2B02H P E,08H 19A2H A,(HL) 2EH DE,HL HL,(40ECH) DE,HL Z,1D78H HL DE,0000H 10H NC HL AF HL,1998H 18H C,1997H H,D L,E

-------------------------------------------------------------------------------------------------------------------------

Error addr to stack Syntax error if no letter follows DEFSTR Subtract an ASCII 'A' which gives a value in range 0-25. Save range value in C and in B Examine next element in code string Test for a dash (-) token No range of letters specified A range has been specified, get the ending letter Check for a letter Syntax error if not a letter A = 0 - 26(base 10) corresponding to letters A thru Z Get next character Now, make sure 2nd letter follows 1st Subtract 1st letter from 2nd Syntax error if letter range not in ascending A=number of type entries to change :order Clear error addr. Save current code string addr HL = type table B = 00 / value for 1st letter Find next entry in type table Set data type in type table Bump to next entry Count of entries changed Loop till range of entries changed Restore code string pointer and look for more letters Test for comma Return if not comma Fetch next element and go test for a letter Get next element from code string **************** Compare to an ASCII A If not a letter Compare to an ASCII up-arrow, gives CARRY Set CARRY if not a letter : if a letter NC if a letter Fetch next symbol from input. ********** cont--> Get value for next expression into cont--> DE as an integer, set to subscript cont--> FC error if index is negative Output FC error Get next character ********** ASCII to binary *** Check for period abbreviation DE = current input symbol addr DE = period address HL = addr of current symbol Jmp, period Backspace to current character ***** see note--> * Initialize accumulation to zero Reprocess previous character Return if not a digit Save current character pointer (digit) Save digit plus flags from RST 10 HL = 6552 Is accumulated value > 6552 SN error if value > 6552 No, continue Move current value to HL

219

1E3D

* *************************************************************

1E45

* Called when evaluating A ************************************ : Subscript for a variable reference : evaluation if value positive

1E4F

* *************************************************************

1E5A

* Start at . pt & work backwards ********* ASCII to binary ****

220

1E6B 1E6C 1E6D 1E6E 1E6F 1E70 1E72 1E73 1E75 1E76 1E77 1E78 1E7A 1E7D 1E80 1E81 1E82 1E83 1E84 1E87 1E88 1E89 1E8A 1E8B 1E8C 1E8D 1E90 1E93 1E96 1E97 1E98 1E9B 1E9C 1E9F 1EA0 1EA3 1EA6 1EA9 1EAC 1EAF 1EB1 1EB3 1EB6 1EB7 1EB8 1EB9 1EBC 1EBD 1EBF 1EC0 1EC1 1EC2 1EC5 1EC8 1EC9 1ECC 1ECD 1ECE 1ECF 1ED2

19 29 19 29 F1 D630 5F 1600 19 EB E1 18E4 CA611B CD461E 2B D7 C0 E5 2AB140 7D 93 5F 7C 9A 57 DA7A19 2AF940 012800 09 DF D27A19 EB 22A040 E1 C3611B CA5D1B CDC741 CD611B 011E1D 1810 0E03 CD6319 C1 E5 E5 2AA240 E3 3E91 F5 33 C5 CD5A1E CD071F E5 2AA240 DF E1 23 DC2F1B D42C1B

ADD ADD ADD ADD POP SUB LD LD ADD EX POP JR JP CALL DEC RST RET PUSH LD LD SUB LD LD SBC LD JP LD LD ADD RST JP EX LD POP JP JP CALL CALL LD JR LD CALL POP PUSH PUSH LD EX LD PUSH INC PUSH CALL CALL PUSH LD RST POP INC CALL CALL

HL,DE HL,HL HL,DE HL,HL AF 30H E,A D,00H HL,DE DE,HL HL 1E5EH Z,1B61H 1E46H HL 10H NZ HL HL,(40B1H) A,L E E,A A,H A,D D,A C,197AH HL,(40F9H) BC,0028H HL,BC 18H NC,197AH DE,HL (40A0H),HL HL 1B61H Z,1B5DH 41C7H 1B61H BC,1D1EH 1EC1H C,03H 1963H BC HL HL HL,(40A2H) (SP),HL A,91H AF SP BC 1E5AH 1F07H HL HL,(40A2H) 18H HL HL C,1B2FH NC,1B2CH

-------------------------------------------------------------------------------------------------------------------------

DE * 2 DE * 4 DE * 5 HE = DE * 10(base 10) Get last ASCII digit Convert it to binary and save in E register DE = 0000 thru 0009 (binary equiv of digit) Add latest digit to total so far DE = 10(base 10) * DE + A Restore ptr to next digit Process next digit Jmp if no byte count *********** CLEAR routine *** Get number of bytes into DE Backspace code string addr Examine next char in input stream Exit if not end of line Save current code string ptr Top of memory ptr into HL DE = no. of bytes to reserve for string Subtract LSB of n from top of mem. ptr Save diff of LSB's Get MSB of top of memory ptr Subtract MSB of n from top of mem. ptr Save diff in D OM error if trying to clear more bytes than HL = end of pgm ptr : available BC = min. amt of variable space needed Plus end of pgm ptr gives earliest string area Compare to start of string area addr OM error if string list overlays variable list HL = new start of string area addr Load start of string ptr Restore code string ptr Join common code at RUN subroutine Jmp if no line specified ******* RUN routine **** DOS Exit (JP 5F78) Go initialize RUN time variables Continuation addr in execution driver :number Use GOTO code to begin execution at specified line Make sure there are at least *** GOSUB routine *** 6 bytes of available memory BC = rtn addr in execution driver Save code string addr and create a hole which will be filled later HL = binary value for current line no. Store in hole on stack. Restore code string Save a 145 on stack :pointer as a GOSUB marker Backspace stack ptr over status flags Save rtn addr in execution driver. Use GOTO code Get line no. to branch to in DE **** GOTO routine* Skip to end of this line Save code string addr, next line HL = binary equivalent of last line no. Compare target line no. With current line no. Restore code string addr Target line is forward : Locate line # speciTarget line is backwards : fied in DE

221

lE7A

* *************************************************************

1EA3

* ************************************************************

1EB1

* ************************************************************

1EC2

* ************************************************************

222

1ED5 1ED6 1ED7 1ED8 1ED9 1EDB 1EDE 1EDF 1EE1 1EE4 1EE5 1EE8 1EEA 1EEC 1EEF 1EF0 1EF3 1EF4 1EF5 1EF6 1EF8 1EFB 1EFC 1EFF 1F02 1F03 1F05 1F08 1F09 1F0B 1F0C 1F0D 1F0E 1F0F 1F10 1F11 1F12 1F13 1F14 1F16 1F18 1F1A 1F1C 1F1D 1F1E 1F1F 1F21 1F24 1F25 1F26 1F27 1F2A 1F2B 1F2C 1F2D 1F2E 1F31 1F32 1F33 1F35

60 69 2B D8 1E0E C3A219 C0 16FF CD3619 F9 22E840 FE91 1E04 C2A219 E1 22A240 23 7C B5 2007 3ADD40 B7 C2181A 211E1D E3 3EE1 013A0E 00 0600 79 48 47 7E B7 C8 B8 C8 23 FE22 28F3 D68F 20F2 B8 8A 57 18ED CD0D26 CF D5 EB 22DF40 EB D5 E7 F5 CD3723 F1 E3 C603 CD1928

LD LD DEC RET LD JP RET LD CALL LD LD CP LD JP POP LD INC LD OR JR LD OR JP LD EX LD LD NOP LD LD LD LD LD OR RET CP RET INC CP JR SUB JR CP ADC LD JR CALL RST PUSH EX LD EX PUSH RST PUSH CALL POP EX ADD CALL

H,B L,C HL C E,0EH 19A2H NZ D,0FFH 1936H SP,HL (40E8H),HL 91H E,04H NZ,19A2H HL (40A2H),HL HL A,H L NZ,1EFFH A,(40DDH) A NZ,1A18H HL,1D1EH (SP),HL A,0E1H BC,0E3AH B,00H A,C C,B B,A A,(HL) A Z B Z HL 22H Z,1F0BH 8FH NZ,1F0EH B A,D D,A 1F0EH 260DH 08H DE DE,HL (40DFH),HL DE,HL DE 20H AF 2337H AF (SP),HL A,03H 2819H

--- On exit BC = addr of requested line no. --- Move addr of target line code string to HL --- Backspace to start of line --- Rtn to execution driver. Start executing new line --- UL error. Line number not found --- Output UL error message --- Syntax error if RETURN XX *** RETURN routine ***** --- Set DE to dummy addr for search routine cont --> --- Backspace stack ptr 4 bytes. Load value into A --- Set stack ptr to backspaced addr --- Save backspacd stack addr --- And look for GOSUB marker --- RG error if RETURN without GOSUB --- Print error message --- HL = binary line no. of GOSUB call --- Save as current line no. --- Bump to next line --- Make sure line no. has not --- overflowed --->: Jmp if no overflow -- : Else we may have a one line pgm -- : Get INPUT PHASE flag and test it -- : Jmp if still in INPUT PHASE <---: HL = rtn addr in execution driver --- Save on stack. HL=code string addr of GOSUB call --- 1F04: POP HL Now scan to end of GOSUB cont--> --- ********************************** DATA routine --- 1F07 LD C,00 Set stop scan char to 00 --- B =00 <---: Save original stop scan char : Reset stop scan char to 00 : B = stop scan value <---:-: Get an element from code string : : Test for end of line : : Exit if end of line : : Test for stop scan char : : Exit if stop scan encountered : : Bump to next element on code string : : Test for quote --->: : If quote, reset stop scan value to (00) : Not quote, test for IF token ----->: Jump if not 'IF' token -: A = 0, if B = 0 then CARRY = 0 and -: Add instr does not change value of D, -: if B <>, then CARRY = 1 and D is ----->: bumped by one loop. --- Get addr of variable into DE *** LET routine ***** --- Test if par name followed by = , if not error --- 1F25: DC D5 '=' --- Addr of variable name to HL --- Save addr of assignment variable --- Restore addr of next input of variable to HL --- Save addr of variable --- Determine data type --- Save type/flags. see note--> --- Evaluate expression. Save result as current --- Restore data to parity A :variable --- Push current code sting addr onto stack. cont--> --- Restore data to 2-I, 3-ST, 4-SN, 8-DB --- Convert result to proper mode

223

1EDE 1EDF

* ********************************************************** : and A - 1 for scan routine

1F03 1F05

: statement & rtn to execution driver * Set stop scan char to : ************************************* : Search code string until an end : if line (00) is found or a stop : scan value of (00) or (:) occurs : For quotes or 'IF' tokens perform : he following : quote - unconditionally reset : stop scan char to (00) : IF token : stop scan char = 00 : do nothing : stop scan char = : : increment D - reg by : one

1F21

* *************************************************************

1F2D

: A = -1(integer), 0(string), 1(single), 5(double)

1F32

: HL = addr of variable

224

1F38 1F3B 1F3C 1F3E 1F41 1F42 1F43 1F44 1F45 1F46 1F49 1F4A 1F4C 1F4F 1F50 1F51 1F53 1F56 1F57 1F59 1F5B 1F5E 1F5F 1F62 1F65 1F66 1F69 1F6A 1F6B 1F6C 1F6E 1F70 1F71 1F72 1F73 1F76 1F77 1F78 1F7A 1F7D 1F7E 1F7F 1F80 1F83 1F84 1F87 1F88 1F89 1F8C 1F8D 1F8E 1F91 1F92 1F95 1F98 1F99 1F9A 1F9C 1F9E 1F9F

CD030A E5 2028 2A2141 E5 23 5E 23 56 2AA440 DF 300E 2AA040 DF D1 300F 2AF940 DF 3009 3ED1 CDF529 EB CD4328 CDF529 E3 CDD309 D1 E1 C9 FE9E 2025 D7 CF 8D CD5A1E 7A B3 2809 CD2A1B 50 59 E1 D2D91E EB 22F040 EB D8 3AF240 B7 C8 3A9A40 5F C3AB19 CD1C2B 7E 47 FE91 2803 CF 8D

CALL PUSH JR LD PUSH INC LD INC LD LD RST JR LD RST POP JR LD RST JR LD CALL EX CALL CALL EX CALL POP POP RET CP JR RST RST ADC CALL LD OR JR CALL LD LD POP JP EX LD EX RET LD OR RET LD LD JP CALL LD LD CP JR RST ADC

0A03H HL NZ,1F66H HL,(4121H) HL HL E,(HL) HL D,(HL) HL,(40A4H) 18H NC,1F5AH HL,(40A0H) 18H DE NC,1F62H HL,(40F9H) 18H NC,1F62H A,0D1H 29F5H DE,HL 2843H 29F5H (SP),HL 09D3H DE HL 9EH NZ,1F95H 10H 08H A,L 1E5AH A,D E Z,1F83H 1B2AH D,B E,C HL NC,1ED9H DE,HL (40F0H),HL DE,HL C A,(40F2H) A Z A,(409AH) E,A 19ABH 2B1CH A,(HL) B,A 91H Z,1FA1H 08H A,L

-------------------------------------------------------------------------------------------------------------------------

Move result to 'current' value area Save addr of variable Jmp if result is not string HL = Pointer to string entry Save it on stack Skip over length E = LSB of string addr Bump to MSB of addr D = MSB of string addr HL = start of pgm ptr Compare stack of pgm ptr to addr of string Jmp if string precedes program :variable HL = string data ptr Compare string addr to lower boundary of string DE = addr of string pointer : area Jmp if not in string area HL = end of pgm ptr Compare string addr to end addr of PST Jmp if string is a literal in the program 1F5A: POP DE DE = pointer to string entry Backspace to prior literal string pool entry DE = address of string entry in string list area Move string to permanent string area Backspace lit. string pool table one entry Load ptr to string entry from stack Move answer to assigned variable location DE = addr of assigned variable HL = code string address Rtn to caller Test token for 'ERROR' **** ON routine *********** Jmp if not ON ERROR Examine next char in input buffer **** ON ERROR ** Test if it is a '8D' if it is then GO TO token Convert following constant to binary. Result in DE Test if ON ERROR GOTO 0000 Clear ON ERROR Combine LSB & MSB of addr :condition Jmp if GOTO addr is zero Locate address of line # in basic pgm list Move addr of basic stmt to DE E = LSB of addr HL = current position in input stream. cont--> UL error if line number not found HL = addr of basic line to GOTO. cont--> 40F0 = addr of statement to resume execution at Restore code string addr to HL Rtn to execution driver if not GOTO 0000, else Get error message override all :fall thru Set status flags Rtn to execution driver if override flag not set else get error code & move it to E register Go to error routine Get n value into DE ****************************** A = next token from code string Save token : ON n GOTO Test for GOSUB token : ON n GOSUB Jump if 'ON n GOSUB' Test for GOTO token DC '8D' - GOTO token

225

1F6C 1F70

* ************************************************************* * *************************************************************

1F7F 1F83

: HL was saved in 1B2A : DE = position in current line

1F95

* *************************************************************

226

1FA0 1FA1 1FA2 1FA3 1FA4 1FA7 1FAA 1FAC 1FAD 1FAF 1FB2 1FB3 1FB4 1FB7 1FB8 1FBB 1FBC 1FBD 1FBF 1FC1 1FC4 1FC5 1FC6 1FC7 1FCA 1FCB 1FCD 1FCE 1FCF 1FD2 1FD3 1FD6 1FD9 1FDA 1FDB 1FDC 1FDD 1FDF 1FE0 1FE1 1FE2 1FE3 1FE4 1FE5 1FE6 1FE7 1FEA 1FED 1FEE 1FF1 1FF4 1FF7 1FF8 1FF9 1FFC 1FFD 1FFE 1FFF 2001 2003

2B 4B 0D 78 CA601D CD5B1E FE2C C0 18F3 11F240 1A B7 CAA019 3C 329A40 12 7E FE87 280C CD5A1E C0 7A B3 C2C51E 3C 1802 D7 C0 2AEE40 EB 2AEA40 22A240 EB C0 7E B7 2004 23 23 23 23 23 7A A3 3C C2051F 3ADD40 3D CABE1D C3051F CD1C2B C0 B7 CA4A1E 3D 87 5F FE2D 3802 1E26

DEC LD DEC LD JP CALL CP RET JR LD LD OR JP INC LD LD LD CP JR CALL RET LD OR JP INC JR RST RET LD EX LD LD EX RET LD OR JR INC INC INC INC INC LD AND INC JP LD DEC JP JP CALL RET OR JP DEC ADD LD CP JR LD

HL C,E C A,B Z,1D60H 1E5BH 2CH NZ 1FA2H DE,40F2H A,(DE) A Z,19A0H A (409AH),A (DE),A A,(HL) 87H Z,1FCDH 1E5AH NZ A,D E NZ,1EC5H A 1FCFH 10H NZ HL,(40EEH) DE,HL HL,(40EAH) (40A2H),HL DE,HL NZ A,(HL) A NZ,1FE3H HL HL HL HL HL A,D E A NZ,1F05H A,(40DDH) A Z,1DBEH 1F05H 2B1CH NZ A Z,1E4AH A A,A E,A 2DH C,2005H E,26H

--- Backspace code string pointer to GOTO token --- C = n value from ON n <---: Decrement n : A = GOSUB or GOTO token : We have skipped n lines rtn to execution driver : Get line no. to GOTO into DE as a binary number : Look for comma following line number else it's : Return if no comma : end of stmt --->: Loop till n line numbers have been skipped --- Get addr of error flag ******* RESUME routine **** --- Load error flag (FF if error, zero otherwise) --- Set status flag --- Error if resume executed w/o error --- Set error flag to zero --- Save it --- Reset error flag --- Get next element from code string --- Test for NEXT token --->: Jump if 'RESUME NEXT' -- : Get binary equiv. of line no. into DE -- : Rtn to EXECUTION DRIVER if no line number -- : Combine LSB and MSB of -- : line number and test for 0 -- : Continue at GOTO if RESUME XXXX -- : Else RESUME 0. Set A = 1 to signal resume 0 ----:>: Jmp to RESUME 0 code <---: : RESUME NEXT test for multiple stmt -: Rtn to execution driver if :, else fall thru <-----: to get addr. of cont--> **** RESUME 0 ***** --- Save in DE --- 40EA = line no. of statement following error --- Which is where we will resume execution --- Restore addr. of current pos. in line cont--> --- Go to EXECUTION DRIVER if RESUME 0 --- Else, we have a RESUME NEXT --- Test for end of line --->: Jmp if not end of line -- : End of line, skip over zero byte terminator -- : Skip over -- : Pointer to next statement -- : Skip over line number in binary for <---: line following error --- DE = line no. of stmt following error --- Test for end of program --- Gives 0 if end of program --- Not end of pgm. Skip to end of line w/error & --- Get INPUT PHASE entered flag :continue --- Test for INPUT PHASE started --- Not started - Go to it --- Skip to end of statement before returning --- ERROR routine **** Evaluate n if ERROR n ********* --- Rtn if not end of statement --- Set status flags for error no. --- FC error if n is zero --- n = n - 1 --- n = 2 (n - 1) --- Save doubled error no. in E --- Compare with 45 (base 10) --- Jmp if error no. in range ( < +45) --- UE error code

227

1FAF

* *************************************************************

1FCF

* curr pos. in line w/error ***********************************

1FD9

: w/error in case we rtn to execution driver

1FF4

* ************************************************************

228

2005 2008 200B 200C 200E 2011 2012 2013 2015 2016 2017 2018 2019 201C 201D 201F 2022 2025 2026 2027 2028 202B 202E 2031 2032 2035 2036 2039 203C 203D 203F 2042 2044 2047 2048 2049 204C 204D 204F 2050 2053 2056 2058 205B 205C 205D 205E 2060 2062 2063 2065 2067 2069 206C 206F 2072 2074 2076 2079 207B

C3A219 110A00 D5 2817 CD4F1E EB E3 2811 EB CF 2C EB 2AE440 EB 2806 CD5A1E C29719 EB 7C B5 CA4A1E 22E440 32E140 E1 22E240 C1 C3331A CD3723 7E FE2C CC781D FECA CC781D 2B E5 CD9409 E1 2807 D7 DAC21E C35F1D 1601 CD051F B7 C8 D7 FE95 20F6 15 20F3 18E8 3E01 329C40 C39B20 CDCA41 FE40 2019 CD012B FE04 D24A1E

JP LD PUSH JR CALL EX EX JR EX RST INC EX LD EX JR CALL JP EX LD OR JP LD LD POP LD POP JP CALL LD CP CALL CP CALL DEC PUSH CALL POP JR RST JP JP LD CALL OR RET RST CP JR DEC JR JR LD LD JP CALL CP JR CALL CP JP

19A2H DE,000AH DE Z,2025H 1E4FH DE,HL (SP),HL Z,2026H DE,HL 08H L DE,HL HL,(40E4H) DE,HL Z,2025H 1E5AH NZ,1997H DE,HL A,H L Z,1E4AH (40E4H),HL (40E1H),A HL (40E2H),HL BC 1A33H 2337H A,(HL) 2CH Z,1D78H 0CAH Z,1D78H HL HL 0994H HL Z,2056H 10H C,1EC2H 1D5FH D,01H 1F05H A Z 10H 95H NZ,2058H D NZ,2058H 204FH A,01H (409CH),A 209BH 41CAH 40H NZ,208FH 2B01H 04H NC,1E4AH

--- Output error message --- AUTO routine ** Default starting line no. is 10 --- Save starting line number --- No parameters specified, use defaults --- Convert 1st parameter from ASCII to binary --- Save user specified starting line in HL --- Then exchange it with 10 on the stack --- Jmp if only one parameter specified --- DE - 10 --- Test for comma following 1st parameter --- DC 2C ',' comma --- DE = current code stmt addr --- HL = previous auto increment value --- DE = previous value, HL = code string addr --- Jmp if no 2nd parameter --- Convert 2nd parameter - increment value --- SN error if NZ --- HL = auto increment value --- Test auto increment --- for zero --- FC error if Z --- Auto increment --- Set auto increment flag for BASIC --- HL = starting line number --- Current input line number --- Clear stack --- Rtn to INPUT PHASE --- Evaluate expression *************** IF *********** --- Was element following --- Expression a comma --- Yes, get next element --- And test for 'THEN token --- If 'THEN' token skip ahead so backspace below will --- leave us positioned at THEN token, else it leaves --- us positioned at element following expression --- Test for true/false condition --- Restore addr of current position in stmt --->: If zero expression was false, look for ELSE or <---:---: end of line. Examine next element in code -- : : If numeric must be GOTO address :stmt string -- : : Rtn to execution driver to evaluate rest of <---: : Count times to scan to end of line * cont -> <---: : Scan to end of line : : A = stop scan value : : Rtn to BASIC if end of line : : Get next element : : And test for ELSE token --->: : If not ELSE token scan again : : Match IF's and ELSE's --->: : Loop till all ELSE's passed ------->: Execute remainder of statement --- A=device code for printer *** LPRINT routine **** --- Save in current device type loc. --- Go analyze rest of statement --- DOS Exit (JP 5A15) ********************** PRINT@ ** --- Test next element for @ token --- Jump if not PRINT@ --- Evaluate @ expression.*** PRINT@ routine ********* --- A = MSB test for @ value > 1023 --- FC error if @ position > 1023

229

2008

* *************************************************************

2039

* *************************************************************

2056

* False path of IF statement **********************************

2067

* *************************************************************

206E

* *************************************************************

2076

* *************************************************************

230

207E 207F 2082 2083 2086 2087 2089 208C 208D 208E 208F 2091 2093 2096 2098 209B 209C 209D 20A0 20A3 20A5 20A8 20AA 20AD 20AE 20B0 20B3 20B5 20B8 20B9 20BC 20BD 20BE 20C0 20C3 20C6 20C9 20CC 20CF 20D0 20D3 20D5 20D8 20D9 20DB 20DD 20E0 20E1 20E4 20E5 20E6 20E9 20EC 20EE 20F1 20F2 20F5 20F6 20F9 20FC

E5 21003C 19 222040 7B E63F 32A640 E1 CF 2C FE23 2008 CD8402 3E80 329C40 2B D7 CCFE20 CA6921 FEBF CABD2C FEBC CA3721 E5 FE2C CA0821 FE3B CA6421 C1 CD3723 E5 E7 2832 CDBD0F CD6528 CDCD41 2A2141 3A9C40 B7 FAE920 2808 3A9B40 86 FE84 1809 3A9D40 47 3AA640 86 B8 D4FE20 CDAA28 3E20 CD2A03 B7 CCAA28 E1 C39B20 3AA640 B7

PUSH LD ADD LD LD AND LD POP RST INC CP JR CALL LD LD DEC RST CALL JP CP JP CP JP PUSH CP JP CP JP POP CALL PUSH RST JR CALL CALL CALL LD LD OR JP JR LD ADD CP JR LD LD LD ADD CP CALL CALL LD CALL OR CALL POP JP LD OR

HL HL,3C00H HL,DE (4020H),HL A,E 3FH (40A6H),A HL 08H L 23H NZ,209BH 0284H A,80H (409CH),A HL 10H Z,20FEH Z,2169H 0BFH Z,2CBDH 0BCH Z,2137H HL 2CH Z,2108H 3BH Z,2164H BC 2337H HL 20H Z,20F2H 0FBDH 2865H 41CDH HL,(4121H) A,(409CH) A M,20E9H Z,20DDH A,(409BH) A,(HL) 84H 20E6H A,(409DH) B,A A,(40A6H) A,(HL) B NC,20FEH 28AAH A,20H 032AH A Z,28AAH HL 209BH A,(40A6H) A

-------------------------------------------------------------------------------------------------------------------------

Stack = current code string addr HL = Display area ptr HL = start of display area + @ position Store cursor position in display DCB E = position within line Not to exceed 63 and save it as Update cursor offset Restore code string addr (pointer to item list) Make sure a , follows @ expression DC 2C ',' Look for # token Jmp if not PRINT# Analyze rest of string ****** PRINT # ** cont--> * Set write to cassette flag Cassette flag (= -1) Backspace over previous symbol in input stream *** Re-examine next char in input stream If zero print a CR (end of statement) cont--> Write sync bytes if PRINT, clear output Device flag (409C), and rtn to execution Jump if print using :driver Test for TAB token Jump if print tab Print item list ************* PRINT # ** cont--> * Test for comma If comma, get next item Test for semi-colon If semicolon BC = current addr in input stream Get addr or value of next item to be printed Save addr of terminal symbol Determine data type If string Convert binary to ASCII and move to print buffer Build a literal string pool entry for ASCII number DOS Exit (JP 5B9A) HL = addr of current print string A = output device flag Test device type flag Jmp if writing to cassette (PRINT#) Jmp if not LPRINT A = current line position *** LPRINT continued ***' Add no. chars in new line and test for line overflow Go test results of comparison Get size of display line *** PRINT ITEM continued * Move it to B so we can compare it Get cursor offset for current line Add length of new line and compare to maximum line size :line If NC, new line will overflow buffer. Skip to new Write line to ****** PRINT# continued ** cont--> * A = ASCII space Print a space. Rtn w/a non-zero Set status flags If current data type is string, write it output Restore current code string addr to HL :device and loop till end of statement (E05) A = cursor offset from current line **** cont--> * Set status flags

231

2093

* Open device *************************************************

209B 209D

* ************************************************************* : Flush line to device

20AD

* Save current position in input stream ***********************

20D5

* *************************************************************

20DD

* *************************************************************

20E9

* current output device ***************************************

20F9

* Position video to next line *********************************

232

20FD 20FE 2100 2103 2106 2107 2108 210B 210E 210F 2112 2114 2117 2119 211B 211E 2120 2123 2126 2127 212A 212B 212E 2130 2132 2134 2135 2137 213A 213C 213D 213E 213F 2140 2141 2144 2147 2148 214B 214E 2151 2153 2156 2157 2158 215A 215B 215C 215E 2161 2162 2164 2165 2166 2169 216C 216D 2170 2171 2174

C8 3E0D CD2A03 CDD041 AF C9 CDD341 3A9C40 B7 F21921 3E2C CD2A03 184B 2808 3A9B40 FE70 C32B21 3A9E40 47 3AA640 B8 D4FE20 3034 D610 30FC 2F 1823 CD1B2B E63F 5F CF 29 2B E5 CDD341 3A9C40 B7 FA4A1E CA5321 3A9B40 1803 3AA640 2F 83 300A 3C 47 3E20 CD2A03 05 20FA E1 D7 C3A020 3A9C40 B7 FCF801 AF 329C40 CDBE41

RET LD CALL CALL XOR RET CALL LD OR JP LD CALL JR JR LD CP JP LD LD LD CP CALL JR SUB JR CPL JR CALL AND LD RST ADD DEC PUSH CALL LD OR JP JP LD JR LD CPL ADD JR INC LD LD CALL DEC JR POP RST JP LD OR CALL XOR LD CALL

Z A,0DH 032AH 41D0H A 41D3H A,(409CH) A P,2119H A,2CH 032AH 2164H Z,2123H A,(409BH) 70H 212BH A,(409EH) B,A A,(40A6H) B NC,20FEH NC,2164H 10H NC,2130H 215AH 2B1BH 3FH E,A 08H HL,HL HL HL 41D3H A,(409CH) A M,1E4AH Z,2153H A,(409BH) 2156H A,(40A6H) A,E NC,2164H A B,A A,20H 032AH B NZ,215EH HL 10H 20A0H A,(409CH) A M,01F8H A (409CH),A 41BEH

--- Exit if at start of a line --- Else skip to next line --- Call video driver --- DOS exit (JP 5B99) --- Clear A-reg status flags/carry flag --- Rtn to caller --- DOS Exit (JP 5B65) ****** PRINT on cassette ****** --- Get current output device --- and test for type --- Jmp if current device not cassette --- A = ASCII comma --- Print comma on printer or display --- Go fetch next char from code string --- Jmp if current device is video display *********** --- Device is printer. Get current print pos in A --- Compare print pos to 112 --- Go test if time for line skip --- A = line size ************************************ --- Save in B --- A = current pos in line --- Test if room in this line. Subtract cont--> --- No, issue a line skip. We are at end of line --- Jmp if end of line marked --- Test for at least 10 print positions left --- Loop till positions to within 10 spaces of end of --- Gives - number of blanks to print :line --- Go print blanks --- Get TAB no., * PRINT TAB processing **** cont--> * --- Results in A. Do not let it exceed 63 --- Save TAB value in B --- Look for closing paren --- DC ',' --- Reposition code string printer to --- and save addr on stack --- DOS Exit (JP 5B65) --- A = output device type code --- Test device type code --- FC error if negative (tape) -->: Jmp if output device video -- : A = print position in current line ---:->: Skip reload of A register <--: : A = cursor position in current video line <-----: A = -current position --- A = -current position + tab --->: Jmp if tab less than current position -- : A = number of blanks to print -- : B = count of blanks to print -- : A = ASCII blank <-: : Print a blank : : Count it ->: : Loop till B blanks printed <---: Restore position in input string -- Examine next character --- Process rest of PRINT TAB statement --- A = device type code ******************* cont--> * --- Test for cassette --- Turn off cassette --- Clear A and status flags --- and reset current device code to display --- DOS Exit (JP 577C)

233

2108

* *************************************************************

2119

* *************************************************************

2123

* *************************************************************

212A

: line size from current position

2137

* evaluate expression ****************************************

2169

* Turn off cassette and reset current device to video ********

234

2177 2178 2179 217A 217B 217C 217D 217E 217F 2182 2183 2186 2189 218A 218C 218F 2190 2193 2196 2199 219A 219D 219E 21A1 21A3 21A6 21A7 21A9 21AC 21AD 21AF 21B2 21B5 21B6 21B7 21B9 21BB 21BD 21BE 21C0 21C3 21C6 21C7 21C9 21CC 21CD 21CF 21D0 21D3 21D4 21D5 21D6 21D9 21DA 21DB 21DC 21DF 21E0 21E3 21E4

C9 3F 52 45 44 4F 0D 00 3ADE40 B7 C29119 3AA940 B7 1E2A CAA219 C1 217821 CDA728 2AE640 C9 CD2828 7E CDD641 D623 32A940 7E 2020 CD9302 E5 06FA 2AA740 CD3502 77 23 FE0D 2802 10F5 2B 3600 CDF801 2AA740 2B 1822 01DB21 C5 FE22 C0 CD6628 CF 3B E5 CDAA28 E1 C9 E5 CDB31B C1 DABE1D 23 7E

RET CCF LD LD LD LD DEC NOP LD OR JP LD OR LD JP POP LD CALL LD RET CALL LD CALL SUB LD LD JR CALL PUSH LD LD CALL LD INC CP JR DJNZ DEC LD CALL LD DEC JR LD PUSH CP RET CALL RST DEC PUSH CALL POP RET PUSH CALL POP JP INC LD

D,D B,L B,H C,A C A,(40DEH) A NZ,1991H A,(40A9H) A E,2AH Z,19A2H BC HL,2178H 28A7H HL,(40E6H) 2828H A,(HL) 41D6H 23H (40A9H),A A,(HL) NZ,21C9H 0293H HL B,0FAH HL,(40A7H) 0235H (HL),A HL 0DH Z,21BDH 21B2H HL (HL),00H 01F8H HL,(40A7H) HL 21EBH BC,21DBH BC 22H NZ 2866H 08H SP HL 28AAH HL HL 1BB3H BC C,1DBEH HL A,(HL)

--- Rtn to caller --- 7 *************** REDO error message ************* --- R --- E --- D --- 0 --- Carriage return --- Message terminator --- Get read flag ************************** cont--> * --- Set status flags --- SN error in NNN if READ active --- Get type of input flag --- Test for zero --- FD error code --- Output FD error message if cassette input --- Clear the stack --- Addr of REDO message --- Output REDO message --- Restore code string addr --- Rtn to caller --- Check for illegal direct ***** INPUT routine ***** --- (Input without line number) --- DOS Exit (JP 5784) --- Check for unit designation # --- 40A9 = 0 if INPUT # --- A = next element from code string --->: Jmp if INPUT from console device -- : Find leader and sync bytes -- : Save code string address -- : B = max no. of bytes to read (250) -- : HL = input area ptr <-: : Read 1 byte from tape : : Save byte just read : : Bump to next location in buffer . : Read into buffer until CR : : Jmp if CR encountered ->: : Or loop till 250 bytes read -- : Position to last place in buffer -- : Put a 00H at end and -- : Turn off tape -- : Input buffer addr to HL -- : Backspace one byte -- : And store a comma there so we cont--> <---: Continuation addr of 21 BD ************ note--> * --- to stack --- Look for quote --- Jump to 21DB if not text in input statement --- Quote (text in input statement) cont--> --- Look for a trailing semi-colon --- DC = ',' --- Save code string addr --- Write prompting message --- Restore code string addr --- Go to 21DB --- Save code string address ************************* --- Print '? ' and accept input on exit cont--> --- BC = code string addr --- Jmp if BREAK key entered --- Position to first byte of data in buffer --- Fetch 1st data byte

235

2178

* *************************************************************

217E

* Output read/input error messages ****************************

219A

* *************************************************************

21C7 21C9

: can use READ processing * INPUT item list *********************************************

21D0

: Build lit. string pool entry for quote.

21DB 21DC

* ************************************************************* : HL = buffer addr -1

236

21E5 21E6 21E7 21E8 21EB 21ED 21EF 21F0 21F3 21F5 21F8 21F9 21FB 21FC 21FD 2200 2201 2202 2203 2205 2207 220A 220B 220E 2211 2212 2214 2217 2219 221C 221F 2220 2221 2224 2225 2226 2227 2228 2229 222C 222D 2230 2231 2232 2234 2235 2236 2237 2239 223B 223D 223F 2240 2243 2244 2245 2248 2249 224A 224D

B7 2B C5 CA041F 362C 1805 E5 2AFF40 F6AF 32DE40 E3 1802 CF 2C CD0D26 E3 D5 7E FE2C 2826 3ADE40 B7 C29622 3AA940 B7 1E06 CAA219 3E3F CD2A03 CDB31B D1 C1 DABE1D 23 7E B7 2B C5 CA041F D5 CDDC41 E7 F5 2019 D7 57 47 FE22 2805 163A 062C 2B CD6928 F1 EB 215A22 E3 D5 C3331F D7

OR DEC PUSH JP LD JR PUSH LD OR LD EX JR RST INC CALL EX PUSH LD CP JR LD OR JP LD OR LD JP LD CALL CALL POP POP JP INC LD OR DEC PUSH JP PUSH CALL RST PUSH JR RST LD LD CP JR LD LD DEC CALL POP EX LD EX PUSH JP RST

A HL BC Z,1F04H (HL),2CH 21F4H HL HL,(40FFH) 0AFH (40DEH),A (SP),HL 21FDH 08H L 260DH (SP),HL DE A,(HL) 2CH Z,222DH A,(40DEH) A NZ,2296H A,(40A9H) A E,06H Z,19A2H A,3FH 032AH 1BB3H DE BC C,1DBEH HL A,(HL) A HL BC Z,1F04H DE 41DCH 20H AF NZ,224DH 10H D,A B,A 22H Z,2240H D,3AH B,2CH HL 2869H AF DE,HL HL,225AH (SP),HL DE 1F33H 10H

--- Set status flags --- Backspace to buffer origin -1 --- Save code string addr --- If 1st data char is binary zeroes, cont--> --- Make READ think we are at end of a value in a --- DATA statement --- Save current pos in PST ********* READ routine *** --- HL = starting addr of data stmt --- 21F4 XOR A - Zero A - Signal INPUT, non-zero --- Not 00 if read :signal READ --00 if input HL = rtn addr, stack = DATA addr --->: Join common code -- : Test for a comma -- : 21FC: DC 2C ',' <---: Get address of current variable into DE --- Pop pointer to current location in data statement --- Replace it w/ addr of variable --- Get next char from data statement --- Test for terminal comma --->: Jump if comma -- : A = read flag -- : Test if READ or INPUT processing -- : Jmp if READ - go find next DATA statement -- : Test whether or not a unit -- : Number was specified in INPUT call -- : OD error - no unit no. given in call -- : Output OD message if no unit specified -- : Print '?' sequence error in data cont--> -- : Print ' ' and accept input -- : Accept input from keyboard. Buffer addr -1 in HL -- : DE = address of next variable -- : BC = addr of next element in code string -- : Jmp if BREAK key during input -- : Position to first data byte in buffer -- : Fetch 1st data byte -- : Set status flags -- : Backspace buffer pointer to buffer origin -1 -- : Save code string address -- : No data in buffer skip to end of cont--> -- : Save addr of variable <---: DOS Exit (JP 5E63) --- Test data type --- Save status from data type test --- Go convert data to binary, SP, or DP --- Else we have string data. Examine next char in --- DATA statement --- Save nest char in B, D --- Test for quote --- Jmp if its a quote - string data --- Else scan DATA statement looking --- for a : or , and build a literal --- string pool entry for it --- Create a literal string pool entry for DATA string --- A = flag for destination data type --- Save HL --- Put continuation addr of 225A onto stack --- and clear stack --- Save addr of variable --- move result to target variable, continue at 225A --- Examine next character in DATA stream ** cont--> *

237

21EB

: skip to end of line & rtn to BASIC

21EF

* ***********************************************************

2217

: while processing INPUT statement

2229

: this line & rtn to BASIC

224D

* Convert next value in DATA stmt from ASCII to binary ********

238

224E 224F 2250 2253 2254 2257 225A 225B 225C 225E 2260 2263 2264 2265 2266 2269 226A 226D 226E 226F 2272 2273 2274 2277 2278 227B 227C 227F 2282 2283 2286 2287 2288 2289 228A 228B 228C 228E 228F 2290 2291 2292 2293 2294 2295 2296 2299 229A 229C 229D 229E 229F 22A0 22A2 22A5 22A6 22A7 22A8 22A9 22AA

F1 F5 014322 C5 DA6C0E D2650E 2B D7 2805 FE2C C27F21 E3 2B D7 C2FB21 D1 3AA940 B7 C8 3ADE40 B7 EB C2961D D5 CDDF41 B6 218622 C4A728 E1 C36921 3F 45 78 74 72 61 2069 67 6E 6F 72 65 64 0D 00 CD051F B7 2012 23 7E 23 B6 1E06 CAA219 23 5E 23 56 EB 22DA40

POP PUSH LD PUSH JP JP DEC RST JR CP JP EX DEC RST JP POP LD OR RET LD OR EX JP PUSH CALL OR LD CALL POP JP CCF LD LD LD LD LD JR LD LD LD LD LD LD DEC NOP CALL OR JR INC LD INC OR LD JP INC LD INC LD EX LD

AF AF BC,2243H BC C,0E6CH NC,0E65H HL 10H Z,2263H 2CH NZ,217FH (SP),HL HL 10H NZ,21FBH DE A,(40A9) A Z A,(40DEH) A DE,HL NZ,1D96H DE 41DFH (HL) HL,2286H NZ,28A7H HL 2169H B,L A,B (HL),H (HL),D H,C NZ,22F7H H,A L,(HL) L,A (HL),D H,L H,H C 1F05H A NZ,22AEH HL A,(HL) HL (HL) E,06H Z,19A2H HL E,(HL) HL D,(HL) DE,HL (40DAH),HL

--- Reload flags from data type test --- and resave. Push rtn addr of 2243 onto stack --- to be returned to following DATA conversion --- 2243 to stack --- Go convert ASCII to binary - not DP --- Go convert ASCII to binary - DP --- Backspace one character in DATA stmt ************* --- Examine terminating character --->: Jmp if end of line --- : Not end of line, test for a comma <---: If not a comma go output error message --- HL = next byte in read stmt, stack = next in DATA --- Backspace over terminal character :stmt --- and reexamine it. If non-zero it must be a --- comma. Go process next variable --- Clear stack --- Check for FD error --- Set status flags --- No error, rtn to BASIC --- Get READ/INPUT flag --- Set status flags --- DE = code string addr --- Jmp if READ error --- Save code string addr. Test for INPUT error --- DOS Exit (JP 579C) --- Test for end of input --- EXTRA IGNORED message --- Output message if not end of INPUT --- Restore code string addr --- Turn off cassette, reset output to cont--> --- EXTRA IGNORED *********************************** --- E --- X --- R --- T --- A --- Space I --- G --- N --- 0 --- R --- E --- D --- CR --- Message terminator --- Search for next data statement *** Call DATA ***** --- Scan to end of current DATA line --- Jmp if : terminated line --- Skip over address of next BASIC statement --- Get line number for next --- statement. If its zero, then we've reached --- the end of the program --- OD error if end of program reached before next --- data statement found --- Bump to line no. this line --- and load it into DE --- Bump to MSB of line no. --- DE = binary line no. this statement --- HL = code string for DATA statement --- Save binary line no. of DATA statement

239

225A

* *************************************************************

2283 2286

: video & ret to BASIC * *************************************************************

2296

* *************************************************************

240

22AD 22AE 22AF 22B1 22B3 22B6 22B9 22BC 22BF 22C2 22C5 22C6 22C9 22CA 22CB 22CC 22CD 22CE 22CF 22D0 22D1 22D4 22D7 22D8 22D9 22DC 22DD 22E0 22E1 22E4 22E5 22E8 22EA 22EB 22EC 22ED 22EE 22EF 22F0 22F1 22F2 22F3 22F4 22F5 22F6 22F7 22F8 22F9 22FC 22FF 2301 2304 2305 2306 2307 2308 2309 230A 230B 230C

EB D7 FE88 20E3 C32D22 110000 C40D26 22DF40 CD3619 C29D19 F9 22E840 D5 7E 23 F5 D5 7E 23 B7 FAEA22 CDB109 E3 E5 CD0B07 E1 CDCB09 E1 CDC209 E5 CD0C0A 1829 23 23 23 23 4E 23 46 23 E3 5E 23 56 E5 69 60 CDD20B 3AAF40 FE04 CAB207 EB E1 72 2B 73 E1 D5 5E 23

EX RST CP JR JP LD CALL LD CALL JP LD LD PUSH LD INC PUSH PUSH LD INC OR JP CALL EX PUSH CALL POP CALL POP CALL PUSH CALL JR INC INC INC INC LD INC LD INC EX LD INC LD PUSH LD LD CALL LD CP JP EX POP LD DEC LD POP PUSH LD INC

DE,HL 10H 88H NZ,2296H 222DH DE,0000H NZ,260DH (40DFH),HL 1936H NZ,199DH SP,HL (40E8H),HL DE A,(HL) HL AF DE A,(HL) HL A M,22EAH 09B1H (SP),HL HL 070BH HL 09CBH HL 09C2H HL 0A0CH 2313H HL HL HL HL C,(HL) HL B,(HL) HL (SP),HL E,(HL) HL D,(HL) HL L,C H,B 0BD2H A,(40AFH) 04H Z,07B2H DE,HL HL (HL),D HL (HL),E HL DE E,(HL) HL

--- Restore BASIC statement addr to HL cont--> --- Examine next token --- Test for DATA token --- Jump if not data token keep looking cont--> --- Locate next DATA statement, continue --- In case no index specified **** NEXT routine ***** --- If index given, get its addr into DE --- Save current code string addr --- Locate FOR push on stack, on exit cont--> --- NF error if no FOR push --- Set stack ptr to addr of type/sign push for STEP --- Save CSP in 40E8 :value --- Save addr of index. Overwrite addr of FOR index --- A = sign flag of increment --- Skip over adj. type flag --- Save sign flag --- DE = addr of index --- A = adj. type flag for STEP increment = cont--> --- Backspace to end of STEP increment --- Test adj. type flag for STEP increment --->: Jmp if integer type -- : Load STEP increment from stack cont--> -- : HL = addr of index. Stack = end addr of TO limit -- : Save addr of index -- : Load index into BC/DE and add to current value -- : Restore addr of index to HL -- : Move current value (new index) to its addr -- : HL = ending addr of TO limit -- : Load TO value into BC/DE -- : Save addr of ptr to binary line no for FOR stmt -- : Compare TO value in BC/DE with new cont--> -- : Go examine results of comparison <---: Backspace stack 4 bytes ************************ --- which skips over the area for --- single precision TO value. --- Prepare to fetch an integer increment --- C = LSB of increment --- Bump to MSB --- B = MSB of increment --- HL = stack addr of TO limit --- HL = addr of index. Stack = ending addr of TO limit --- E = LSB of index :on stack --- Bump to MSB --- D = MSB of index --- Save addr of MSB of index --- L = LSB of increment --- H = MSB of increment --- Add value in DE to HL. Sum in HL if integer. --- Get data type flag :index + increment --- Test for single precision --- OV error if single precision --- DE = new index value --- HL = addr of index in variable area --- Save MSB of new index --- Skip down to LSB --- Save LSB of new index --- HL = addr of TO value in FOR push --- Save new index --- E = LSB of TO value --- Bump to MSB

241

22AD

: may be in DATA statement

22B1 22B6

: till DATA or end of pgm * *************************************************************

22BF

: HL = stack addr of type (adj)/sign flag

22CE

: +1 if single precision, -1 if integer

224D

: Save as current value

22E5 22EA

: index in current value * *************************************************************

242

230D 230E 230F 2310 2313 2314 2315 2316 2319 231B 231C 231F 2320 2321 2324 2325 2328 232B 232C 232E 2331 2332 2335 2336 2338 233A 233B 233D 2340 2343 2346 2349 234A 234B 234D 234F 2351 2353 2355 2357 2358 2359 235A 235B 235E 2361 2362 2364 2365 2366 2369 236A 236D 236F 2370 2372 2373 2374 2377 2379

56 23 E3 CD390A E1 C1 90 CDC209 2809 EB 22A240 69 60 C31A1D F9 22E840 2ADF40 7E FE2C C21E1D D7 CDB922 CF 282B 1600 D5 0E01 CD6319 CD9F24 22F340 2AF340 C1 7E 1600 D6D4 3813 FE03 300F FE01 17 AA BA 57 DA9719 22D840 D7 18E9 7A B7 C2EC23 7E 22D840 D6CD D8 FE07 D0 5F 3AAF40 D603 B3

LD INC EX CALL POP POP SUB CALL JR EX LD LD LD JP LD LD LD LD CP JP RST CALL RST JR LD PUSH LD CALL CALL LD LD POP LD LD SUB JR CP JR CP RLA XOR CP LD JP LD RST JR LD OR JP LD LD SUB RET CP RET LD LD SUB OR

D,(HL) HL (SP),HL 0A39H HL BC B 09C2H Z,2324H DE,HL (40A2H),HL L,C H,B 1D1AH SP,HL (40E8H),HL HL,(40DFH) A,(HL) 2CH NZ,1D1EH 10H 22B9H 08H Z,2363H D,00H DE C,01H 1963H 249FH (40F3H),HL HL,(40F3H) BC A,(HL) D,00H 0D4H C,2364H 03H NC,2364H 01H D D D,A C,1997H (40D8H),HL 10H 234DH A,D A NZ,23ECH A,(HL) (40D8H),HL 0CDH C 07H NC E,A A,(40AFH) 03H E

--- D = MSB of TO value --- Bump to addr of line number --- HL = TO value , save addr of line no. on stack --- Compare new index to limit --- HL = addr of binary line no. of FOR stmt --- BC = sign flag of index --- Compare sign of comparison w/sign expected --- Load BC = addr of 1st stmt in loop. cont--> --->: Jmp if index <> to limit -- : HL = binary line no of FOR stmt -- : Save line no. Of FOR stmt -- : Move LSB of 1st loop stmt -- : Move MSB of 1st loop stmt -- : Continue execution. Restore FOR cont--> <---: Restore stack pointer ************* see note--> * --- And save in 40EB --- HL = Code string addr after NEXT I --- Get next token --- Compare with a comma --- Jump if not comma --- Position to next index --- Re-enter and execute NEXT --- Test for left paren in input stream --- 2336: DC 28 Left paren --- 2337: DEC HL --- D = precedence value, E = operator token --- Number of bytes of free memory required --- Check limits of free memory --- Get value of next element in expression cont--> --- Addr of next token --- Re-entry point following a reduction --- BC = DE = precedence value last cont--> --- Get next token (operator or function) --- Clear relational token flag encountered <-----: Test for arithmetic or relational operator --->: : Operator +, -, *, /,up arrow, AND, OR --- : : Test for >, =, < token --->: : Jmp token SGN - MID$ --- : : Set CARRY if >. Test for <=, >= sequence --- : : Adjusted token gives 1(>), 2(=), 4(<) --- : : Test for permissible combinations <=, => --- : : by combining previous adjusted token --- : : with current adjusted token. cont--> --- : : Error if << , >>, or == --- : : Addr of <, -, or > token to 40D8 --- : : Get next token ----:-: Two relationals to be treated as one <---: Get relational operator flag --- Set status flags then --- Jmp if <, =, or > token previously encountered --- A = operator token --- Addr of arithmetic operator to 40D8 --- Test for arithmetic token --- Return if token not arithmetic --- Test for + through OR token --- Rtn if token > through MID$ --- E = 0 - 7 --- Get type flag for current variable --- -1(int), 0(str), 1(sng), 5(dbl) --- Combine op token & type so we can test for

243

2316

: DE = binary line no. of FOR stmnt

2321 2324

: token and GAP for FOR. * Start of expression evaluation ******************************

2340

: If var : addr to 4121, if const : value to 4127

2349

: operand/last operator token * < = > * 4 2 1 * < 4 0 6 5 * = 2 6 0 7 * > 1 5 3 0 * * Relational Table

235A

: Combination must be greater than previous value

* * * * * * * * *

E 0 1 2 3 4 5 6

TOKEN + * / @@ AND OR

244

237A 237D 2380 2381 2382 2383 2384 2385 2386 2389 238A 238B 238D 2390 2392 2395 2398 2399 239C 239D 239E 239F 23A2 23A3 23A4 23A5 23A6 23A9 23AA 23AB 23AC 23AD 23AE 23AF 23B0 23B3 23B4 23B5 23B7 23BA 23BB 23BC 23BD 23BE 23BF 23C0 23C1 23C2 23C3 23C5 23C7 23C8 23C9 23CA 23CD 23CE 23D1 23D4 23D7 23DA

CA8F29 219A18 19 78 56 BA D0 C5 014623 C5 7A FE7F CAD423 FE51 DAE123 212141 B7 3AAF40 3D 3D 3D CAF60A 4E 23 46 C5 FAC523 23 4E 23 46 C5 F5 B7 E2C423 F1 23 3803 211D41 4E 23 46 23 C5 4E 23 46 C5 06F1 C603 4B 47 C5 010624 C5 2AD840 C33A23 CDB10A CDA409 01F213

JP LD ADD LD LD CP RET PUSH LD PUSH LD CP JP CP JP LD OR LD DEC DEC DEC JP LD INC LD PUSH JP INC LD INC LD PUSH PUSH OR JP POP INC JR LD LD INC LD INC PUSH LD INC LD PUSH LD ADD LD LD PUSH LD PUSH LD JP CALL CALL LD

Z,298FH HL,189AH HL,DE A,B D,(HL) D NC BC BC,2346H BC A,D 7FH Z,23D4H 51H C,23E1H HL,4121H A A,(40AFH) A A A Z,0AF6H C,(HL) HL B,(HL) BC M,23C5H HL C,(HL) HL B,(HL) BC AF A PO,23C4H AF HL C,23BAH HL,411DH C,(HL) HL B,(HL) HL BC C,(HL) HL B,(HL) BC B,0F1H A,03H C,E B,A BC BC,2406H BC HL,(40D8H) 233AH 0AB1H 09A4H BC,13F2H

--- String addition --- Table of precedent operator values --- Add local token (0 - 7) --- Compute addr for this operator --- Get precedence value for last operator --- Get precedent value for this operator --- Exit if this operator has higher operator --- Precedence value last operator/token last operator --- Resumption addr in case break in precedence --- To stack --- A = precedence value for this operator --- Test for exponential --- Jmp if exponential --- Test for LOGICAL operators --- Jmp if AND/OR --- HL = addr of binary value for 1st operand --- Clear status flags --- Get data type --- Minus 1 : -1(int), 0(str), 1(sng), 5(dbl) --- Minus 2 --- Minus 3 --- TM error if Z (string) --- Now, load binary value of operator --- C = LSB of value. Bump to MSB --- BC = binary value --- Save binary value --- Jump if integer operand saved --- Else get rest of value --- Into BC and save it on stack also --- C = MSB of SP value --- B = exponent of SP value --- Save rest of digit --- Save type -3 --- Reset status flags so we can test for DP value --->: Jump if not double precision -- : Clear stack -- : Bump to next byte of value -->:: Jmp if rem. of value not in WRA1 -- :: Reset HL to start of WRA1 <--:: Load rest of double precision -- :value and save on stack -- : B = next most LSB -- : Bump to next digit -- : Save LSB/NMSB of DP value -- : then load -- : Middle bytes of -- : DP value in BC -- : and save on stack <---: 23C4: POP AF Clear type -3/status push --- A = type --- Token for arithmetic operator (0 - 7) --- Plus length of operand --- Follow operand on stack --- Addr for reordering operations --- To stack --- Restore HL to addr of last token encountered --- Note DE = precedence value/operator value (0 - 7) --- Convert integer (4121-4122) to SP ****** cont--> * --- Move a SP no. from 4121-4124 to stack --- Addr of SP exponential routine

245

23D4

* and store in 4121 - 4124 ************************************

246

23DD 23DF 23E1 23E2 23E5 23E6 23E7 23EA 23EC 23ED 23EF 23F0 23F1 23F2 23F5 23F8 23F9 23FA 23FD 2400 2401 2404 2406 2407 2408 240B 240C 240E 2410 2413 2415 2418 2419 241A 241C 241F 2420 2422 2425 2428 242B 242D 242E 242F 2430 2431 2432 2433 2436 2437 2438 243B 243E 243F 2442 2443 2446 2447 2448 244B

167F 18EC D5 CD7F0A D1 E5 01E925 18E1 78 FE64 D0 C5 D5 110464 21B825 E5 E7 C29523 2A2141 E5 018C25 18C7 C1 79 32B040 78 FE08 2828 3AAF40 FE08 CA6024 57 78 FE04 CA7224 7A FE03 CAF60A D27C24 21BF18 0600 09 09 4E 23 46 D1 2A2141 C5 C9 CDDB0A CDFC09 E1 221F41 E1 221D41 C1 D1 CDB409 CDDB0A

LD JR PUSH CALL POP PUSH LD JR LD CP RET PUSH PUSH LD LD PUSH RST JP LD PUSH LD JR POP LD LD LD CP JR LD CP JP LD LD CP JP LD CP JP JP LD LD ADD ADD LD INC LD POP LD PUSH RET CALL CALL POP LD POP LD POP POP CALL CALL

D,7FH 23CDH DE 0A7FH DE HL BC,25E9H 23CDH A,B 64H NC BC DE DE,6404H HL,25B8H HL 20H NZ,2395H HL,(4121H) HL BC,258CH 23CDH BC A,C (40B0H),A A,B 08H Z,2438H A,(40AFH) 08H Z,2460H D,A A,B 04H Z,2472H A,D 03H Z,0AF6H NC,247CH HL,18BFH B,00H HL,BC HL,BC C,(HL) HL B,(HL) DE HL,(4121H) BC 0ADBH 09FCH HL (411FH),HL HL (411DH),HL BC DE 09B4H 0ADBH

--- D = precedence value for up arrow --- Continue expression evaluation --- Save precedence value/token ********************** --- Convert current value to an integer, leave in HL --- Restore precedence value/token --- Save current value (integer) --- Logical operator routine address --- Continue syntax analysis --- A = precedence value previous operator * cont--> * --- Compare it with relational AND --- Exit if prior operator was relational --- BC = precedence value previous operator/token --- DE = 6, 5, or 3/token --- DE = precedence value for '<=', '>=' cont--> --- Addr of routine to compare logical quantities --- to stack --- Test data type --- If not string go --- HL = string address. Put variable onto stack --- Save string address on stack --- BC = address of string comparison routine --- Save addr in BC on stk. Continue analyzing stmt --- End of statement or precedence break *** cont--> * --- A = C = token --- 40B0 = arith token of last operand cont--> --- Data type of first operand --- Test data type for first operand --->: Jmp if first operand is double precision -- : No, test current operand -- : Test data type -- : Jump if double precision -- : D = data type current operand -- : A = data type 1st operand -- : Test data type for current operand -- : Jmp if 1st operand single precision -- : A = data type current operand -- : Is it CR string variable -- : TM error if string variable -- : Jump if sng, else integer -- : Compute addr of arith routines -- : As two * arith token -- : plus origin of arith routine addr table -- : gives addr of loc. containing addr cont--> -- : Addr of integer arith routines. C = LSB -- : Bump to next loc. of addr -- : B = MSB of addr of arith routine -- : DE = value of first operand -- : HL = value of current operand -- : Save addr of arith routine on stack for following -- : Go to arith routine :POP <---: Convert current value to DP ******************* --- Convert current value to SP --- Move current value to --- very end of WRA1 --- HL = 2nd most sig. part of DP value --- to near end of WRA1 --- BC/DE = remainder of DP value --- Save BC/DE in upper part of WRA1 --- Move DE to 4121, BC to 4123 --- Convert first value to double precision

247

23E1

* *************************************************************

23EC

* *********************** Relational token routine ************

23F2

: /token (relational sequence)

2406 2408

* BC = data type/ arithmetic token 0 - 7 ********************** : (the one to be performed)

242E

: of arith routine

2438

* *************************************************************

248

244E 2451 2454 2455 2456 2457 2459 245A 245B 245C 245D 245E 245F 2460 2461 2464 2465 2468 246A 246C 246D 2470 2472 2475 2476 2477 247A 247C 247D 2480 2483 2486 2487 248A 248B 248E 2490 2491 2492 2495 2496 2499 249C 249F 24A0 24A2 24A5 24A8 24AB 24AE 24B0 24B2 24B4 24B7 24B9 24BC 24BE 24C1 24C3 24C6

21AB18 3AB040 07 C5 4F 0600 09 C1 7E 23 66 6F E9 C5 CDFC09 F1 32AF40 FE04 28DA E1 222141 18D9 CDB10A C1 D1 21B518 18D5 E1 CDA409 CDCF0A CDBF09 E1 222341 E1 222141 18E7 E5 EB CDCF0A E1 CDA409 CDCF0A C3A008 D7 1E28 CAA219 DA6C0E CD3D1E D24025 FECD 28ED FE2E CA6C0E FECE CA3225 FE22 CA6628 FECB CAC425 FE26

LD LD RLCA PUSH LD LD ADD POP LD INC LD LD JP PUSH CALL POP LD CP JR POP LD JR CALL POP POP LD JR POP CALL CALL CALL POP LD POP LD JR PUSH EX CALL POP CALL CALL JP RST LD JP JP CALL JP CP JR CP JP CP JP CP JP CP JP CP

HL,18ABH A,(40B0H) BC C,A B,00H HL,BC BC A,(HL) HL H,(HL) L,A (HL) BC 09FCH AF (40AFH),A 04H Z,2446H HL (4121H),HL 244BH 0AB1H BC DE HL,18B5H 2451H HL 09A4H 0ACFH 09BFH HL (4123H),HL HL (4121H),HL 2477H HL DE,HL 0ACFH HL 09A4H 0ACFH 08A0H 10H E,28H Z,19A2H C,0E6CH 1E3DH NC,2540H 0CDH Z,249FH 2EH Z,0E6CH 0CEH Z,2532H 22H Z,2866H 0CBH Z,25C4H 26H

-------------------------------------------------------------------------------------------------------------------------

Base addr of double precision routines Get token value. Use it to compute addr of arith Token times 2 :routine Save BC so we can use it for 16 bit arith C = 2 * token B = 0 (Token value * 2) + 18AB = table addr of arith Restore BC :routine Load LSB of arith routine addr Bump to MSB Load MSB of arith routine addr into HL HL = addr of arith routine Jmp to arith routine. Rtn to 2346 Save data type first operand/arith token *cont-->* Move current value to 'saved' area A = data type for other operand Save it and test for single precision Jump if SP, go convert value to DP and do Value must be integer. Pop it from :operation stack, save as current value then go, convert it to double precision and perform operation Convert current operand to single precision ****** Left hand operator to BC and DE Base addr of SP arith routines Go perform operation Load integer operand into HL *********** cont--> Save current SP value on stack Convert integer value in Iii. to SP Load SP equivalent of integer into BC/DE LSB/NMSB of stack SP value to current value MSB/exponent of stack value to current value Go perform operation Save HL so it can be ** INTEGER division * cont-> * Prepare to convert DE to SP Convert DE to SP Restore original HL Move converted DE to stack Convert HL to SP Go do SP division Plus routine examine next symbol ***************** MO error if end of string Output if Z Jump if numeric - convert ASCII to binary Check for letter Go if letter Test for + token Go if + (token) - look for following number Test for decimal point Go if decimal point Test for - token Go if - (token) Test for quote Go if quote. Build a literal string pointer entry Test for not token Go if not (token) Test for &

249

2460

* 1st operand not DP ********* 2nd operand DP *****************

2472

* *************************************************************

247C

* 1st operand is SP **** 2nd operand is integer ***************

2490

* converted later ***-- Convert both values (HL & DE) to SP *** : and use SP division.

249E

* *************************************************************

250

24C8 24CB 24CD 24CF 24D0 24D3 24D4 24D7 24D8 24D9 24DB 24DD 24DE 24DF 24E2 24E5 24E6 24E7 24E9 24EB 24EC 24ED 24EF 24F0 24F2 24F3 24F4 24F5 24F6 24F7 24FA 24FD 24FE 24FF 2501 2504 2506 2509 250B 250E 2510 2513 2515 2518 251A 251D 251F 2522 2524 2527 2529 252C 252F 2530 2531 2532 2534 2537 253A 253B

CA9441 FEC3 200A D7 3A9A40 E5 CDF827 E1 C9 FEC2 200A D7 E5 2AEA40 CD660C E1 C9 FEC0 2014 D7 CF 28CD 0D 26CF 29 E5 EB 7C B5 CA4A1E CD9A0A E1 C9 FEC1 CAFE27 FEC5 CA9D41 FEC8 CAC927 FEC7 CA7641 FEC6 CA3201 FEC9 CA9D01 FEC4 CA2F2A FEBE CA5541 D6D7 D24E25 CD3523 CF 29 C9 167D CD3A23 2AF340 E5 CD7B09

JP CP JR RST LD PUSH CALL POP RET CP JR RST PUSH LD CALL POP RET CP JR RST RST JR DEC LD ADD PUSH EX LD OR JP CALL POP RET CP JP CP JP CP JP CP JP CP JP CP JP CP JP CP JP SUB JP CALL RST ADD RET LD CALL LD PUSH CALL

Z,4194H 0C3H NZ,24D9H 10H A,(409AH) HL 27F8H HL 0C2H NZ,24E7H 10H HL HL,(40EAH) 0C66H HL 0C0H NZ,24FFH 10H 08H Z,24BCH C H,0CFH HL,HL HL DE,HL A,H L Z,1E4AH 0A9AH HL 0C1H Z,27FEH 0C5H Z,419DH 0C8H Z,27C9H 0C7H Z,4176H 0C6H Z,0132H 0C9H Z,019DH 0C4H Z,2A2FH 0BEH Z,4155H 0D7H NC,254EH 2335H 08H HL,HL D,7DH 233AH HL,(40F3H) HL 097BH

-------------------------------------------------------------------------------------------------------------------------

Go if & Test for ERR token Go if not ERR Position to next element in code string Fetch current error number Save current code string addr Save err. no. as current value (integer) Restore code string addr Rtn to expression evaluation Test for ERL ************************************* Go if not ERL Position to next element in code string Save current code string addr Fetch line no. with error Convert line no. to SP & save as current value Restore code string addr Rtn to expression evaluation Test for VARPTR token ************ VARPTR ********* Go if not VARPTR Get next char from code string 24EC: RST 08 - Test next char for left cont--> 24ED: DC 28 - Value for left paren 24EE: CALL 260D - Evaluate variable name 24F1: RST 08 - Test next char for right cont--> 24F2: DC 29 - Value for right paren Save current code string addr Move address of variable to HL Then test for zero address (undefined variable) Combine LSB and MSB of address FC error if variable not defined Save addr as current variable, set type to integer Restore current code string address Return to execution driver Test for USR ************************************* Go if USR Test for INSTR token Go if INSTR : Disk BASIC (JP 582F) Test for MEM token Go if MEM Test for TIME$ token Go if TIME$ Test for POINT token Go if POINT Test for INKEY$ token Go if INKEY$ Test for STRING$ token Go if STRING$ Test for FN token Go if FN : Disk BASIC (JP 558E) Test for SGN to MID$ tokens Jmp if token SGN thru MID$ Token < 215 - better be (. Call pause cont--> Test next char for close paren ')' 2530: DC 29 Value for ')' Rtn to caller Load precedence value ** Binary minus routine **** Evaluate variable Get addr of next element in code string Save addr of where to continue from Invert sign of current value

251

24D9

* ***********************************************************

24E7

* *************************************************************

24EC

: paren & skip over it

24F0

: paren & skip over it

24FF

* *************************************************************

252C

: return when expression exhausted

2532

* *************************************************************

252

253E 253F 2540 2543 2544 2545 2548 2549 254C 254D 254E 2550 2551 2552 2553 2554 2555 2557 2559 255C 255D 255E 2561 2562 2565 2566 2567 2568 256B 256C 256D 256F 2572 2573 2574 2576 2578 257A 257B 257E 257F 2582 2583 2586 2587 2588 2589 258A 258B 258C 258F 2590 2591 2592 2593 2594 2595 2596 2597 259A

E1 C9 CD0D26 E5 EB 222141 E7 C4F709 E1 C9 0600 07 4F C5 D7 79 FE41 3816 CD3523 CF 2C CDF40A EB 2A2141 E3 E5 EB CD1C2B EB E3 1814 CD2C25 E3 7D FE0C 3807 FE1B E5 DCB10A E1 113E25 D5 010816 09 4E 23 66 69 E9 CDD729 7E 23 4E 23 46 D1 C5 F5 CDDE29 D1

POP RET CALL PUSH EX LD RST CALL POP RET LD RLCA LD PUSH RST LD CP JR CALL RST INC CALL EX LD EX PUSH EX CALL EX EX JR CALL EX LD CP JR CP PUSH CALL POP LD PUSH LD ADD LD INC LD LD JP CALL LD INC LD INC LD POP PUSH PUSH CALL POP

HL 260DH HL DE,HL (4121H),HL 20H NZ,09F7H HL B,00H C,A BC 10H A,C 41H C,256FH 2335H 08H L 0AF4H DE,HL HL,(4121H) (SP),HL HL DE,HL 2B1CH DE,HL (SP),HL 2583H 252CH (SP),HL A,L 0CH C,257FH 1BH HL C,0AB1H HL DE,253EH DE BC,1608H HL,BC C,(HL) HL H,(HL) L,C (HL) 29D7H A,(HL) HL C,(HL) HL B,(HL) DE BC AF 29DEH DE

--- Restore code string addr see note--> --- Ret to expression evaluation --- Get addr of variable *************** see note--> * --- Save code string addr --- Addr of variable to HL --- Store it in 4121 --- Determine data type --- Call if numeric data: move numeric value to 4127 --- HL = addr of next symbol in input string --- Rtn to caller --- B = 0 ************************ SNG - MID$ ********* --- A = 2*(token - D7) --- Save new token --- Save 0/2*(token - D7) on stack --- Fetch next character from tokenized string --- Look for SGN - CHR$ token --- Test for adjusted token --->: Jmp if token SGN-CHR$ , else it's LEFT-MID$ -- : Go evaluate expression part of cont--> -- : Test next char for comma -- : 255D: DC 2C comma -- : Insure current variable is a string, else error -- : Make sure current variable is a string. DE = -- : current pos. in pgm stmt. HL = addr of string -- : Move string addr to stack, followed by string -- : Save 00/2*(token - D7) -- : Pgm statement position to HL -- : Evaluate n portion of string function -- : DE = current position in statement. HL = n -- : Move n to stack. HL = 2*(token - D7) -- : Go to action routine for token <---: Evaluate expression. see note--> --- HL = 0 + 2*(token - D7) --- A = 2*(token - D7) --- Test for SNG - SQR --->: Jmp if token SNG - SQR -- : Test adjusted token then -- : Save 0 + 2*(token - D7) and -- : Convert integer in 4121 to SP if token SQR-ATN -- : Restore token to HL <---: Push return addr of 253E onto stack so we can --- return after executing function --- Addr for functions SGN - MID$ --- Add index for required function --- C = LSB of addr of function --- Bump to MSB --- H = MSB of addr of function --- HL = addr of function --- Jmp to SGN - MID$ function --- Make sure string will fit into ********* cont--> * --- A = length --- Bump to LSB of string addr --- Load LSB of string addr --- Bump to MSB of string addr --- BC = string address --- Clear the stack --- Save first string addr --- A = length of first string --- Get addr. of second string into HL --- D = length of first string

253

253E 2540

: Rtn here after executing functions SNG - MID$ * Locate address of variable. Name pointed to by HL **********

254E

* *************************************************************

2559

: calling sequence. 2 or 3 parameter calling sequence.

256E

: Single variable parameter call

258C

: string data area ***** Relational compare two strings *******

254

259B 259C 259D 259E 259F 25A0 25A1 25A2 25A3 25A4 25A5 25A7 25A8 25A9 25AA 25AB 25AC 25AD 25AE 25AF 25B0 25B1 25B2 25B4 25B5 25B8 25B9 25BA 25BB 25BC 25BE 25BF 25C2 25C4 25C6 25C9 25CC 25CD 25CE 25CF 25D0 25D1 25D2 25D5 25D6 25D9 25DC 25DE 25E0 25E2 25E3 25E4 25E5 25E7 25E8 25E9 25EA 25ED 25EE 25EF

5E 23 4E 23 46 E1 7B B2 C8 7A D601 D8 AF BB 3C D0 15 1D 0A BE 23 03 28ED 3F C36009 3C 8F C1 A0 C6FF 9F CD8D09 1812 165A CD3A23 CD7F0A 7D 2F 6F 7C 2F 67 222141 C1 C34623 3AAF40 FE08 3005 D603 B7 37 C9 D603 B7 C9 C5 CD7F0A F1 D1 01FA27

LD INC LD INC LD POP LD OR RET LD SUB RET XOR CP INC RET DEC DEC LD CP INC INC JR CCF JP INC ADC POP AND ADD SBC CALL JR LD CALL CALL LD CPL LD LD CPL LD LD POP JP LD CP JR SUB OR SCF RET SUB OR RET PUSH CALL POP POP LD

E,(HL) HL C,(HL) HL B,(HL) HL A,E D Z A,D 01H C A E A NC D E A,(BC) (HL) HL BC Z,25A1H 0960H A A,A BC B A,0FFH A,A 098DH 25D6H D,5AH 233AH 0A7FH A,L L,A A,H H,A (4121H),HL BC 2346H A,(40AFH) 08H NC,25E5H 03H A

03H A BC 0A7FH AF DE BC,27FAH

--- E = no. of characters in second string --- Bump to LSB of 2nd string addr --- C = LSB of addr. for string 2 --- Bump to MSB of addr. --- BC = address of string 2 --- HL = addr. of string 1 <---: A = remaining characters string 2 : D = remaining characters string 1 : Exit if all characters compared : Reload count of chars remaining string 1 : Test if count is zero : Exit if string 1 exhausted : Clears A-reg : Gives zero - no. of remaining chars string 2 : Test if any char remains in string 2 : Exit if string 2 exhausted : Decrement chars remaining string 1 : Decrement chars remaining string 2 : Compare a character in string 1 with string 2 : Compare : Bump string 1 address : Bump string 2 address --->: Jmp if characters are equal --- Else reverse CARRY flag so 960 will give --- a +1 or -1. Rtn to caller --- Increment value for current operator --- Gives 1 w/NC if 0 or 0 w/C if FF see note--> --- Load value for other operand --- Combine values --- Yields 0 if both equal, CARRY if unequal --- Sets A = 0 if equal, 1 if unequal --- Set current value to 00 if A +, FF if A negative --- Continue with expression evaluation --- D = precedence value * NOT routine * see note--> * --- Evaluate rest of exp until a higher precedence --- Current value to integer --- Result in HL --- Complement LSB of integer --- Restore LSB to HL --- Then load MSB --- Complement MSB of integer --- Restore MSB to HL --- Save complemented number as current value --- Clear the stack --- Continue with expression evaluation --- Load data type for value in WRA1 ******* cont--> * --- Prepare to set data flags -->: Jmp if double precision -- : not DP, subtract 03 -- : then set status flags according to result -- : and exit with -- : CARRY flag set <--: for DP types subtract 03 --- then set status flags according to result --- and exit without CARRY flag set --- B = precision value for last operator ** cont--> * --- Convert current value to integer --- Pop BC into AF --- Return addr to DE --- Place new rtn addr on stack

255

: Compare two logical quantities

25C4

* * Entered from PLUS routine while evaluating *** : * an expression

25D9

* RST 20 routine **********************************************

25E9

: ! : ! : ! : ! : ! : ! : ! * Logical

Data type stored in 40AFH as follows ! TYPE CODE ZERO CARRY NEG PARITY A-REG ! ---- ---- ---- ----- --- ------ --- . ! INT 02 NZ C N E -1 ! STR 03 Z C P E 0 ! SNG 04 NZ C P O 1 ! DBL 08 NZ NC P E 5 ! operator routine - Entered from expression evaluation

256

25F2 25F3 25F5 25F7 25F8 25F9 25FA 25FB 25FC 25FD 25FE 25FF 2600 2601 2602 2603 2604 2605 2606 2607 2608 260B 260C 260E 2611 2612 2615 2618 2619 261A 261B 261D 2620 2622 2623 2624 2626 2629 262B 262E 262F 2631 2633 2634 2635 2637 2638 2639 263B 263C 263E 2640 2641 2642 2644 2646 2647 2649 264A 264D

C5 FE46 2006 7B B5 6F 7C B2 C9 7B A5 6F 7C A2 C9 2B D7 C8 CF 2C 010326 C5 F6AF 32AE40 46 CD3D1E DA9719 AF 4F D7 3805 CD3D1E 3809 4F D7 38FD CD3D1E 30F8 115226 D5 1602 FE25 C8 14 FE24 C8 14 FE21 C8 1608 FE23 C8 78 D641 E67F 5F 1600 E5 210141 19

PUSH CP JR LD OR LD LD OR RET LD AND LD LD AND RET DEC RST RET RST INC LD PUSH OR LD LD CALL JP XOR LD RST JR CALL JR LD RST JR CALL JR LD PUSH LD CP RET INC CP RET INC CP RET LD CP RET LD SUB AND LD LD PUSH LD ADD

BC 46H NZ,25FDH A,E L L,A A,H D A,E L L,A A,H D HL 10H Z 08H L BC,2603H BC 0AFH (40AEH),A B,(HL) 1E3DH C,1997H A C,A 10H C,2622H 1E3DH C,262BH C,A 10H C,2623H 1E3DH NC,2623H DE,2652H DE D,02H 25H Z D 24H Z D 21H Z D,08H 23H Z A,B 41H 7FH E,A D,00H HL HL,4101H HL,DE

--- Save rtn addr on stack --- Is token an 'OR' --->: No, Jmp to comparison routine -- : Comp DE with HL. Result in HL -- : Comp E and L. Result in L -- : Restore L -- : Comp H and D. Result left in A. Will be moved -- : to H at 27FA -- : Go to 27FA. Convert result to integer. Rtn to <---: Logical comp DE with HL. Result in HL. :2346 --- And E and L --- Result to L --- Load H so we can : H at 27FA --- Comp D with H. Result left in A will be moved to --- Goto 27FA. Make result an integer. Rtn to 2346 --- Backspace code string pointer ******************** --- Re-evaluate last symbol --- Exit if end of statement --- Test next char for single quote --- 2607: DC 2C single quote --- Locate addr of a variable ** Force rtn to 2603 ** --- 260C : OR AF Set create mode --- 260D : XOR A Zero A, set 40AE = locate --- Set 40AE = locate/create mode --- Save 1st char of variable name --- Check for letter --- SN error if C (not a letter in (HL) cont--> --- Clear A and C --- Zeros C --- Get next char in input string ----->: Jump if numeric -: Test for alpha-numeric. Set CARRY if false --->: : Jump if not a letter. Error if cont--> <---:-: 2nd char of name to C <-- : Test symbol following 2nd char until a non-->:: numeric symbol is found, cont--> -- :: Test for letter -->:: Jmp if a letter <---: We are now positioned at end of cont--> --- Place 2652H return address on stack --- Test char following name for --- If so, set D to data type 2 --- Return (jump 2652H) if % (INT) : D = 2 --- Ret D to 3 in case variable is a string --- Test for $ following variable name --- Return if $ (STR) : D = 3 --- Ret D to 4 in case variable is SP --- Test for ! following variable name --- Return if ! (SNG) : D = 4 --- Ret D to 8 in case variable is DP --- Test for # following variable name --- Return if # (DBL) : D = 8 cont--> --- Ref etch first char of symbol --- Convert from alpha to numeric (0-26) --- Clear possible sign bit --- E = 0(A) thru 26(Z) --- DE = 0 (A) thru 26(base 10) (Z) --- Save current position in input stream --- Start of data type table --- Add value of first char of var name (0=A,...26=Z)

257

2603

* *******************************************************

2608

* **********************************************************

2615

: Variable name does not start with a letter.

2620

: not a letter, or digit, or (

2624

: Jmp if char is numeric

262E

: variable name. Only 1st two characters are used.

2640

: Variable name was not followed by type suffix. Use 1st char : of var name to determine data type.

258

264E 264F 2650 2651 2652 2653 2656 2657 265A 265B 265E 265F 2661 2664 2665 2668 2669 266A 266D 266E 2671 2672 2673 2675 2676 2677 2678 2679 267B 267C 267D 267F 2680 2681 2682 2685 2687 2688 2689 268B 268C 268E 268F 2690 2691 2692 2693 2696 2697 2699 269C 269D 269E 26A0 26A1 26A2 26A3 26A4 26A5 26A7

56 E1 2B C9 7A 32AF40 D7 3ADC40 B7 C26426 7E D628 CAE926 AF 32DC40 E5 D5 2AF940 EB 2AFB40 DF E1 2819 1A 6F BC 13 200B 1A B9 2007 13 1A B8 CACC26 3E13 13 E5 2600 19 18DF 7C E1 E3 F5 D5 11F124 DF 2836 114325 DF D1 2835 F1 E3 E5 C5 4F 0600 C5

LD POP DEC RET LD LD RST LD OR JP LD SUB JP XOR LD PUSH PUSH LD EX LD RST POP JR LD LD CP INC JR LD CP JR INC LD CP JP LD INC PUSH LD ADD JR LD POP EX PUSH PUSH LD RST JR LD RST POP JR POP EX PUSH PUSH LD LD PUSH

D,(HL) HL HL A,D (40AFH),A 10H A,(40DCH) A NZ,2664H A,(HL) 28H Z,26E9H A (40DCH),A HL DE HL,(40F9H) DE,HL HL,(40FBH) 18H HL Z,268EH A,(DE) L,A H DE NZ,2686H A,(DE) C NZ,2686H DE A,(DE) B Z,26CCH A,13H DE HL H,00H HL,DE 266DH A,H HL (SP),HL AF DE DE,24F1H 18H Z,26CFH DE,2543H 18H DE Z,26D5H AF (SP),HL HL BC C,A B,00H BC

--- Get data type --- Restore pointer to current pos in input stream --- Backspace 1 position --- Return with data type in D (Go to 2652) --- D = data type continuation of locating * cont--> * --- Save data type flag --- Get next char of variable name (call 1D78) --- Get 'FOR' statement flag --- Test it --->: Jmp if processing 'FOR' statement -- : Refetch next element from code string -- : Compare with a ( -- : Jump if '(' (subscripted variable) <---: Zero A-reg --- Flag as non-subscripted --- HL = current position in input string --- Save data type flag --- HL = end of pgm ptr = start of simple var list <-----: DE = addr of a simple variable : Start of arrays pointer : Compare addr of next simple cont--> : HL = data type flag ------:>: Variable not currently defined : : Get type for current variable : : Save in L : : Compare type : : Bump to 2nd char of name for this entry --->: : : Types do not match. Skip to next var in list : : : Type matches, compare 2nd char of name from : : : VLT w/2nd char of name in BC : : : No match, go find next entry in AT : : : 2nd char matches, compare 1st char of name : : : after bumping to 1st char of name : : : Test if first char of names are equal : : : We have found the addr of a simple var, exit <---: : : 2686: INC DE Bump to next entry in simple : : variable list : : Save data type flag so it can be reloaded : : at 2672 : : Bump to next entry in list ----->: : Continue searching for variable name <-------: Save type --- Clear stack, HL = current position in input string --- HL = return addr Stack = current position in input --- A = type :string --- DE = start of arrays ptr --- Addr of VARPTR locator --- Were we called from VARPTR? --- Yes, Jmp to 26CF --- DE = addr of find addr of variable routine --- Were we called from find addr of variable? --- Remove start of arrays ptr from stack --- Called while evaluating a subscript cont--> --- Clear stack, A = type --- HL = current position in input string. --- Stack = Return addr --- Place BC (1st char/2nd char of name) on stack --- followed by ret addr --- Clear B for computations --- Save 00/type. Now create a new entry in cont-->

259

2652

* a variable name *********************************************

2671

: variable to start of array list

269E

: This is the first reference to a simple variable. Define it.

26A7

: free space list for current variable.

260

26A8 26A9 26AA 26AB 26AE 26AF 26B0 26B1 26B2 26B5 26B6 26B9 26BA 26BB 26BE 26BF 26C1 26C2 26C4 26C5 26C6 26C7 26C8 26C9 26CA 26CB 26CC 26CD 26CE 26CF 26D0 26D1 26D2 26D3 26D4 26D5 26D8 26D9 26DA 26DB 26DE 26DF 26E1 26E4 26E7 26E8 26E9 26EA 26ED 26EE 26EF 26F0 26F1 26F4 26F5 26F6 26F7 26F8 26F9 26FA

03 03 03 2AFD40 E5 09 C1 E5 CD5519 E1 22FD40 60 69 22FB40 2B 3600 DF 20FA D1 73 23 D1 73 23 72 EB 13 E1 C9 57 5F F1 F1 E3 C9 322441 C1 67 6F 222141 E7 2006 212819 222141 E1 C9 E5 2AAE40 E3 57 D5 C5 CD451E C1 F1 EB E3 E5 EB 3C

INC INC INC LD PUSH ADD POP PUSH CALL POP LD LD LD LD DEC LD RST JR POP LD INC POP LD INC LD EX INC POP RET LD LD POP POP EX RET LD POP LD LD LD RST JR LD LD POP RET PUSH LD EX LD PUSH PUSH CALL POP POP EX EX PUSH EX INC

BC BC BC HL,(40FDH) HL HL,BC BC HL 1955H HL (40FDH),HL H,B L,C (40FBH),HL HL (HL),00H 18H NZ,26BEH DE (HL),E HL DE (HL),E HL (HL),D DE,HL DE HL D,A E,A AF AF (SP),HL (4124H),A BC H,A L,A (4121H),HL 20H NZ,26E7H HL,1928H (4121H),HL HL HL HL,(40AEH) (SP),HL D,A DE BC 1E45H BC AF DE,HL (SP),HL HL DE,HL A

--- B = 00, C = type --- Gives type +02 --- Gives type +03 = 3 bytes overhead + spare for var --- Load start of free memory ptr (fmp) --- Save free mem ptr --- Free mem ptr + type(length) yields new fmp --- BC = old free mem ptr --- Save new free mem ptr --- Move array list down. Add value to simple --- variable list --- Save new free mem ptr (it's official) --- HL = old fmp = 1st byte of new entry --- L = LSB byte of fmp --- New start of arrays pointer <---: Zero out new entry. All space between the new : free memory pointer and the start of arrays ptr : have we reached the end of the list --->: No, loop --- Get length (type) --- And store as first word in new entry --- Bump to next location of entry --- Get 2nd char of name and store as 2nd word of --- entry --- Bump to 3rd byte of entry --- And now 1st char of name --- DE = addr of start of value in entry --- Leave addr of variable name in DE --- Clear stack before exiting --- Return to caller --- DE = type/type *********************************** --- E = type --- Clear stack --- Clear stack --- Return addr to stk. Code string addr to HL --- Rtn to VARPTR routine --- Zero WRA1 ********* Locate subscripted variable ** --- Clear stack --- Zero H --- and L --- Zero string pointer in WRA1 --- Determine data type ----> Jmp if not a string --- : Addr of READY message --- : goes to WRA1 <---: Restore code string addr --- Rtn to caller --- Current pos in input string ******** see note--> * --- HL = 00 locate mode, <> 0 create mode --- Stack = (40AE), HL = code string addr. --- Zero to D --- D = 0, E = numeric value of 1st char --- BC = 1st char/2nd char of name in ASCII --- Evaluate everything up to the first cont--> --- BC = 1st char/2nd char of name in ASCII --- A = 0 --- DE = current pos in input. End of cont--> --- Stack = value of subscript, (40AE) --- Save current pos in input string --- HL = current pos in input string, DE = (40AE) --- Increment no. of subscripts evaluated

261

26CF

* *************************************************************

26D5

* *************************************************************

26E9

* Locate addr of subscripted var ** On entry: D=type, B=1st char : C = 2nd char of name, : HL = current pos in input : string

26F1

: ) or ,. Result in DE (integer) value

26F6

: subscript exp. HL = value of subscript

262

26FB 26FC 26FD 26FF 2701 2702 2703 2706 2707 270A 270B 270E 2710 2711 2714 2715 2716 2719 271B 271C 271D 271F 2720 2721 2722 2724 2725 2726 2728 2729 272A 272B 272C 272D 272F 2732 2733 2735 2738 2739 273A 273D 273F 2742 2743 2744 2745 2747 2748 2749 274A 274B 274C 274D 2750 2751 2752 2755 2756 2757

57 7E FE2C 28EE CF 29 22F340 E1 22AE40 D5 2AFB40 3E19 EB 2AFD40 EB DF 3AAF40 2827 BE 23 2008 7E B9 23 2004 7E B8 3E23 23 5E 23 56 23 20E0 3AAE40 B7 1E12 C2A219 F1 96 CA9527 1E10 C3A219 77 23 5F 1600 F1 71 23 70 23 4F CD6319 23 23 22D840 71 23 3AAE40

LD LD CP JR RST ADD LD POP LD PUSH LD LD EX LD EX RST LD JR CP INC JR LD CP INC JR LD CP LD INC LD INC LD INC JR LD OR LD JP POP SUB JP LD JP LD INC LD LD POP LD INC LD INC LD CALL INC INC LD LD INC LD

D,A A,(HL) 2CH Z,26EFH 08H HL,HL (40F3H),HL HL (40AEH),HL DE HL,(40FBH) A,19H DE,HL HL,(40FDH) DE,HL 18H A,(40AFH) Z,2742H (HL) HL NZ,2727H A,(HL) C HL NZ,2728H A,(HL) B A,23H HL E,(HL) HL D,(HL) HL NZ,270FH A,(40AEH) A E,12H NZ,19A2H AF (HL) Z,2795H E,10H 19A2H (HL),A HL E,A D,00H AF (HL),C HL (HL),B HL C,A 1963H HL HL (40D8H),HL (HL),C HL A,(40AEH)

--- And save in D --- Get terminal symbol --- Go evaluate next index if terminal symbol was a --- comma, else --- Test next char in input stream for ',' --- 2702: DC 29 ',' --- 40F3 = addr of terminal symbol for subscript exp --- HL = (40AE) before subscript evaluation. Create --- and save for later use. :locate flag. --- DE = number of subscripts evaluated --- Start of arrays pointer <-------: 270F: ADD HL,DE Compute end cont--> : DE = addr of next array :research : Load free memory ptr - upper limit for : HL = arrays ptr. DE = free memory ptr : Compare free mem ptr to array ptr : Data type/length flag ----->: : Jmp if name not found & all arrays tested : : Compare data type of an arrays entry with : : the type we're looking for --->: : : Types don't match. Skip to next array : : : Data types match. Now look for a match on : : : the 2nd character of the name. : : : 2nd char doesn't match. Skip to next array : : : No match, skip to next entry : : : 2nd char matches. : : : Test 1st char. Leave Z flag set if a match : : : 2727: INC HL : : : Bump to next byte in array entry : : : E = LSB of offset to next array : : : Bump to next byte of array entry : : : DE = offset to next array : : : Bump to number of indexes entry ------:>: Named array not found, examine next entry --: 1st char matches. We have found the addr of --: the variable in the arrays list. Are we in a --: create mode? --: Yes, then error. Symbol is doubly defined --: A = number of subscripts evaluated --: Compared to no. specified in DIM statement --: Jmp if no. of indexes match --: BS error code --: Output BS error message <-----: Save type. Build a subscripted variable entry --- Bump to 1st char of name (2nd actually, cont--> --- DE = 00/number of bytes per entry --- D = 00 --- A = number of indexes --- Save 2nd char of name --- Bump to pos for 2nd char of name --- Save 1st char of name --- Bump to LSB of offset to next entry --- C = number of indexes --- Compute amt of space left between HL & free mem. --- Skip over offset entry --- HL = pos for number of indexes in entry --- 40D8 = addr of max number of indices --- Save number of indexes for this array (1,2,or 3) --- HL points to first subscript entry in array table --- A = create/locate flag

263

270E

: of arrays. Search array for named variable

2743

: because they are stored in last/first order)

264

275A 275B 275C 275F 2761 2762 2763 2764 2765 2766 2767 2768 276B 276C 276D 276F 2770 2771 2772 2773 2774 2776 2779 277C 277D 277F 2780 2782 2783 2784 2787 2788 2789 278A 278B 278C 278D 278E 278F 2790 2791 2792 2793 2795 2796 2797 2798 2799 279B 279C 279D 279E 279F 27A0 27A1 27A2 27A5 27A8 27A9 27AA

17 79 010B00 3002 C1 03 71 23 70 23 F5 CDAA0B F1 3D 20ED F5 42 4B EB 19 38C7 CD6C19 22FD40 2B 3600 DF 20FA 03 57 2AD840 5E EB 29 09 EB 2B 2B 73 23 72 23 F1 3830 47 4F 7E 23 16E1 5E 23 56 23 E3 F5 DF D23D27 CDAA0B 19 F1 3D

RLA LD LD JR POP INC LD INC LD INC PUSH CALL POP DEC JR PUSH LD LD EX ADD JR CALL LD DEC LD RST JR INC LD LD LD EX ADD ADD EX DEC DEC LD INC LD INC POP JR LD LD LD INC LD LD INC LD INC EX PUSH RST JP CALL ADD POP DEC

A,C BC,000BH NC,2763H BC BC (HL),C HL (HL),B HL AF 0BAAH AF A NZ,275CH AF B,D C,E DE,HL HL,DE C,273DH 196CH (40FDH),HL HL (HL),00H 18H NZ,277CH BC D,A HL,(40D8H) E,(HL) DE,HL HL,HL HL,BC DE,HL HL HL (HL),E HL (HL),D HL AF C,27C5H B,A C,A A,(HL) HL D,0E1H E,(HL) HL D,(HL) HL (SP),HL AF 18H NC,273DH 0BAAH HL,DE AF A

--- Set carry flag = 0 - locate, 1 - create --- no. of indexes for this array <---: Default index = 10+1 if name not cont--> -->:: Jmp if creating because unable to locate :: Else we are in create mode. Get user :: specified index. Add one <--:: and save :: in the array :: table :: Bump to next set of indices :: Save create/locate flag :: Multiply size of index times bytes per entry. :: Accumulate product in DE. When done cont--> :: Decrement no. of indexes multiplied --->: Jmp if more indexes --- Save create/locate flag --- B = MSB of array length --- BC = length of array in bytes --- DE = start of array - current addr in array table --- HL = end of array --- Error, overflowed 2**16 --- Test amt of free space, rtn if enough --- 40FD = LWA of array <---: Zero array starting at :end and working towards start :Are we at start --->: No, loop --- BC = no. of bytes in array + 1 --- D = 0 --- HL = addr of no. of indices --- DE = max. no. of indexes --- DE = addr of no. of indices. HL=max no. of indexes --- HL = 2 * no. of indexes --- HL = 2 * no. of indexes + size of array --- HL = no. of indexes addr --- Backspace two bytes to offset address --- 2nd backspace --- Save offset to next --- entry in arrays --- List --- HL = addr of no. of indexes entry --- Restore create/locate flag --- Jmp if in create mode --- BC=0 for first pass thru loop ****** see note--> * --- C = 0 --- A = no. of indexes in array --- Bump HL to right index (max + 1) --- 279A: POP HL Word addr of next index limit --- E = LSB of index limit --- Bump to pos of MSB --- D = MSB of index limit --- HL = addr of next index limit --- HL = callers index value. Stack=addr of next index --- Save number of indexes :limit --- Now, compare user subscript against limit for that --- Jmp if index greater than allowed :index --- Multiply previous subscript times max allowed --- Value for current subscript. Keep sum of products --- A = no. of indexes :in HL --- Count index just processed

265

275C

: explicitly dimensioned

276B

: DE = size of array in bytes

2795

* Continuation of array processing. Locate address of ******** * subscripted variable then load its value. Column major * format.

266

27AB 27AC 27AD 27AF 27B2 27B3 27B4 27B5 27B7 27B9 27BA 27BC 27BD 27BE 27C1 27C2 27C3 27C4 27C5 27C8 27C9 27CA 27CB 27CE 27D1 27D2 27D3 27D4 27D7 27D8 27DB 27DC 27DD 27DF 27E2 27E5 27E8 27E9 27EC 27ED 27EE 27EF 27F0 27F1 27F2 27F5 27F8 27F9 27FA 27FB 27FE 2801 2802 2805 2806 2809 280A 280D 280E 2810

44 4D 20EB 3AAF40 44 4D 29 D604 3804 29 2806 29 B7 E2C227 09 C1 09 EB 2AF340 C9 AF E5 32AF40 CDD427 E1 D7 C9 2AFD40 EB 210000 39 E7 200D CDDA29 CDE628 2AA040 EB 2AD640 7D 93 6F 7C 9A 67 C3660C 3AA640 6F AF 67 C39A0A CDA941 D7 CD2C25 E5 219008 E5 3AAF40 F5 FE03 CCDA29

LD LD JR LD LD LD ADD SUB JR ADD JR ADD OR JP ADD POP ADD EX LD RET XOR PUSH LD CALL POP RST RET LD EX LD ADD RST JR CALL CALL LD EX LD LD SUB LD LD SBC LD JP LD LD XOR LD JP CALL RST CALL PUSH LD PUSH LD PUSH CP CALL

B,H C,L NZ,279AH A,(40AFH) B,H C,L HL,HL 04H C,27BDH HL,HL Z,27C2H HL,HL A PO,27C2H HL,BC BC HL,BC DE,HL HL,(40F3H) A HL (40AFH),A 27D4H HL 10H HL,(40FDH) DE,HL HL,0000H HL,SP 20H NZ,27ECH 29DAH 28E6H HL,(40A0H) DE,HL HL,(40D6H) A,L E L,A A,H A,D H,A 0C66H A,(40A6H) L,A A H,A 0A9AH 41A9H 10H 252CH HL HL,0890H HL A,(40AFH) AF 03H Z,29DAH

--- BC = previous subscript --- C = LSB --- Jmp if more indexes to go --- A = data type flag --- Now, prepare to multiply --- index by size of each entry --- Index * 2 --- Test data type --- Jump if integer or string --- Neither, compute index * 4 --- Jmp if single precision --- Index * 8, must be double precision --- Set parity status flags --- Jump if integer --- Index * 3, string --- BC = starting addr of array --- Add index to base --- DE = address of subscripted variable --- Restore code string position --- Rtn to caller --- Clear A, status flags ************ MEM routine *** --- Save current position in pgm stmt --- Set current data not string so FRE will cont--> --- Call FRE routine - Rtn amt of free cont--> --- Restore current pointer in pgm stmt --- Load next token into A --- Rtn to BASIC --- HL = start of free memory ******** FRE routine ** --- DE = start of free mem ptr --- clear HL so we can load CSP by adding it to HL --- HL = current stack ptr --- Test data type ---> Jump if called from MEM. Variable not a string ---: Get addr of string into HL ---: Go compute amt of space remaining See note --> ---: Load boundary addr for string area ---: Move limit to DE ---: HL = current string area pointer <--: A = LSB of one addr --- Minus LSB of other addr --- Restore L --- H = MSB of one addr --- Minus MSB of other addr --- Restore H. HL = diff in addr (HL-DE) --- Convert diff to single precision & return --- Load current cursor position ** POS routine ** --- Save in L --- Zero A-reg, H-reg --- HL = cursor position (H = 00, L = Position) --- Value in HL to 4121. Flag as integer. Rtn to BASIC --- DOS Exit (JP 5679) ***************** USR routine ** --- Get next character from input stream --- Evaluate the remainder of the statement. cont--> --- Save addr of next element in code string --- This continuation addr clears the stack before --- returning to the BASIC caller --- A = current data type --- Save on stack --- Test for string --- If a string, get addr into HL

267

27C9 27CB 27CE

* ************************************************************* : will do simple compilation : space as current value

27D4

* *************************************************************

27E2

* Remaining space = Current stack addr - start of free mem ptr * if variable not a string, or * = next available location in string area * start of string area. * If variable is a string.

27F5

* *************************************************************

27FE 2802

* ************************************************************* : Get USR number

268

2813 2814 2815 2818 2819 281A 281C 281F 2820 2822 2823 2826 2827 2828 2829 282C 282D 282E 282F 2830 2831 2833 2836 2839 283C 283F 2842 2843 2844 2845 2846 2849 284A 284B 284C 284D 2850 2851 2852 2855 2856 2857 285A 285D 285E 285F 2860 2861 2862 2863 2864 2865 2866 2868 2869 286A 286C 286D 286E 286F

F1 EB 2A8E40 E9 E5 E607 21A118 4F 0600 09 CD8625 E1 C9 E5 2AA240 23 7C B5 E1 C0 1E16 C3A219 CDBD0F CD6528 CDDA29 012B2A C5 7E 23 E5 CDBF28 E1 4E 23 46 CD5A28 E5 6F CDCE29 D1 C9 CDBF28 21D340 E5 77 23 73 23 72 E1 C9 2B 0622 50 E5 0EFF 23 7E 0C B7

POP EX LD JP PUSH AND LD LD LD ADD CALL POP RET PUSH LD INC LD OR POP RET LD JP CALL CALL CALL LD PUSH LD INC PUSH CALL POP LD INC LD CALL PUSH LD CALL POP RET CALL LD PUSH LD INC LD INC LD POP RET DEC LD LD PUSH LD INC LD INC OR

AF DE,HL HL,(408EH) (HL) HL 07H HL,18A1H C,A B,00H HL,BC 2586H HL HL HL,(40A2H) HL A,H L HL NZ E,16H 19A2H 0FBDH 2865H 29DAH BC,2A2BH BC A,(HL) HL HL 28BFH HL C,(HL) HL B,(HL) 285AH HL L,A 29CEH DE 28BFH HL,40D3H HL (HL),A HL (HL),E HL (HL),D HL HL B,22H D,B HL C,0FFH HL A,(HL) C A

-------------------------------------------------------------------------------------------------------------------------

Restore type to A-reg DE = string addr (408E) contains entry pt to USR subroutine Enter user assembly language subroutine Called by LET to convert result of ***** cont--> * A = result type Address of arithmetic conversion routines Setup BC = 00/type where Type = 0(DP), 1(I), 2(string), 3(SP) Plus offset for result of arithmetic Convert result to proper data type Restore HL Rtn Save code string addr * Called from INPUT routine * HL = current line no. in binary Add 1 so a test for a DIRECT statement can be made. Line no. = FFFF while in INPUT phase Restore code string pointer Exit if line no. not zero (not a DIRECT stmt) Else give an ID error Print error and rtn to INPUT PHASE Current value convert caller's ********* cont--> * Build a literal string, pool entry cont--> Get addr of current value into HL Continuation addr in CHR$ routine to stack Put addr on stack A = length of string Bump to string address HL = address of string pointer Test remaining string area to make sure new string will fit. Reload HL with string address C = LSB of string addr. Bump to MSB :user value BC = address of string for ASCII equivalent of Save length, address of string at 40D3 HL = 40D3 L = length of string Move string from BC (temp area) to DE (string data DE = 40D3 :area) Rtn to caller Make sure there's room. Get addr of **** cont--> * HL = addr of temp storage area Save 40D3 on stk so it can be restored Save length of string Bump to position of LSB of addr Save LSB of string addr Bump to position of MSB of addr Save MSB of string addr Restore starting addr of string control block Rtn to caller Backspace input pointer to quote * Quote Routine * B = ASCII value for quote (') D = terminating search character Save addr of starting quote Initialize counter to -1 Skip over quote Get a character Bump count of characters processed Set status flags

269

2819

* arithmetic routines to proper destination type **************

2828

* *************************************************************

2836 2839

* parameter to ASCII ****************************************** : for ASCII number. Save as current value

2857

* next string area in DE ***** Save A, DE at 40D3 - 40D5 ******

2865

* *************************************************************

270

2870 2872 2873 2875 2876 2878 287A 287D 287E 287F 2880 2881 2884 2887 2889 288C 288F 2891 2894 2897 289A 289B 289E 289F 28A0 28A1 28A3 28A6 28A7 28AA 28AD 28B0 28B1 28B2 28B3 28B4 28B7 28B9 28BC 28BD 28BF 28C0 28C2 28C3 28C6 28C7 28CA 28CB 28CC 28CE 28CF 28D0 28D1 28D3 28D6 28D7 28D8 28D9 28DA 28DB

2806 BA 2803 B8 20F4 FE22 CC781D E3 23 EB 79 CD5A28 11D340 3ED5 2AB340 222141 3E03 32AF40 CDD309 11D640 DF 22B340 E1 7E C0 1E1E C3A219 23 CD6528 CDDA29 CDC409 14 15 C8 0A CD2A03 FE0D CC0321 03 18F2 B7 0EF1 F5 2AA040 EB 2AD640 2F 4F 06FF 09 23 DF 3807 22D640 23 EB F1 C9 F1 1E1A

JR CP JR CP JR CP CALL EX INC EX LD CALL LD LD LD LD LD LD CALL LD RST LD POP LD RET LD JP INC CALL CALL CALL INC DEC RET LD CALL CP CALL INC JR OR LD PUSH LD EX LD CPL LD LD ADD INC RST JR LD INC EX POP RET POP LD

Z,2878H D Z,2878H B NZ,286CH 22H Z,1D78H (SP),HL HL DE,HL A,C 285AH DE,40D3H A,0D5H HL,(40B3H) (4121H),HL A,03H (40AFH),A 09D3H DE,40D6H 18H (40B3H),HL HL A,(HL) NZ E,1EH 19A2H HL 2865H 29DAH 09C4H D D Z A,(BC) 032AH 0DH Z,2103H BC 28B1H A C,0F1H AF HL,(40A0H) DE,HL HL,(40D6H) C,A B,0FFH HL,BC HL 18H C,28DAH (40D6H),HL HL DE,HL AF AF E,1AH

--- Jmp if EOS --- Test for terminating char (usually quote) --- Jmp if terminating character --- Test for second terminating character --- Still not terminating character, loop till it is --- Was last character a quote ? --- If yes get following character --- Address of starting quote see note--> --- Plus one gives address of first char --- Starting addr of char string to DE --- A = length of string --- Move length, addr of string to 40 D3 --- 40D3 = length, addr of the ********* see note--> * --- string in the string data area --- HL = addr of next avail literal string entry --- Addr of current string val = current literal area --- Current value type = string :string value --- Save in type flag byte --- Move length string area addr to current lit. --- DE = end of literal are addr to current lit. --- Make sure we have not overrun lit. string --- pool area. Update addr of next aval lit. string --- Restore code string addr :pool entry --- A = next element of code string --- Return if temp string area not overrun --- ST error code --- Output ST error message --- Message output routine *************************** --- Build literal string pool entry --- Get addr of current variable into HL --- Get length of string into D. Starting addr in BC --- for decrement <---: Count 1 character printed : Exit if all characters printed : Character to be printed : Output char to system output device : Then test if it was a carriage return : Exit if char was a carriage return : Bump to next character --->: Loop till CR, or D characters printed --- Compute amt of space remaining in string area **** --- 28C1H : POP AF --- Save length of string --- Load starting addr of string area into HL --- DE = addr of string area --- Load ptr to next avail string loc into HL --- Compute the negative of the length of the string --- and save it in C --- BC = - length of string --- HL = new current string pointer --- plus one --- Compare new string pointer against limit --->: OS error if CARRY see note--> -- : Save new current string pointer -- : Bump it by one -- : DE = new current string pointer -- : A = length of string -- : Rtn to caller <---: A = length of string, **************** cont--> * --- OS error code

271

287D

: Address of 1st non-blank char after quote to stack

2884

* : : :

Move length, address from 40113 to current literal string. *** Pool entry pointed to by 40113. Set current value to type string and point its addr to the current literal string (40D3)

2816

* *************************************************************

28BF

* *************************************************************

28D1

: Insufficient room in string area

28DA

* get status flags to find out if reorganization has ********** : been attempted

272

28DD 28E0 28E1 28E2 28E5 28E6 28E9 28EC 28EF 28F0 28F3 28F4 28F7 28F8 28FB 28FC 28FD 2900 2903 2906 2907 290A 290B 290C 290E 290F 2910 2911 2912 2914 2916 2919 291A 291B 291D 291E 2920 2921 2922 2925 2926 2927 292A 292B 292C 292F 2930 2931 2933 2935 2938 2939 293A 293C 293D 293E 293F 2940 2943 2944

CAA219 BF F5 01C128 C5 2AB140 22D640 210000 E5 2AA040 E5 21B540 EB 2AB340 EB DF 01F728 C24A29 2AF940 EB 2AFB40 EB DF 2813 7E 23 23 23 FE03 2004 CD4B29 AF 5F 1600 19 18E6 C1 EB 2AFD40 EB DF CA6B29 7E 23 CDC209 E5 09 FE03 20EB 22D840 E1 4E 0600 09 09 23 EB 2AD840 EB DF

JP CP PUSH LD PUSH LD LD LD PUSH LD PUSH LD EX LD EX RST LD JP LD EX LD EX RST JR LD INC INC INC CP JR CALL XOR LD LD ADD JR POP EX LD EX RST JP LD INC CALL PUSH ADD CP JR LD POP LD LD ADD ADD INC EX LD EX RST

Z,19A2H A AF BC,28C1H BC HL,(40B1H) (40D6H),HL HL,0000H HL HL,(40A0H) HL HL,40B5H DE,HL HL,(40B3H) DE,HL 18H BC,28F7H NZ,294AH HL,(40F9H) DE,HL HL,(40FBH) DE,HL 18H Z,2921H A,(HL) HL HL HL 03H NZ,291AH 294BH A E,A D,00H HL,DE 2906H BC DE,HL HL,(40FDH) DE,HL 18H Z,296BH A,(HL) HL 09C2H HL HL,BC 03H NZ,2920H (40D8H),HL HL C,(HL) B,00H HL,BC HL,BC HL DE,HL HL,(40D8H) DE,HL 18H

--- Error if free space reorganized and still no room --- Set status flags to zero and ret --- Save zero --- Continuation address to retry allocation --- To stack --- HL = highest memory pointer --- Reset current string pointer to end of memory --- Load a zero --- And save it on stack --- HL = boundary of string data area --- Save it on stack also --- HL = address of first entry in string pointer area --- Save HL in DE --- HL = addr of current entry in LSPT :area --- DE = address of current entry in string pointer --- Is 40 B3 pointing to the first entry (40B5) --- Continuation addr in case answer is no --- No, JMP to 294A, RTN to 28F7 --- HL = simple variable pointer <------: Save it in DE : HL = arrays pointer : HL = variable list pointer. DE = arrays ptr : Compare their addresses. Are they equal ->:----: Yes, simple variables have been scanned : : Get type for first simple variable : : Bump to LSB by incrementing HL by 3 : : So that type can be added to give addr of : : Addr of next variable : : Test if variable is a string : : Jmp if not a string : : For a string, get its addr into HL : : Zero A because HL already points to next : : Bump to addr of :entry : : Next variable : : Gives addr of next variable in list --:--->: Loop till all simple variables examined <-:------: Clear HL, push from below <-: : DE = points to current array entry : HL = addr of next avail mem loc. : DE = addr of first avail mem loc. : Have we scanned all arrays entries : Yes : No, get type for this array : Bump to 2nd char of name : Load offset to next array into cont ---> : Save addr of no. of indexes : Add offset to get next arrays entry : Is current type a string? -------->: No, loop keep looking --- Save addr of next array entry --- HL = addr of no. of indexes --- C = no. of indexes --- Set B = 0. Then --- add 2 times no. of indexes to current --- addr to get end of index boundaries --- HL = addr of end of indexes for this variable --- Move it to DE --- HL = addr of next variable --- HL = end of index boundaries, DE = addr of next --- Test for empty list :variable

273

:BC. Skips over name

274

2945 2947 294A 294B 294C 294D 294E 294F 2950 2951 2952 2953 2954 2955 2958 2959 295A 295B 295C 295D 295E 295F 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 296A 296B 296C 296D 296E 296F 2970 2971 2972 2973 2974 2975 2976 2977 2979 297A 297B 297C 297D 297E 297F 2982 2985 2986 2987 2988 2989 298A

28DA 013F29 C5 AF B6 23 5E 23 56 23 C8 44 4D 2AD640 DF 60 69 D8 E1 E3 DF E3 E5 60 69 D0 C1 F1 F1 E5 D5 C5 C9 D1 E1 7D B4 C8 2B 46 2B 4E E5 2B 6E 2600 09 50 59 2B 44 4D 2AD640 CD5819 E1 71 23 70 69 60

JR LD PUSH XOR OR INC LD INC LD INC RET LD LD LD RST LD LD RET POP EX RST EX PUSH LD LD RET POP POP POP PUSH PUSH PUSH RET POP POP LD OR RET DEC LD DEC LD PUSH DEC LD LD ADD LD LD DEC LD LD LD CALL POP LD INC LD LD LD

Z,2921H BC,293FH BC A (HL) HL E,(HL) HL D,(HL) HL Z B,H C,L HL,(40D6H) 18H H,B L,C C HL (SP),HL 18H (SP),HL HL H,B L,C NC BC AF AF HL DE BC DE HL A,L H Z HL B,(HL) HL C,(HL) HL HL L,(HL) H,00H HL,BC D,B E,C HL B,H C,L HL,(40D6H) 1958H HL (HL),C HL (HL),B L,C H,B

-------------------------------------------------------------------------------------------------------------------------

Jmp if list empty Continuation addr for string array processing Save continuation addr on stack Clear all status flags A = length of string Bump to next two bytes to get string address Bump to MSB of string addr DE = string address :addr) Bump to next entry in string pointer area (test Exit if string length is zero BC = addr of next string pointer Loaded from HL HL = current string area pointer Is string in string data area? Restore addr of next literal pool entry to HL Return if string in string area HL = return address HL = callers test address Compare callers test addr to string addr Restore stack to callers flag, rtn addr Restore rtn addr to stack HL = addr of next literal string pool entry Loaded from BC Exit if string addr below callers addr BC = return address Get rid of callers string addr Callers flag Save addr of next string area pointer Save addr of current string Return addr Rtn to caller DE = addr of last string moved to string area **** HL = addr of next string area pointer If HL = 0 then there were no strings in string area which belonged to the literal cont--> Exit if no temp strings in string area cont--> Backspace addr to get pointers for literal pool B = LSB of addr for string :entry Skip backwards to next byte of addr C = MSB of addr for string Save addr of pointer in lit. string so we update Bump down to length : it after move L = length of string Zero H so we can do 16 bit arith BL = ending addr of string DE = starting addr of string Loaded from BC HL = ending addr -1 BC = ending addr -1 Loaded from HL HL = current string data pointer Move string to new area in string area table HL = addr of literal string pointer Now, move address of string in string area to 2nd and Ad bytes of literal pool entry Save 1st character of name Then setup HL so it points to the start of the last string moved to the string area

275

296B

* *************************************************************

296E 296F

: string pool (temporary) : String area reorganized

276

298B 298C 298F 2990 2991 2994 2995 2998 2999 299C 299D 299E 29A1 29A2 29A3 29A5 29A8 29AB 29AC 29AF 29B0 29B3 29B4 29B7 29B8 29BB 29BE 29C1 29C2 29C3 29C6 29C7 29C8 29C9 29CA 29CB 29CC 29CD 29CE 29CF 29D0 29D1 29D2 29D3 29D4 29D5 29D7 29DA 29DD 29DE 29E1 29E2 29E3 29E4 29E5 29E6 29E7 29E8 29EB 29EC

2B C3E928 C5 E5 2A2141 E3 CD9F24 E3 CDF40A 7E E5 2A2141 E5 86 1E1C DAA219 CD5728 D1 CDDE29 E3 CDDD29 E5 2AD440 EB CDC629 CDC629 214923 E3 E5 C38428 E1 E3 7E 23 4E 23 46 6F 2C 2D C8 0A 12 03 13 18F8 CDF40A 2A2141 EB CDF529 EB C0 D5 50 59 1B 4E 2AD640 DF 2005

DEC JP PUSH PUSH LD EX CALL EX CALL LD PUSH LD PUSH ADD LD JP CALL POP CALL EX CALL PUSH LD EX CALL CALL LD EX PUSH JP POP EX LD INC LD INC LD LD INC DEC RET LD LD INC INC JR CALL LD EX CALL EX RET PUSH LD LD DEC LD LD RST JR

HL 28E9H BC HL HL,(4121H) (SP),HL 249FH (SP),HL 0AF4H A,(HL) HL HL,(4121H) HL A,(HL) E,1CH C,19A2H 2857H DE 29DEH (SP),HL 29DDH HL HL,(40D4H) DE,HL 29C6H 29C6H HL,2349H (SP),HL HL 2884H HL (SP),HL A,(HL) HL C,(HL) HL B,(HL) L,A L L Z A,(BC) (DE),A BC DE 29CFH 0AF4H HL,(4121H) DE,HL 29F5H DE,HL NZ DE D,B E,C DE C,(HL) HL,(40D6H) 18H NZ,29F3H

-------------------------------------------------------------------------------------------------------------------------

And loop until no more literal pool entries are found which must be moved to the string area. String addition. Concatenate two strings * note--> Save PV last operand/ last token, and code string Stack = addr of string 1, HL = current pos. :addr in input string Locate next variable HL = 4121, Stack = code string addr Make sure it's a string A = length of string 1 Save addr of string 1 HL = addr of string 2 Addr of string 2 to stack A = length string 1 + string 2 output if carry Jmp if combined string length exceeds 256 Make sure there's enough room for both strings DE = addr of string 2 Update string area for string 2 if necessary HL = addr of string 1 Update string area for string 1 if necessary Save addr of string 1 Get addr of string 2 DE = address of second string Move string 1 from stack to string work area Move string 2 Continuation addr in expression evaluation to stack. Code string addr to HL Save code string addr :table Save string 1 + string 2 as entry in literal pool HL = rtn addr, stack = string addr ***** cont--> * Stack = rtn addr, HL = string addr A = count of characters to move Bump to LSB of addr C = LSB of addr Bump to MSB of addr BC = addr L = no. of bytes to move Do INC/DEC to set status flags Decrement count of characters moved Exit if all character moved see note--> Fetch a char Store a char Bump source addr Bump destination addr Loop Continuation of VAL, FRE, and PRINT **** cont--> * HL = addr of current string Move addr to DE Test : is current variable also the last lit. string pool entry No, exit w/DE = current variable addr Yes, current variable was last literal string defined Move string addr to DE and save on stack C = count of characters in current string HL = current string pointer Is current string=last one defined in string area No, exit

277

298E

* Called by expression evaluation *****************************

29C6

* Move using stack routine On entry stack = count/source **** : address, DE = destination address.

29D0

: Move L characters from (BC) to (DE)

29D7

* processing. Test current value to make sure it's string. *** : Error if number

278

29EE 29EF 29F0 29F3 29F4 29F5 29F8 29F9 29FA 29FB 29FC 29FD 29FE 29FF 2A02 2A03 2A06 2A07 2A0A 2A0B 2A0C 2A0D 2A0E 2A0F 2A12 2A13 2A16 2A19 2A1A 2A1B 2A1C 2A1D 2A1E 2A1F 2A21 2A24 2A27 2A2A 2A2B 2A2C 2A2F 2A30 2A31 2A33 2A34 2A35 2A36 2A37 2A38 2A3B 2A3C 2A3D 2A3E 2A3F 2A40 2A42 2A45 2A47 2A4A 2A4B

47 09 22D640 E1 C9 2AB340 2B 46 2B 4E 2B DF C0 22B340 C9 01F827 C5 CDD729 AF 57 7E B7 C9 01F827 C5 CD072A CA4A1E 23 5E 23 56 1A C9 3E01 CD5728 CD1F2B 2AD440 73 C1 C38428 D7 CF 28CD 1C 2B D5 CF 2C CD3723 CF 29 E3 E5 E7 2805 CD1F2B 1803 CD132A D1 F5

LD ADD LD POP RET LD DEC LD DEC LD DEC RST RET LD RET LD PUSH CALL XOR LD LD OR RET LD PUSH CALL JP INC LD INC LD LD RET LD CALL CALL LD LD POP JP RST RST JR INC DEC PUSH RST INC CALL RST ADD EX PUSH RST JR CALL JR CALL POP PUSH

B,A HL,BC (40D6H),HL HL HL,(40B3H) HL B,(HL) HL C,(HL) HL 18H NZ (40B3H),HL BC,27F8H BC 29D7H A D,A A,(HL) A BC,27F8H BC 2A07H Z,1E4AH HL E,(HL) HL D,(HL) A,(DE) A,01H 2857H 2B1FH HL,(40D4H) (HL),E BC 2884H 10H 08H Z,2A00H E HL DE 08H L 2337H 08H HL,HL (SP),HL HL 20H Z,2A47H 2B1FH 2A4AH 2A13H DE AF

--- Yes , update current string pointer --- HL = addr of string + length = new string ptr addr --- Save new string ptr addr --- HL = addr of current string --- Rtn to caller --- HL = addr of next avail string location ********** --- Now, backup two words and load --- addr of previous string into BC. --- Then, compare the address of that entry --- against the address of the current --- variable (or whatever's in DE). If unequal --- exit, else reset the pointer (40 B3) to --- point to the current (last) entry --- Update pointer to current entry in LSPT --- Rtn to caller --- Continuation addr of POS to stk *** LEN routine ** --- 27F8 to stack --- Get addr of current string pointer into HL --- Clear status, zero A --- and D --- A = length of string from string pointer area --- Set status flags for length --- Continue at POS unless entered at 2A07 --- Continuation addr of 27F8 to stk **8 ASC routine ** --- Saves value in HL as current value --- Get addr of current string pointer into HL. Length --- Error of length of string = 0 :into A --- Now, load addr of string into DE --- E = LSB of string addr --- Bump to MSB --- D = MSB of string addr --- A = first character of string --- Rtn to caller --- A=length of string to be created ** CHR$ routine * --- Save length and value of char at 40 D3 --- Convert value to integer. Save in DE --- HL = address of temporary string --- Save value in string area --- Clear stack :interpreter --- Move string from literal pool to string. Rtn to --- STRING$ routine ********************************* --- Test next char for '(' --- 2A31: DC 28 '(' --- 2A32: CALL 2B1C evaluate expression - get N --- Backspace code string --- Save integer value for N --- Test next char for comma --- 2A37: DC 2C comma --- Evaluate expression, get value of char --- Test next char for ')' --- 2A3C: DC 29 ')' --- HL = integer value for N/stack = next code string --- Followed by N :addr --- Test current value data type --->: Jump if string -- : Convert to integer. Leave in DE, WRA1 -- : Skip loading of string addr & 1st character <---: A = character to be repeated --- DE = value of N from STRING$ (N,'X') call --- Save character

279

29F5

* *************************************************************

2A03

* *************************************************************

2A0F

* *************************************************************

2A1F

* *************************************************************

2A2F

* *************************************************************

280

2A4C 2A4D 2A4E 2A51 2A52 2A53 2A54 2A55 2A57 2A5A 2A5B 2A5C 2A5D 2A5F 2A61 2A64 2A65 2A66 2A67 2A69 2A6A 2A6B 2A6C 2A6E 2A6F 2A72 2A73 2A76 2A77 2A78 2A79 2A7A 2A7B 2A7C 2A7D 2A7E 2A80 2A81 2A82 2A83 2A86 2A87 2A8A 2A8B 2A8E 2A91 2A94 2A95 2A96 2A97 2A98 2A9A 2A9B 2A9C 2A9F 2AA0 2AA1 2AA4 2AA5 2AA7

F5 7B CD5728 5F F1 1C 1D 28D4 2AD440 77 23 1D 20FB 18CA CDDF2A AF E3 4F 3EE5 E5 7E B8 3802 78 110E00 C5 CDBF28 C1 E1 E5 23 46 23 66 68 0600 09 44 4D CD5A28 6F CDCE29 D1 CDDE29 C38428 CDDF2A D1 D5 1A 90 18CB EB 7E CDE22A 04 05 CA4A1E C5 1EFF FE29

PUSH LD CALL LD POP INC DEC JR LD LD INC DEC JR JR CALL XOR EX LD LD PUSH LD CP JR LD LD PUSH CALL POP POP PUSH INC LD INC LD LD LD ADD LD LD CALL LD CALL POP CALL JP CALL POP PUSH LD SUB JR EX LD CALL INC DEC JP PUSH LD CP

AF A,E 2857H E,A AF E E Z,2A2BH HL,(40D4H) (HL),A HL E NZ,2A5AH 2A2BH 2ADFH A (SP),HL C,A A,0E5H HL A,(HL) B C,2A70H A,B DE,000EH BC 28BFH BC HL HL HL B,(HL) HL H,(HL) L,B B,00H HL,BC B,H C,L 285AH L,A 29CEH DE 29DEH 2884H 2ADFH DE DE A,(DE) B 2A65H DE,HL A,(HL) 2AE2H B B Z,1E4AH BC E,0FFH 29H

--- Save two copies of the character --- A = number of repetition --- Allocate N bytes in string area. cont--> --- E = number of repetition --- A = character to be repeated --- Set status flags --- So we can test for zero --- If zero repetition, exit --- HL = addr allocated in string area <---: Move char : Bump string addr : Count repetition --->: Loop till 'N' copies moved --- Rtn to caller --- Test for closing ')' ** LEFT$ routine ** cont--> * --- Clear A, status flags --- HL = addr of n. Stack = current code string addr --- Zero to C --- 2A68: LD H,A --- Save addr of string --- Get length of string --- Compare with number of bytes to return --- Jmp if byte request exceeds size of string --- Save no. of bytes to return --- 2A70: LD C,00 --- Save length of string to return --- Make sure there's room for new string. cont--> --- BC = length of string to be returned --- HL = string addr --- Save string addr on stack --- Skip over character count --- B = LSB of string addr --- Skip to MSB --- H = MSB of string addr --- HL = addr of string --- BC = 00/length of string desired --- HL = ending addr of last char to be moved --- Now, move ending --- Addr into BC --- Save length (A) and starting addr (DE) cont--> --- L = number of chars to move --- Move (L) chars. from (BC) to (DE) --- Clear stack --- Get addr of literal pool string into 40D3 --- Go move string to string area. Ret to interpreter --- Setup registers **************** RIGHT$ routine ** --- Load string address --- And restore it to stack --- A = number of characters in string --- Subtract no. of bytes to isolate --- Use LEFT$ code --- HL = code string addr ************ MID$ routine ** --- A = terminal character --- BC = position DE = string address --- Set status flags to --- correspond to position value --- Error if starting position is zero --- Save starting position --- E = 256 in case number of bytes not given --- Test for right paren following P

281

2A4E

: Save address of allocated area at 40D4 - 40D5

2A61

* Setup registers ***** On entry : : :

HL = address of LEFT$ ***** stack = string address stack + 1 = n DE = code string addr

2A73

: Get addr of next string area in DE

2A83

: next avail loc in lit pool

2A91

* *************************************************************

2A9A

* *************************************************************

282

2AA9 2AAB 2AAC 2AAD 2AB0 2AB1 2AB2 2AB3 2AB4 2AB7 2AB8 2AB9 2ABA 2ABC 2ABD 2ABE 2ABF 2AC0 2AC1 2AC2 2AC3 2AC4 2AC5 2AC8 2ACB 2ACC 2ACD 2ACE 2ACF 2AD0 2AD1 2AD2 2AD3 2AD4 2AD5 2AD6 2AD7 2AD8 2ADB 2ADC 2ADD 2ADE 2ADF 2AE0 2AE1 2AE2 2AE3 2AE4 2AE5 2AE6 2AE7 2AE9 2AEC 2AEF 2AF2 2AF5 2AF8 2AFB 2AFE 2B01

2805 CF 2C CD1C2B CF 29 F1 E3 01692A C5 3D BE 0600 D0 4F 7E 91 BB 47 D8 43 C9 CD072A CAF827 5F 23 7E 23 66 6F E5 19 46 72 E3 C5 7E CD650E C1 E1 70 C9 EB CF 29 C1 D1 C5 43 C9 FE7A C29719 C3D941 CD1F2B 329440 CD9340 C3F827 CD0E2B C39640 D7

JR RST INC CALL RST ADD POP EX LD PUSH DEC CP LD RET LD LD SUB CP LD RET LD RET CALL JP LD INC LD INC LD LD PUSH ADD LD LD EX PUSH LD CALL POP POP LD RET EX RST ADD POP POP PUSH LD RET CP JP JP CALL LD CALL JP CALL JP RST

Z,2AB0H 08H L 2B1CH 08H HL,HL AF (SP),HL BC,2A69H BC A (HL) B,00H NC C,A A,(HL) C E B,A C B,E 2A07H Z,27F8H E,A HL A,(HL) HL H,(HL) L,A HL HL,DE B,(HL) (HL),D (SP),HL BC A,(HL) 0E65H BC HL (HL),B DE,HL 08H HL,HL BC DE BC B,E 7AH NZ,1997H 41D9H 2B1FH (4094H),A 4093H 27F8H 2B0EH 4096H 10H

--->: Jmp if no byte count given, else -- : Test next input value for comma -- : 2AAC: DC 2C comma -- : Evaluate expression. Get byte count as integer <---: Test next char for ')' :into DE --- 2AB1: DC 28 ')' --- A = starting position --- HL = string addr. Stack = current code string addr --- Continuation of MID$ processing in LEFT$ --- Address to stack --- Starting position minus one --- Compare starting position with length of string --- B = 00 --- Continue at 2A69 if starting position-1 > length of --- C = starting position -1 :string --- A = length of string --- C = no. of chars between P and end of string --- Compare with number of characters to return --- B = no. of characters to return --- Continue at 2A69 if more characters cont--> --- Else, return number of characters requested --- Continue at 2A69 --- Get length into A-reg *************** VAL routine * --- Address of string pointer block in HL --- Exit if length = 0. Move length to E, D = 0 --- Skip over length --- A = LSB of string addr --- Bump to MSB of addr --- H = MSB of string addr --- Now, HL = string addr --- Save string addr then add length which --- gives HL = ending addr --- Save last char of string --- Replace it with a zero --- Stack=ending addr of string. HL=starting addr of --- Save replaced char of string :string --- A = 1st char of string --- Convert numerics at start of string from ASCII to --- B = replaced character :binary --- HL = ending addr of string --- Restore replaced char --- Rtn to BASIC --- DE = addr of calling routine *********** cont--> * --- Look for right paren following parameters --- DC 28 ')' --- Return address --- DE = count of bytes to isolate --- Restore return addr --- B = byte count --- HL = code string addr --- Test if token in range *************************** --- SN error if NZ. Error if token => FA --- Disk BASIC Exit. Let Disk BASIC handle TAB-MID$ --- Get port no. into A-reg ********* INP routine **** --- Save port number --- Go execute IN XX instr. Rtn to execution driver --- Evaluate expression . ** OUT routine ** cont--> * --- Value to A-reg. --- Go execute OUT XX instr. Rtn to execution driver --- Position to next char in input stream ** cont--> *

283

2AC2

: requested than string has in it

2AC5

* ***********************************************************

2AE7

* HL = code string addr ****

Called by LEFTS, MID$, & RIGHT$ ** to test for ending ')'. Entry Exit Stk=string addr string addr byte count DE=byte count ret addr B=byte count

2AEF

* **************************************************************

2AEF

: **************************************************************

2AFB

* Port no. to 4094, 4097 ***************************************

2B01

* Evaluate an expression . Leave result as integer in DE *******

284

2B02 2B05 2B06 2B09 2B0A 2B0B 2B0C 2B0D 2B0E 2B11 2B14 2B17 2B18 2B19 2B1B 2B1C 2B1F 2B22 2B25 2B26 2B27 2B28 2B29 2B2B 2B2E 2B2F 2B32 2B33 2B36 2B39 2B3A 2B3B 2B3C 2B3D 2B3E 2B3F 2B40 2B41 2B44 2B47 2B4A 2B4B 2B4C 2B4D 2B4E 2B4F 2B50 2B51 2B52 2B53 2B54 2B57 2B58 2B59 2B5A 2B5B 2B5E 2B61 2B63 2B64

CD3723 E5 CD7F0A EB E1 7A B7 C9 CD1C2B 329440 329740 CF 2C 1801 D7 CD3723 CD052B C24A1E 2B D7 7B C9 3E01 329C40 C1 CD101B C5 21FFFF 22A240 E1 D1 4E 23 46 23 78 B1 CA191A CDDF41 CD9B1D C5 4E 23 46 23 C5 E3 EB DF C1 DA181A E3 E5 C5 EB 22EC40 CDAF0F 3E20 E1 CD2A03

CALL PUSH CALL EX POP LD OR RET CALL LD LD RST INC JR RST CALL CALL JP DEC RST LD RET LD LD POP CALL PUSH LD LD POP POP LD INC LD INC LD OR JP CALL CALL PUSH LD INC LD INC PUSH EX EX RST POP JP EX PUSH PUSH EX LD CALL LD POP CALL

2337H HL 0A7FH DE,HL HL A,D A 2B1CH (4094H),A (4097H),A 08H L 2B1CH 10H 2337H 2B05H NZ,1E4AH HL 10H A,E A,01H (409CH),A BC 1B10H BC HL,0FFFFH (40A2H),HL HL DE C,(HL) HL B,(HL) HL A,B C Z,1A19H 41DFH 1D9BH BC C,(HL) HL B,(HL) HL BC (SP),HL DE,HL 18H BC C,1A18H (SP),HL HL BC DE,HL (40ECH),HL 0FAFH A,20H HL 032AH

--- Evaluate expression. Result to WRA1 --- Next code string addr --- Convert result to integer. Put it in HL --- DE = result (in integer form) --- Restore position in input stream --- MSB of result to A --- Rtn to caller --- Ret sign/zero flags for result --- Evaluate expression. Get port no. ****** cont--> * --- Save port no. in DOS addresses --- 4094 and 4097 --- Test following char for single quote --- 2B18: DC 2C single quote --->: Skip over PRINT TAB entry point --- : Examine next char (called by PRINT TAB) <---: Evaluate expression. Get value --- Convert result of exp to integer, load cont--> --- FC error value > 255 --- Backspace input string --- Get next char from input string (bump HL & ret --- LSB of result to A :flags) --- Rtn to caller --- Device type for printer ********** LLIST routine ** --- Set current output device to printer --- Remove rtn addr from stack ******** LIST routine ** --- Get range of line nos. list on exit cont--> --- Save start line ptr --- Set current line number to -1 --- Save in current line number location --- HL = addr of first line to be listed --- DE = addr of last line to be listed --- Now, get the pointer the next line --- C holds LSB of pointer to next line --- B = MSB of pointer to next line --- HL=addr of first byte for current line (line no.) --- If the pointer to the next line cont--> --- Check for end of pgm --- Return to READY routine if end --- DOS Exit (JP 579C) --- Test keyboard input. Pause if cont--> --- Save addr of next line to be printed --- Get LSB of line number for current line --- Bump to next byte of line number --- Load MSB of current line number --- HL = first byte of pgm statement for current line --- Save line no.(in binary) for current line on stack --- Rearrange : stack=addr of 1st byte of pgm cont--> --- DE = addr of current line, HL = addr of last line --- Test to see if all lines listed :to list --- BC = addr of 1st byte of current line --- Rtn to Input Phase if all lines listed --- HL = addr of last line to be printed cont--> --- Save addr of current line --- Save line no. (binary) for current line --- HL = addr of current line --- Save in loc. for line number with error --- Output a line # in ASCII --- A = ASCII blank --- HL = addr of current line --- And a blank

285

2B0E

* Continuation of OUT routine *********************************

2B1F

: it into DE. Set A = MSB

2B29

* ************************************************************

*********************************************************** 2B2F : BC = addr of first line. Stack = addr of last line

2B3F

: is zero, then the end of the pgm has been found

2B47

: shift @ hit, rtn when any release key hit

2B50

: HL = binary line no.

2B57

: Stack = line no. of current line

286

2B67 2B6A 2B6D 2B70 2B73 2B75 2B76 2B77 2B78 2B7B 2B7C 2B7E 2B7F 2B82 2B83 2B84 2B85 2B87 2B89 2B8A 2B8B 2B8C 2B8D 2B8E 2B8F 2B90 2B91 2B94 2B96 2B98 2B99 2B9A 2B9B 2B9C 2B9D 2B9E 2B9F 2BA0 2BA2 2BA5 2BA7 2BA8 2BA9 2BAC 2BAD 2BAE 2BAF 2BB2 2BB3 2BB5 2BB7 2BB8 2BB9 2BBA 2BBD 2BBE 2BBF 2BC0 2BC3 2BC4

CD7E2B 2AA740 CD752B CDFE20 18BE 7E B7 C8 CD2A03 23 18F7 E5 2AA740 44 4D E1 16FF 1803 03 15 C8 7E B7 23 02 C8 F2892B FEFB 2008 0B 0B 0B 0B 14 14 14 14 FE95 CC240B D67F E5 5F 215016 7E B7 23 F2AC2B 1D 20F7 E67F 02 03 15 CAD828 7E 23 B7 F2B72B E1 18C6

CALL LD CALL CALL JR LD OR RET CALL INC JR PUSH LD LD LD POP LD JR INC DEC RET LD OR INC LD RET JP CP JR DEC DEC DEC DEC INC INC INC INC CP CALL SUB PUSH LD LD LD OR INC JP DEC JR AND LD INC DEC JP LD INC OR JP POP JR

2B7EH HL,(40A7H) 2B75H 20FEH 2B33H A,(HL) A Z 032AH HL 2B75H HL HL,(40A7H) B,H C,L HL D,0FFH 2B8CH BC D Z A,(HL) A HL (BC),A Z P,2B89H 0FBH NZ,2BA0H BC BC BC BC D D D D 95H Z,0B24H 7FH HL E,A HL,1650H A,(HL) A HL P,2BACH E NZ,2BACH 7FH (BC),A BC D Z,28D8H A,(HL) HL A P,2BB7H HL 2B8CH

--- Move current line to work area(40A7) and expand it --- HL = addr of expanded line --- Buffer to screen (print current line) --- Terminate line w/carriage ret line feed --- Loop till all lines printed --- Output area pointed to by HL ********************* --- Fetch next character to print --- Exit if end of message --- Print (HL) --- Bump to next char --- Keep printing till (HL) = 0 --- Save addr of line to be moved ****** see note--> * --- HL = addr of input buffer. Move it --- to BC where it will be used as --- an output buffer for expanded line --- Restore addr of line to be moved/expanded --- D = max. no. chars in a line --- Jmp into middle of move/expand code <---: Bump to next loc. in print/work buffer : Count of chars moved : Exit if 256 chars moved <---:-: Get a char from program table (PST) : : Set status flags so we can test for EOS or : : Bump to next char in code string :token : : Save last char in print/work buffer area : : Exit if EOS (end of statement) --->: : Jmp if char is not a token cont--> :Test for quote token --->: : Not a quote token, go search RW list for : : full syntax for this token : : We have a quote token : : Backspace expanded buffer ptr : : by 4 : : Then adjust : : count of characters : : in buffer : : by four <---: : Test for ELSE token : Backspace expanded buffer ptr if ELSE : A = the number of the entry cont--> : Save current code string addr : B = number of entries to skip : HL = reserved word table ptr <---: : Get a byte from reserved word (RW) table : : Set status to test for start of entry : : Bump to next word in RW table --->: : Jmp if not start of entry : : Count one entry skipped see note--> --->: : Jmp if we have not skipped enough entries : Clear sign bit in first word of entry : Move a byte of RW (in ASCII) to print/work : buffer. Bump to next work buffer addr : Count total chars moved to print buffer : Jmp if 256 moved (Rtn to caller cont--> : Get next word from RW list : Bump to next entry in RW list : Set status flags so we can test cont--> : Jmp if not end - Move rest of chars cont--> : Restore code string addr ----->: Continue scannning/moving code string

287

2B75

* **********************************************************

2B7E

* Called by LIST and EDIT. Move line pointer to by HL to ***** : input buffer area. Expand each token into its key word

2B91

: (does not need expansion) go get next char

2BA5

: we are looking for in the reserved word list (RW)

: : : :

Scan the reserved word list looking for the nth entry. Each entry in variable length and starts byte where the sign bit is on, the entry itself be reserved word in ASCII that we are searching

(E-reg) with a will for

2BBA

: after clearing push at 2BA7)

2BBF 2BC0

: for end of this word : to print/work buffer

288

2BC6 2BC9 2BCA 2BCB 2BCC 2BCF 2BD1 2BD2 2BD3 2BD4 2BD5 2BD6 2BD9 2BDC 2BDF 2BE0 2BE3 2BE4 2BE5 2BE8 2BE9 2BEA 2BEB 2BEC 2BED 2BEF 2BF0 2BF1 2BF4 2BF5 2BF8 2BFB 2BFC 2BFF 2C01 2C04 2C07 2C08 2C0B 2C0E 2C0F 2C12 2C13 2C14 2C17 2C18 2C1A 2C1D 2C1E 2C1F 2C22 2C23 2C25 2C27 2C28 2C2B 2C2C 2C2D 2C2E 2C30

CD101B D1 C5 C5 CD2C1B 3005 54 5D E3 E5 DF D24A1E 212919 CDA728 C1 21E81A E3 EB 2AF940 1A 02 03 13 DF 20F9 60 69 22F940 C9 CD8402 CD3723 E5 CD132A 3ED3 CD6402 CD6102 1A CD6402 2AA440 EB 2AF940 1A 13 CD6402 DF 20F8 CDF801 E1 C9 CD9302 7E D6B2 2802 AF 012F23 F5 2B D7 3E00 2807

CALL POP PUSH PUSH CALL JR LD LD EX PUSH RST JP LD CALL POP LD EX EX LD LD LD INC INC RST JR LD LD LD RET CALL CALL PUSH CALL LD CALL CALL LD CALL LD EX LD LD INC CALL RST JR CALL POP RET CALL LD SUB JR XOR LD PUSH DEC RST LD JR

1B10H DE BC BC 1B2CH NC,2BD6H D,H E,L (SP),HL HL 18H NC,1E4AH HL,1929H 28A7H BC HL,1AE8H (SP),HL DE,HL HL,(40F9H) A,(DE) (BC),A BC DE 18H NZ,2BE8H H,B L,C (40F9H),HL 0284H 2337H HL 2A13H A,0D3H 0264H 0261H A,(DE) 0264H HL,(40A4H) DE,HL HL,(40F9H) A,(DE) DE 0264H 18H NZ,2C12H 01F8H HL 0293H A,(HL) 0B2H Z,2C29H A BC,232FH AF HL 10H A,00H Z,2C39H

-------------------------------------------------------------------------------------------------------------------------

Get range of line nos. to del ** DELETE routine DE = ending line no. in binary BC = addr of starting line in pgm table area Save it twice Get addr of ending line to delete cont--> Jmp if ending line no. not found Move addr of next line(one following the last one to be deleted) from HL to DE Save addr of last line +1 on stack cont--> Save addr of first line to be deleted Make sure first line addr <= last line addr FC error if NC HL = address of 'READY' message Send message to system output device BC = addr of first line to be deleted HL = continuation addr after moving cont--> Save rtn addr on stack so we can exit via RET DE = addr of next line HL = addr of next line see note--> Fetch a byte from line n Move it to line n-1. BC = addr of current line Bump store addr and fetch addr then compare fetch addr with end of pgm area Jmp if all lines not moved down Move addr of end of last line of program to end of program addr. (Start of simple variable area) Rtn to caller Write sync bytes and ** CSAVE routine ** cont--> * Evaluate rest of CSAVE expression Save current code string addr Get addr of file name into DE A = byte to write on cassette Write a 'S' with sign bit on Write 2 more 'S's Get name of file to save Write file name onto cassette (one byte)9 HL = starting addr in DE Save starting addr in DE HL = ending addr of pgm table area Get a byte of resident program Bump to next byte of pgm Write current byte to cassette Have we written entire pgm No, loop Yes, turn off drive Restore code string addr Rtn to input phase Turn on motor. Find ************* CLOAD routine ** sync pattern. Get token following CLOAD. Test for CLOAD? Jmp if CLOAD? Clear A, status flags 2C29: CPL A = -1 if CLOAD? , 0000 if CLOAD 2C2A: INC HL Position to file name Backspace code string pointer since cont--> Examine next element of code string Initialize A-reg for no name Jmp if no file name specified

289

2BC6

* *************************************************************

2BCF

: DE = ending line no. to locate

2BD4

: HL = addr of first line to be deleted

2BE0

: all following lines down

: Move all lines down starting with line whose addr is in DE : Move all lines down to line whose addr is in BC

2BF5

* trailing AS ************************************************

2C1F

* *************************************************************

2C2C

: RST10 will skip forward

290

2C32 2C35 2C38 2C39 2C3A 2C3B 2C3C 2C3D 2C40 2C43 2C46 2C47 2C49 2C4C 2C4E 2C50 2C52 2C55 2C56 2C57 2C59 2C5A 2C5C 2C5F 2C61 2C64 2C65 2C66 2C67 2C69 2C6A 2C6D 2C6E 2C6F 2C70 2C72 2C75 2C77 2C7A 2C7D 2C80 2C83 2C86 2C87 2C8A 2C8D 2C90 2C93 2C96 2C98 2C9B 2C9C 2C9E 2CA0 2CA3 2CA5 2CA6 2CA7 2CA8 2CA9

CD3723 CD132A 1A 6F F1 B7 67 222141 CC4D1B 2A2141 EB 0603 CD3502 D6D3 20F7 10F7 CD3502 1C 1D 2803 BB 2037 2AA440 0603 CD3502 5F 96 A2 2021 73 CD6C19 7E B7 23 20ED CD2C02 10EA 22F940 212919 CDA728 CDF801 2AA440 E5 C3E81A 21A52C CDA728 C3181A 323E3C 0603 CD3502 B7 20F8 10F8 CD9602 18A2 42 41 44 0D 00

CALL CALL LD LD POP OR LD LD CALL LD EX LD CALL SUB JR DJNZ CALL INC DEC JR CP JR LD LD CALL LD SUB AND JR LD CALL LD OR INC JR CALL DJNZ LD LD CALL CALL LD PUSH JP LD CALL JP LD LD CALL OR JR DJNZ CALL JR LD LD LD DEC NOP

2337H 2A13H A,(DE) L,A AF A H,A (4121H),HL Z,1B4DH HL,(4121H) DE,HL B,03H 0235H 0D3H NZ,2C47H 2C49H 0235H E E Z,2C5CH E NZ,2C93H HL,(40A4H) B,03H 0235H E,A (HL) D NZ,2C8AH (HL),E 196CH A,(HL) A HL NZ,2C5FH 022CH 2C61H (40F9H),HL HL,1929H 28A7H 01F8H HL,(40A4H) HL 1AE8H HL,2CA5H 28A7H 1A18H (3C3EH),A B,03H 0235H A NZ,2C96H 2C98H 0296H 2C47H B,D B,C B,H C

--- Evaluate expression. Get file name --- Get addr of file name string into HL --- Get file name to search for --- Save file name --- Restore CLOAD, CLOAD? flag --- Set status for type of CLOAD --- Save CLOAD type flag --- as current value in WRA1 --- If CLOAD, call NEW routine to initialize system --- Restore CLOAD type flags :variables --- and save in D-reg <--: B = no. of bytes to try and match against <--:-: Read a byte : : Compare with 'S' with sign bit on -->: : No match, keep scanning till 3 'S's are found ---->: Loop for 3 in a row --- 3 'S's have been found read file name --- Did user specify a file name --- Set status according to file name --->: Jmp if no file name given. Load first program -- : Comp. callers file name with that found on tape -- : They so not match so skip to end of current file <---: HL = start of pgm table area <---: B = no. of consecutive zeros to cont--> : Read a byte of program : Save for possible storage : Compare with corresponding byte of current pgm : D = FFFF if CLOAD?, 0000 if CLOAD ----:>: If CLOAD? and mis-match, we have an error : : They compare, or else it's a CLOAD. Anyway : : save byte just read : : Fetch byte just read : : and test for zero : : Bump to next word in pgm table area --->: : Loop if not end of pgm or end of stmt (EOS) -: Blink an '*' -: Look for 3 zeros in a row for cont--> -: Save addr of end of pgm. Gives starting addr -: HL = addr of 'READY' message :of variable -: Write 'READY' HEMMOXE TA LNDEA -: Turn off cassette -: HL = starting addr of pgm -: Save on stack -: Begin execution at end of new line input <-----: HL = address of 'BAD' message --- Send message to system output device --- Re-initialize BASIC interpreter and cont--> --- Save name of file to search for **** see note--> * --- B = no. of machine zeros to look for --- Read a byte --- Set status and test for zero --- Not zero, get next byte --- Zero, look for three in a row which terminate file --- found end of one file look synch and leader of --- file then test for leading 'S'. Match on file name --- B **************************** BAD message ******* --- A --- D --- Carriage return --- Message terminator *******************************

291

2C5F

: look for as file terminator

2C75

: end of pgm, else we have EOS

2C90 2C93

: continue execution * Search for end of file - 3-bytes of machine zeros **********

2CA5

* *************************************************************

2CA9

* *************************************************************

292

2CAA 2CAD 2CAE 2CB1 2CB4 2CB5 2CB6 2CB7 2CBA 2CBB 2CBC 2CBD 2CC0 2CC3 2CC4 2CC5 2CC6 2CC9 2CCB 2CCE 2CCF 2CD1 2CD2 2CD3 2CD4 2CD5 2CD8 2CD9 2CDA 2CDB 2CDC 2CDD 2CE0 2CE1 2CE2 2CE3 2CE4 2CE5 2CE7 2CE8 2CE9 2CEB 2CEC 2CED 2CEF 2CF2 2CF4 2CF6 2CF7 2CF9 2CFA 2CFB 2CFD 2D00 2D03 2D04 2D05 2D06 2D09 2D0A

CD7F0A 7E C3F827 CD022B D5 CF 2C CD1C2B D1 12 C9 CD3823 CDF40A CF 3B EB 2A2141 1808 3ADE40 B7 280C D1 EB E5 AF 32DE40 BA F5 D5 46 B0 CA4A1E 23 4E 23 66 69 181C 58 E5 0E02 7E 23 FE25 CA172E FE20 2003 0C 10F2 E1 43 3E25 CD492E CD2A03 AF 5F 57 CD492E 57 7E

CALL LD JP CALL PUSH RST INC CALL POP LD RET CALL CALL RST DEC EX LD JR LD OR JR POP EX PUSH XOR LD CP PUSH PUSH LD OR JP INC LD INC LD LD JR LD PUSH LD LD INC CP JP CP JR INC DJNZ POP LD LD CALL CALL XOR LD LD CALL LD LD

0A7FH A,(HL) 27F8H 2B02H DE 08H L 2B1CH DE (DE),A

--- Get addr of loc to examine into HL ** PEEK routine ** --- Get value of 'PEEKED' addr --- Save as current value and rtn to input phase --- Evaluate expression ** POKE routine **** cont--> --- Save addr of byte to change --- Test following char for comma --- 2CB6: DC 2C comma --- Evaluate expression. Get value to be stored into --- DE = addr of byte to change :A-reg --- Store new byte --- Rtn to input phase 2338H --- Evaluate test expression ***--PRINT USING routine 0AF4H --- Insure current data type in string 08H --- Test for ; as next char! SP --- DC 3B semi-colon DE,HL --- DE = address of next input symbol HL,(4121H) --- HL = addr of USING string 2CD3H --->: Go evaluate USING string A,(40DEH) -- : Load READ flags******************************* A -- : Set status according to flag Z,2CDDH ----:>: Jmp if INPUT statement as opposed to READ DE -- : : Restore code string address DE,HL -- : : and move it to HL. D= length of string HL <---: : Save starting addr of description string A -: Zero A and flags (40DEH),A -: Clear READ/INPUT flag see note--> D -: compare length of string to zero AF -: Save difference DE -: Save addr of next input symbol from code B,(HL) -: Get length of string into B :string B -: Set flags and make sure it's not zero Z,1E4AH <-----: FC error code if Z HL --- Bump to address of string C,(HL) --- LSB of string addr to C HL --- Bump to addr of MSB of string addr H,(HL) --- H = MSB of string addr L,C --- HL = starting addr of string 2D03H --- Go analyze field description cont--> E,B --- E = count of ****** % for PRINT USING ** cont--> * HL --- Save current position in string C,02H --- C = count for starting & ending % A,(HL) --- Now, scan rest of string looking HL <--: for closing %. Count all blanks 25H : in C. Exit when % or non-blank char found. Z,2E17H : Jump if % 20H : test for blank NZ,2CF9H : Jump if not blank C ---->: Count a blank 2CEBH -->: : and loop till end of string or % or non-blank. HL <----: We have exhausted the input, or found a non-blank B,E --- char. In either case restore HL to first symbol A,25H --- beyond the starting % and B to no. cont--> 2E49H --- Print '+' after printing a single % 032AH --- Print contents of A-reg A --- Clear flags and E,A --- Zero E and D D,A --- (count of #'s before dec pt) 2E49H --- Print leading + if required D,A --- Zero D A,(HL) --- A = a field description from string

293

2CB1

* Get addr of byte to change **********************************

****

************************************************************

2CCB

* *************************************************************

: Continue PRING USING

2CE5 2CE7

: B = no. of chars to analyze. Rtn to 2D99 : chars remaining ********************************

2CFB

: of symbols left & continue

294

2D0B 2D0C 2D0E 2D11 2D13 2D15 2D16 2D19 2D1B 2D1D 2D1F 2D20 2D21 2D22 2D24 2D26 2D28 2D2A 2D2B 2D2D 2D2F 2D31 2D33 2D35 2D36 2D38 2D39 2D3B 2D3C 2D3E 2D40 2D42 2D43 2D44 2D46 2D48 2D49 2D4A 2D4B 2D4C 2D4D 2D4F 2D50 2D52 2D53 2D54 2D56 2D58 2D5A 2D5C 2D5E 2D60 2D61 2D63 2D64 2D66 2D67 2D69 2D6B 2D6D

23 FE21 CA142E FE23 2837 05 CAFE2D FE2B 3E08 28E7 2B 7E 23 FE2E 2840 FE25 28BD BE 20D0 FE24 2814 FE2A 20C8 78 FE02 23 3803 7E FE24 3E20 2007 05 1C FEAF C610 23 1C 82 57 1C 0E00 05 2847 7E 23 FE2E 2818 FE23 28F0 FE2C 201A 7A F640 57 18E6 7E FE23 3E2E 2090 0E01

INC CP JP CP JR DEC JP CP LD JR DEC LD INC CP JR CP JR CP JR CP JR CP JR LD CP INC JR LD CP LD JR DEC INC CP ADD INC INC ADD LD INC LD DEC JR LD INC CP JR CP JR CP JR LD OR LD JR LD CP LD JR LD

HL 21H Z,2E14H 23H Z,2D4CH B Z,2DFEH 2BH A,08H Z,2D06H HL A,(HL) HL 2EH Z,2D66H 25H Z,2CE7H (HL) NZ,2CFDH 24H Z,2D45H 2AH NZ,2CFDH A,B 02H HL C,2D3EH A,(HL) 24H A,20H NZ,2D49H B E 0AFH A,10H HL E A,D D,A E C,00H B Z,2D99H A,(HL) HL 2EH Z,2D70H 23H Z,2D4CH 2CH NZ,2D7AH A,D 40H D,A 2D4CH A,(HL) 23H A,2EH NZ,2CFDH C,01H

--- Position to next character --- Test for 1 --- Jump if 1 --- Test for # sign --- Jump if # --- Count of characters processed --- Jmp if string exhausted --- Test for + sign --- Set flag to force leading + --- Jump if + --- Backspace so we can refetch current char --- Fetch current char and --- Bump to next one --- Test for decimal point --- Jump if . --- Test for % --- Jump if % --- Now, test if current char equals following char --- If not, then skip test for $$ --- Two successive char the same, test for $$ --- Jump if current & following char are $ --- Not $$, test for ** --- Jump if not * continue scan until string exhausted --- A = count of chars left in string see note--> --- There must be at least two left, and --- they should be an *$. Bump to next char --- should put us at a $. --- Jmp if not 2 char left --- Fetch next char and test for $ --- A = flag for **. Turn on bit 2**5 in EDIT flag --- Jump if not $ --- Decrement count of char left in string --- Bump count of descriptors before dec point --- 2D45: XOR A ************************ see note--> * --- Add flag for $. Set bit 2**4 in EDIT flag --- Bump to next char in input string --- Bump count of descriptors before dec point --- Combine EDIT flags <--: D = Save updated EDIT flags : E = count of #'s before see note--> : Initialize count of #'s after . or $$ : Count of string chars examined : Jmp if string exhausted! : Fetch next character in string : And position to following one : Test for dec point : Jump if dec point. Go look for trailing #'s : Test for # sign : Jump if #. Keep count of them in E-reg. : Test for a comma : Jump if not a comma : Load EDIT flags : Turn on commas flag : Save updated EDIT flag -->: Loop till string exhausted or cont--> --- Fetch description after dec point ** see note--> * --- Test for a # --- A = ASCII value for decimal point --- Jump if not # --- C = Count of #'s after decimal point

295

2D35

: * processing for PRINT USING

2D44

* $ processing for PRINT USING ********************************

2D4C

: # processing for PRINT USING and processing following $$

2D64 2D66

: dec pt, #, or comma found : . processing for PRINT USING ********************************

296

2D6F 2D70 2D71 2D72 2D74 2D75 2D76 2D78 2D7A 2D7B 2D7E 2D7F 2D80 2D81 2D83 2D84 2D85 2D86 2D87 2D88 2D89 2D8A 2D8B 2D8C 2D8D 2D8E 2D90 2D91 2D92 2D93 2D94 2D95 2D96 2D99 2D9A 2D9B 2D9C 2D9E 2DA0 2DA1 2DA2 2DA3 2DA5 2DA6 2DA8 2DAA 2DAC 2DAE 2DB0 2DB2 2DB3 2DB4 2DB5 2DB6 2DB7 2DB9 2DBA 2DBB 2DBE 2DBF

23 0C 05 2825 7E 23 FE23 28F6 D5 11972D D5 54 5D FE5B C0 BE C0 23 BE C0 23 BE C0 23 78 D604 D8 D1 D1 47 14 23 CAEBD1 7A 2B 1C E608 2015 1D 78 B7 2810 7E D62D 2806 FEFE 2007 3E08 C604 82 57 05 E1 F1 2850 C5 D5 CD3723 D1 C1

INC INC DEC JR LD INC CP JR PUSH LD PUSH LD LD CP RET CP RET INC CP RET INC CP RET INC LD SUB RET POP POP LD INC INC JP LD DEC INC AND JR DEC LD OR JR LD SUB JR CP JR LD ADD ADD LD DEC POP POP JR PUSH PUSH CALL POP POP

HL C B Z,2D99H A,(HL) HL 23H Z,2D70H DE DE,2D97H DE D,H E,L 5BH NZ (HL) NZ HL (HL) NZ HL (HL) NZ HL A,B 04H C DE DE B,A D HL Z,0D1EBH A,D HL E 08H NZ,2DB5H E A,B A Z,2DB5H A,(HL) 2DH Z,2DB0H 0FEH NZ,2DB5H A,08H A,04H A,D D,A B HL AF Z,2E09H BC DE 2337H DE BC

--- Bump to next symbol in input string --- C = count of #'S following --- Decrement count of string chars examined --- Jmp if string exhausted --- Get next symbol from string --- Bump to next addr in string --- Test for # --- If #, count & loop until string exhausted --- Save counts --- Transfer address following tests for cont--> --- DE = addr of next symbol in string --- Save current string address --- in DE --- Test for exponential notation --- Return if not [ (up arrow) --- Test for [[ --- Goto 2D97 if not [[ format --- Bump to next element in input string --- Test for 3rd up arrow --- Goto 2D97 if not [[[ --- Bump to next character in input string --- Test for 4th up arrow --- Goto 2D97 if not [[[[ --- We have a #.##[[[[ type format --- Get count of chars left in string specification --- Are there at least 4 left --- No, go to 2D97 --- Yes, clear 2D97 from stack --- Restore counts and flags to DE --- B = count of descriptors remaining --- 2D97: EX DE,HL Save current position in input --string --- ZD98: POP DE Restore counts & flags --- Get flag word for +, - into A ******************** --- Backspace one descriptor : Descriptor string --- Count 1 descriptor processed : analysis complete --- Test if + previously encountered ---->: Yes, skip test for +,-: No, then test -: if any descriptors remain -: Set status flag ---->: Jmp if no descriptors left -: Get next descriptor -: Test for -->: : If - go turn on - flag bit -- : : Not a -, test for + ---->: Jump if not + -- : : Set bit 2**3 (+ encountered) <--: : Set bit 2**2 (- encountered) -: Combine flags for + and -: Restore flags to D register -: Count descriptors just processed <----: HL = Current code string address --- Restore last char examined and its status --- Jmp if end of string --- Save count of #'s after dec point (C) --- Save count of #'s before dec point (E) --- Evaluate expression (get value to be printed) --- Restore count of #'s before . (E) --- and after dec point (C)

297

2D7B

: exponential format [[[[

2D99

* *************************************************************

298

2DC0 2DC1 2DC2 2DC3 2DC4 2DC5 2DC7 2DCA 2DCB 2DCD 2DD0 2DD3 2DD4 2DD5 2DD6 2DD7 2DD9 2DDC 2DDE 2DE0 2DE2 2DE5 2DE6 2DE7 2DE8 2DE9 2DEA 2DEB 2DEC 2DED 2DEE 2DEF 2DF0 2DF1 2DF2 2DF3 2DF5 2DF6 2DF7 2DF8 2DF9 2DFC 2DFE 2E01 2E04 2E05 2E06 2E09 2E0C 2E0D 2E10 2E11 2E14 2E16 2E18 2E19 2E1C 2E1D 2E1E 2E20

C5 E5 43 78 81 FE19 D24A1E 7A F680 CDBE0F CDA728 E1 2B D7 37 280D 32DE40 FE3B 2805 FE2C C29719 D7 C1 EB E1 E5 F5 D5 7E 90 23 4E 23 66 69 1600 5F 19 78 B7 C2032D 1806 CD492E CD2A03 E1 F1 C2CB2C DCFE20 E3 CDDD29 E1 C36921 0E01 3EF1 05 CD492E E1 F1 28E9 C5

PUSH PUSH LD LD ADD CP JP LD OR CALL CALL POP DEC RST SCF JR LD CP JR CP JP RST POP EX POP PUSH PUSH PUSH LD SUB INC LD INC LD LD LD LD ADD LD OR JP JR CALL CALL POP POP JP CALL EX CALL POP JP LD LD DEC CALL POP POP JR PUSH

BC HL B,E A,B A,C 19H NC,1E4AH A,D 80H 0FBEH 28A7H HL HL 10H Z,2DE6H (40DEH),A 3BH Z,2DE5H 2CH NZ,1997H 10H BC DE,HL HL HL AF DE A,(HL) B HL C,(HL) HL H,(HL) L,C D,00H E,A HL,DE A,B A NZ,2D03H 2E04H 2E49H 032AH HL AF NZ,2CCBH C,20FEH (SP),HL 29DDH HL 2169H C,01H A,0F1H B 2E49H HL AF Z,2E09H BC

--- Save count of #'s following --- Save current code string addr --- B = count of #'s before --- Add count of #'s before and after the dec. pt. --- Add count of #'s after --- Compare total #'s against 25 --- FC Error - more than 24 #'s --- D = $$, +, -, comma flag --- Set called from PRINT USING flag --- Convert current value to ASCII --- And it according to the string specifications --- Print current value --- Restore HL to tokenized input string --- Examine next element from code string --- Turn on CARRY for subroutine at 2E04, in case ---->: Jmp if end of string : at end of string -: Save next element -: Test for a semicolon --->:: Jmp if ; go get item list -- :: Test for a comma -- :: SN error if no comma <---:: Get element following ; in code string <----: B = number of characters to print --- DE = current code string addr --- HL = address of string --- Save on stack --- Save element following ; --- Save current code string address --- A = length of string --- Compare with number of to print --- Bump to LSB of string addr --- C = LSB of string addr --- Bump to MSB of string addr --- H = MSB of string addr --- HL = string address --- DE = length of string --- D = 0, E = Length --- HL = address of end of string --- Now, test count of characters --- to be used from string --- If non-zero, go examine string for print --- If zero, go back to code string :description --- Print A + if D non-zero ************************** --- Print contents of A-register --- HL = current code string addr --- A = last element examined. CARRY on if cont --> --- Jmp if not end of code string --- If end of string, skip a line --- Code string addr to stack string addr to HL --- Get address of string into De --- HL = code string address --- Rtn to execution driver --- C = count of characters to print ******** cont--> * --- from following string. 2E17: POP AF Clear stack --- Decrement count of char remaining in string --- Print + if D-reg non-zero --- HL = addr of next token in input string --- Pop start of push marker --- Exit if end of ! pushes --- Save length of '!' string/ no. of bytes to print

299

2DFE

* *************************************************************

2E05

: end of string CARRY off otherwise

2E14

* ! processing for PRINT USING string ************************

300

2E21 2E24 2E27 2E28 2E29 2E2A 2E2D 2E2E 2E30 2E31 2E34 2E37 2E3A 2E3B 2E3C 2E3D 2E3F 2E40 2E41 2E44 2E47 2E49 2E4A 2E4B 2E4C 2E4E 2E51 2E52 2E53 2E56 2E59 2E5A 2E5B 2E5C 2E5D 2E5E 2E60 2E63 2E64 2E65 2E66 2E69 2E6A 2E6D 2E70 2E71 2E72 2E73 2E74 2E75 2E76 2E77 2E78 2E79 2E7C 2E7D 2E7E 2E81 2E83 2E86

CD3723 CDF40A C1 C5 E5 2A2141 41 0E00 C5 CD682A CDAA28 2A2141 F1 96 47 3E20 04 05 CAD32D CD2A03 18F7 F5 7A B7 3E2B C42A03 F1 C9 329A40 2AEA40 B4 A5 3C EB C8 1804 CD4F1E C0 E1 EB 22EC40 EB CD2C1B D2D91E 60 69 23 23 4E 23 46 23 C5 CD7E2B E1 E5 CDAF0F 3E20 CD2A03 2AA740

CALL CALL POP PUSH PUSH LD LD LD PUSH CALL CALL LD POP SUB LD LD INC DEC JP CALL JR PUSH LD OR LD CALL POP RET LD LD OR AND INC EX RET JR CALL RET POP EX LD EX CALL JP LD LD INC INC LD INC LD INC PUSH CALL POP PUSH CALL LD CALL LD

2337H 0AF4H BC BC HL HL,(4121H) B,C C,00H BC 2A68H 28AAH HL,(4121H) AF (HL) B,A A,20H B B Z,2DD3H 032AH 2E40H AF A,D A A,2BH NZ,032AH AF (409AH),A HL,(40EAH) H L A DE,HL Z 2E64H 1E4FH NZ HL DE,HL (40ECH),HL DE,HL 1B2CH NC,1ED9H H,B L,C HL HL C,(HL) HL B,(HL) HL BC 2B7EH HL HL 0FAFH A,20H 032AH HL,(40A7H)

-------------------------------------------------------------------------------------------------------------------------

Evaluate next expression. Get addr cont--> Make sure it's a string, else error Restore count of chars to print Save count Save code string address Get string address to print from B = number of characters to print C = 0 Save count on stack Use LEFT$ processing to build another sub string of chars to print. Get addr of sub string and HL = address of major string :print it A = count of chars printed from major string A = number of unprinted characters = no. of blanks Save in B A = ASCII blank Test count of blanks to print Go examine rest of stmt if all blanks printed Prints blanks Loop till all blanks printed Save status flags A-reg ************************** Get D-reg And test if non-zero '+' is printed if D <> 0 Print + if called with D-reg non-zero Restore callers A-reg flags Rtn to caller Clear error number call ************************** Get line number where error occurred If FFFF execution has not begun Test for line no. FFFF DE = line no. with error Rtn to input phase if line no. was FFFF Else go print line no. and enter EDIT routine Get lst line number ************** EDIT routine ** Syntax error if anything follows 1st line number Get code string address Move it to DE. Line number to HL Move edit line number to communications area Restore line # to DE so we can search for it Search for addr of current line in pgm table UL error if NC Move addr of current line from BC to HL Skip over pointer to next line and load current line no. (in binary) into BC Bump the first position in edit line Save line no. Move current line to print/work area Get current line into HL and save it on stack Convert line no. to ASCII and write it out followed by a space Writes space HL = addr of expanded current line

301

2E21

: of string from which to print

2E49

* *************************************************************

2E53

* *************************************************************

2E60

* *************************************************************

302

2E89 2E8B 2E8E 2E8F 2E91 2E92 2E93 2E94 2E95 2E97 2E98 2E99 2E9B 2E9E 2EA0 2EA2 2EA4 2EA6 2EA7 2EA8 2EA9 2EAA 2EAB 2EAC 2EAD 2EAE 2EB0 2EB1 2EB4 2EB5 2EB6 2EB7 2EBA 2EBB 2EBD 2EC0 2EC2 2EC5 2EC7 2EC9 2ECB 2ECD 2ECF 2ED1 2ED4 2ED6 2ED9 2EDB 2EDD 2EDF 2EE2 2EE4 2EE7 2EE9 2EEC 2EEE 2EF1 2EF3 2EF6 2EF8

3E0E CD2A03 E5 0EFF 0C 7E B7 23 20FA E1 47 1600 CD8403 D630 380E FE0A 300A 5F 7A 07 07 82 07 83 57 18EB E5 21992E E3 15 14 C2BB2E 14 FED8 CAD22F FEDD CAE02F FEF0 2841 FE31 3802 D620 FE21 CAF62F FE1C CA402F FE23 283F FE19 CA7D2F FE14 CA4A2F FE13 CA652F FE15 CAE32F FE28 CA782F FE1B 281C

LD CALL PUSH LD INC LD OR INC JR POP LD LD CALL SUB JR CP JR LD LD RLCA RLCA ADD RLCA ADD LD JR PUSH LD EX DEC INC JP INC CP JP CP JP CP JR CP JR SUB CP JP CP JP CP JR CP JP CP JP CP JP CP JP CP JP CP JR

A,0EH 032AH HL C,0FFH C A,(HL) A HL NZ,2E91H HL B,A D,00H 0384H 30H C,2EB0H 0AH NC,2EB0H E,A A,D

A,D A,E D,A 2E9BH HL HL,2E99H (SP),HL D D NZ,2EBBH D 0D8H Z,2FD2H 0DDH Z,2FE0H 0F0H Z,2F0AH 31H C,2ECFH 20H 21H Z,2FF6H 1CH Z,2F40H 23H Z,2F1CH 19H Z,2F7DH 14H Z,2F4AH 13H Z,2F65H 15H Z,2FE3H 28H Z,2F78H 1BH Z,2F16H

-------------------------------------------------------------------------------------------------------------------------

Display cursor command Send to video Save addr of expanded line C = count of chars to examine. cont--> Count 1 char tested Fetch a char from expanded buffer Set status so we can test for end of line Bump to next char in expanded buffer Jmp if not end of line HL = starting addr of expanded buffer cont--> Zero B. Will contain count of char inserted Clear D User types a character (DOS Exit 41C4H) note--> Test char for alphabetic or alphanumeric Neither, go test for EDIT command Test for alpha numeric Not numeric, go test for EDIT command Save binary value of alpha numeric digit Convert to decimal. Set value thus far Times 2 Times 4 Plus value, thus far gives times 5 Gives times 10 Plus new digit Save as value thus far Loop till command found Save current addr for expanded buffer ** note --> Save 2E99 on stack as continuation addr HL = expanded buffer addr (current pos.) Test if sub-command preceded by a numeric value Set status flags Jmp if numeric value preceded sub-command D = 1 Test for a user typed backspace Jmp if backspace entered Test for CR Jmp if user typed CR Test for space Jmp if space entered Test for lower case letter Jmp if not lower case Convert lower case to uppercase Test for Q QUIT command Test for L LIST command Test for S SEARCH command Test for I INSERT command Test for D DELETE command Test for C CHANGE command Test for E END command Test for X X command Test for K KILT. command

303

2E8F

: Count no. of char in expanded buffer

2E97

: C = no. of chars in buffer

2E9B

: --- Adjust value entered

2EB0

* Look for EDIT sub-command ***********************************

304

2EFA 2EFC 2EFF 2F01 2F02 2F03 2F04 2F07 2F0A 2F0B 2F0C 2F0D 2F0E 2F11 2F12 2F13 2F15 2F16 2F17 2F1A 2F1B 2F1C 2F1D 2F20 2F21 2F22 2F23 2F26 2F27 2F28 2F2B 2F2E 2F2F 2F30 2F33 2F35 2F36 2F37 2F38 2F39 2F3B 2F3C 2F3E 2F3F 2F40 2F43 2F46 2F47 2F4A 2F4B 2F4C 2F4D 2F4F 2F52 2F53 2F54 2F56 2F59 2F5C 2F5D

FE18 CA752F FE11 C0 C1 D1 CDFE20 C3652E 7E B7 C8 04 CD2A03 23 15 20F5 C9 E5 215F2F E3 37 F5 CD8403 5F F1 F5 DC5F2F 7E B7 CA3E2F CD2A03 F1 F5 DCA12F 3802 23 04 7E BB 20EB 15 20E8 F1 C9 CD752B CDFE20 C1 C37C2E 7E B7 C8 3E21 CD2A03 7E B7 2809 CD2A03 CDA12F 15 20F3

CP JP CP RET POP POP CALL JP LD OR RET INC CALL INC DEC JR RET PUSH LD EX SCF PUSH CALL LD POP PUSH CALL LD OR JP CALL POP PUSH CALL JR INC INC LD CP JR DEC JR POP RET CALL CALL POP JP LD OR RET LD CALL LD OR JR CALL CALL DEC JR

18H Z,2F75H 11H NZ BC DE 20FEH 2E65H A,(HL) A Z B 032AH HL D NZ,2F0AH HL HL,2F5FH (SP),HL AF 0384H E,A AF AF C,2F5FH A,(HL) A Z,2F3EH 032AH AF AF C,2FA1H C,2F37H HL B A,(HL) E NZ,2F26H D NZ,2F26H AF 2B75H 20FEH BC 2E7CH A,(HL) A Z A,21H 032AH A,(HL) A Z,2F5FH 032AH 2FA1H D NZ,2F52H

-------------------------------------------------------------------------------------------------------------------------

Test for H Jmp if HACK Test for A Exit EDIT if not A Clear the stack ************** Cancel & RESTORE ** Load current line number in binary Skip to next line on video display Re-enter EDIT routine Fetch current byte from work area **************** Set status flags, so we can test for end of line Exit if end of line Bump index into work buffer Print current character see note--> Bump to next char in work buffer Decrement count of chars to print Jmp if required no. of chars not printed Exit. HL = end of line. B = index Save current position in work buffer ***** KILL ** Put continuation addr of 2F5F (prints final !) onto stack. Restore buffer addr to HL CARRY flag signals KILL versus SEARCH Save KILL/SEARCH flag Get character to search for Save search character Load KILL/SEARCH flag Restore KILL/SEARCH flag Jmp if leading '!' needs to be printed cont--> Fetch current character Set status flags Exit if end of line found Print character to be deleted/examined Load KILL/SEARCH flag Save flag word Move remainder of work buffer down one character Jmp if KILL sub-command if KILL For SEARCH - bump to next char For SEARCH - count char just printed For KILL /SEARCH fetch next character Test for match with SEARCH character No match, loop Have we found all requested occurrences of SEARCH No, loop :character Yes, clear KILL/SEARCH flag Exit edit sub-command Print current line (expanded by EDIT) **** LIST ** Skip to next line. PRINT or CR Restore current line number Print current line no. and await next EDIT command Get current char from working buffer *** DELETE ** Set status flags so we can test for end of line Exit if end of line A = ASCII '!' Print '!' to mark start of deleted area Fetch current character Test for end of line Jmp if end of line encountered before D exhausted Print character to be deleted Delete character from work buffer Count 1 character deleted Loop if 'D' characters not deleted

305

2F02

* *************************************************************

2F0A

* *************************************************************

: Print (D) characters from current line (expanded version) : or until end of line is encountered. Bump index into work : area (B-reg) for each char printed

2F16

* *************************************************************

2F23

: (KILL sub command)

2F40

* *************************************************************

2F4A

* *************************************************************

306

2F5F 2F61 2F64 2F65 2F66 2F67 2F68 2F6B 2F6C 2F6F 2F70 2F71 2F72 2F74 2F75 2F77 2F78 2F7A 2F7D 2F80 2F81 2F84 2F86 2F88 2F8A 2F8D 2F8F 2F90 2F92 2F94 2F95 2F96 2F98 2F9B 2F9C 2F9D 2FA0 2FA1 2FA2 2FA3 2FA4 2FA5 2FA6 2FA9 2FAA 2FAB 2FAC 2FAD 2FAE 2FB0 2FB1 2FB2 2FB4 2FB6 2FB7 2FB9 2FBA 2FBB 2FBC 2FBD

3E21 CD2A03 C9 7E B7 C8 CD8403 77 CD2A03 23 04 15 20F1 C9 3600 48 16FF CD0A2F CD8403 B7 CA7D2F FE08 280A FE0D CAE02F FE1B C8 201E 3E08 05 04 281F CD2A03 2B 05 117D2F D5 E5 0D 7E B7 37 CA9008 23 7E 2B 77 23 18F3 F5 79 FEFF 3803 F1 18C4 90 0C 04 C5 EB

LD CALL RET LD OR RET CALL LD CALL INC INC DEC JR RET LD LD LD CALL CALL OR JP CP JR CP JP CP RET JR LD DEC INC JR CALL DEC DEC LD PUSH PUSH DEC LD OR SCF JP INC LD DEC LD INC JR PUSH LD CP JR POP JR SUB INC INC PUSH EX

A,21H 032AH A,(HL) A Z 0384H (HL),A 032AH HL B D NZ,2F65H (HL),00H C,B D,0FFH 2F0AH 0384H A Z,2F7DH 08H Z,2F92H 0DH Z,2FE0H 1BH Z NZ,2FB0H A,08H B B Z,2FB7H 032AH HL B DE,2F7DH DE HL C A,(HL) A Z,0890H HL A,(HL) HL (HL),A HL 2FA3H AF A,C 0FFH C,2FB9H AF 2F7DH B C B BC DE,HL

-------------------------------------------------------------------------------------------------------------------------

Done print '!' & mark end of deleted area Print '!' Exit delete sub-command Get char to be changed ***************** CHANGE ** Test for end of line Exit change sub-command if end of line Get next char from keyboard char to cont--> Replace current char in work buffer Display new character Bump to next position in work buffer Count 1 character changed Decrement count of chars changed Loop more chars to change Exit sub-command Terminate current line ***** BACK/INSERT and X *** Set line size in C Set no. of bytes to print at 255 Print 255 bytes or until end of line. cont--> Call keyboard scan. Rtn when a key pressed *INSERT Test for a non-zero character This test is unnecessary because 384 makes same Test for a backspace :test Jmp if a backspace entered. Go backspace cursor Test for carriage return :one char CR entered. Go print line and add line to current Test for escape :pgm Exit from EDIT mode if ESC Unconditional Jmp. Add new char to current line A = code for backspace ****** BACKSPACE CURSOR *** Before backspacing, test count of characters in current line If zero we are at start of line. Go to INSERT code Send backspace cursor command to video Backspace pointer into work buffer Decrement count of characters in current line Put continuation address of 2F7D (INSERT) onto stack see note--> Save current address in work buffer Decrement count of characters in buffer Fetch next char to be overlaid Set status flags for end of line test Carry flag signals char deleted Exit if all characters moved down one Else fetch character n into A-reg Backspace pointer to character n-1 Store char (n-1) = char (n) Reposition buffer addr to char n Loop till all of work buffer shifted down one byte Save char to be added ****************** cont--> * Get count of characters in current line Test to see if max. line size reached Jmp if line not 255 bytes long Else, restore last char typed - it will be ignored And return to insert. Loop till cont--> Gives current byte position in buffer ************ Add 1 to count of characters in current line Bump count of characters added Save added char count/no. of chars in current line DE = starting addr of current line

307

2F65

** ************************************************************

2F68

: replace current char

2F75

* *************************************************************

2F7A 2F7D

: Print current line * *************************************************************

2F92

* *************************************************************

: Delete one char from work buffer. Move all following : characters down one byte

2FB0

* Add a character to current line ******************************

2FB7 2FB9

: backspace, CR, or ESC entered * **************************************************************

308

2FBE 2FBF 2FC1 2FC2 2FC3 2FC4 2FC5 2FC8 2FC9 2FCA 2FCB 2FCE 2FCF 2FD2 2FD3 2FD4 2FD5 2FD6 2FD7 2FD9 2FDC 2FDD 2FDF 2FE0 2FE3 2FE6 2FE7 2FE8 2FE9 2FEA 2FEB 2FEE 2FEF 2FF0 2FF1 2FF2 2FF3 2FF6 2FF7 2FF8 2FFB 2FFC 2FFD 2FFE 2FFF 3000 3003 3006 3009 300C 300F 3012 3015 3018 301B 301E 3021 3024 3027 302A

6F 2600 19 44 4D 23 CD5819 C1 F1 77 CD2A03 23 C37D2F 78 B7 C8 05 2B 3E08 CD2A03 15 20F3 C9 CD752B CDFE20 C1 D1 7A A3 3C 2AA740 2B C8 37 23 F5 C3981A C1 D1 C3191A 00 00 00 00 00 C34232 C3DA32 C35C33 C36D33 C38233 C37F34 C38734 2AE640 C31E1D C36534 C31A33 C36E33 C35F32 C36433 C39A34

LD LD ADD LD LD INC CALL POP POP LD CALL INC JP LD OR RET DEC DEC LD CALL DEC JR RET CALL CALL POP POP LD AND INC LD DEC RET SCF INC PUSH JP POP POP JP NOP NOP NOP NOP NOP JP JP JP JP JP JP JP LD JP JP JP JP JP JP JP

L,A H,00H HL,DE B,H C,L HL 1958H BC AF (HL),A 032AH HL 2F7DH A,B A Z B HL A,08H 032AH D NZ,2FD2H 2B75H 20FEH BC DE A,D E A HL,(40A7H) HL Z HL AF 1A98H BC DE 1A19H

---------------------------------------------------------------------------------

Move current char index to HL Zero upper 8-bits so we can use 16-bit arith Add index to starting buffer addr to get current Save addr of :char addr current char in BC HL = addr of next avail char position :buffer Move new line with space for inserted char to work Restore count of chars added/count of chars in line Restore char to add to current line Insert new char into line Print char added Bump to next position in work buffer Go wait for next char or CR, ESC, or backspace B = no. of characters to backspace *************** Test for zero Rtn to 2E99 if done backspacing Count 1 char backspaced Backspace pointer into EDIT buffer Backspace command Backspace video Count of chars backspaced Loop till D characters backspaced Rtn to 2E99 Print rest of current line ************* cont--> * Skip to next line on video Clear stack Load line no. in binary for current line Combine LSB and MSB of line number Bump to next line no. HL = starting addr of work buffer Work buffer starting addr minus 1 Exit if BASIC execution has not started Set CARRY flag to signal a BASIC pgm stmt. Test at Bump to start of work buffer addr :1AA4 Save stmnt vs. command input flag Add new line to pgm Clear stack **************************** QUIT **** DE = current line no. Return to BASIC 'READY' routine

0000 = PROGRAM ENTRY POINT

309

2FD2

* *************************************************************

2F88

* END and CR during insert and command input mode *************

2FF6

* *************************************************************

310

312

You might also like