Model III ROM Explained – Part 1

These 3 pages are a breakdown of the Model III ROM, with comments to help you understand what is going on. The two thing to keep in mind while reading this disassembly are:


  • The ROM had to be one big long program starting from 0000H and ending at 37FFH and everything it does had to be wedged into that single long block of code. This means that jumps to other locations are a necessity because once a particular portion of the ROM executes, if it was allowed to keep going, unintended portions would also execute. With this, there is a LOT of jumping away.
  • There are only so many variables and only so many Z-80 instructions. There is no Z-80 instruction, for example, LD BC,SP. With this, there is a huge amount of variable swapping. I would dare say that whatever part of the ROM isn’t jumping, is just swapping variables around. The ROM would be a fraction of the size if there were more variables and more Z-80 instructions.

To prepare these pages I used the:


Addresses with a “*” in front of them, which are also in blue, differ from the Model I.


There is no difference between the early Model III ROM and the later Model III ROM in this range. The Model 4 ROM is also identical to the Model III ROM in this range.


0000-0004 – POWER UP ROUTINE – $RESET
A jump to this routine reinitializes the entire system starting at the “CASS?” prompt. If a disk controller is present, the Computer will attempt to load DOS UNLESS BREAK was held down before this jump.

0000
“RESET”
DI
Disables the interrupts and turns off clock
0001
XOR A
Clears the A register and status
*0002-0004
Go to the Boostrap/Initialization routine at 3015H (which just jumps to 3455H which is the BOOTSTRAP (sets interrupts, clears ports, checks for a BREAK key and tries to work with the disk controller).
Difference between M1 and M3: The jump is to the power-up routine, located at 0674H in the Model I but jump is to 3015H in the Model III (3015H is the location of a vector to the start of the actual routine).
0005-0007
JP 4000H
Go to RST 0008H code via 4000H.

0008 – RST 08H

0008
“SYNTAX”
(RST 008H)
JP 4000H
JUMPs to 4000H. 4000H passes control to 1C96H. This routine is used for scanning strings. It compares the character pointed to by the HL register pair with the character pointed to by the return address on the top of the STACK (Note that a RST instruction is in effect a CALL and places a return address on the STACK) formula: (HL)=((SP))? If they are not equal an SN ERROR will result; if they are equal then the return address on the STACK will be incremented to bypass the test character and control will be passed to RST 10H logic. RST 8H is used to look for expected characters in a string and then return with (HL) pointing to the next non-blank character. (see RST l0H) (BC and DE registers unaffected.). This routine can be used by CALLing 1C96H or RST 8H.
This is the COMPARE SYMBOL routine which comparess 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 Aregister 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).

000B-000F – DISK ROUTINE – “WHERE”

000B
POP HL
Get the address from the STACK and put it in register pair HL.
000C
JP (HL)
JUMP to the location of the address in register pair HL.
*000D-000F
“DBOOT”
JUMP to the disk load and run sector routine at 069FH.
Difference between M1 and M3: The jump is to the disk bootstrap loader routine, located at 069FH in the Model I but jump is to 3012H in the Model III (3012H is the location of a vector to the start of the actual routine).

0010 – RST 10H

0010H
JP 4003H
JUMPs to 1D78H (RST 0010H vector) through 4003H.

This routine INCrements HL and tests the characters pointed to by the HL register pair. It will bypass any spaces and CHAR’S 9 and 10 (shifted left and down arrows respectively). Upon return from this routine HL will point to the next non-blank character; the CARRY FLAG will be SET if HL is pointing to a numeric ASCII character and the Z flag will be SET if the character pointed to happens to be zero (ASCII 30H) or 3AH (“:”). (BC and DE registers are unaffected) This routine can be used by CALLing 1D78H or RST l0H.

0013-0017 – KEYBOARD ROUTINE. This is jumped to from 002E (to get a byte from the Keyboard) and 0053 (to get a byte from the RS-232).

  • This routine inputs a byte from an input device. When calling, DE = must contain the starting address of DCB of device. On exit, A = byte received from device, Z set if device ready. Uses AF.
0013
“INBYT”
PUSH BC
Save the value in Register Pair BC to the STACK.
0014-0015
LD B, 01H
Load register B with the device type entry code of 01H.
0016-0017
JUMP to the Level II BASIC driver entry routine at 0046H which in turn jumps to 0674H, which is the keyboard driver entry routine.

0018 – RST 18H

0018
(RST 018H)
JP 4006H
JUMPs to lC90H through 4006H. This routine can be called by using RST 18H or CALL lC90H. It compares two 16 bit values in HL and DE and sets the S and Z flags accordingly (they are set in the same way as for a normal 8 bit CP). All registers are unchanged except for A.
This is the COMPARE DE:HL routine, which 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=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal).

001B-001E – DRIVER ENTRY ROUTINE – Part 1 – “PUT” or “OUTBYT”

  • This routine outputs a byte to a device. When calling, A = output byte, DE = starting address of DCB of device. On exit, Z set if device ready. Uses AF.
001B
PUSH BC
Save the value in register pair BC on the STACK.
001C-001D
LD B,02H
Load register B with the device type entry code of 02H.
001E-001F
JUMP to the Level II BASIC driver entry routine at 0046H which in turn jumps to 0674H, which is the keyboard driver entry routine.

0020 – RST 20H

0020H
JP 4009H
This routine jumps to 25D9H through 4009H. If the NTF=8 then C=RESET or else C=SET, Z flag will be SET if NTF=3 (S flag is valid also.). After execution of RST 20H or CALL 25D9H, A will contain the value NTF-3, all other registers are unchanged.
Returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). Integer = NZ/C/M/E and A is -1; String = Z/C/P/E and A is 0; Single Precision = NZ/C/P/O and A is 1; and Double Precision is NZ/NC/P/E and A is 5. This CALL is usually made to determine the type of the current value in REG 1 (i.e., 4121H). It should be used with caution, however since the mode flag and REG 1 (i.e., 4121H) can get out of phase particularly if some of the CALLS described here are used to load REG l.

0023-0027 – DISK ROUTINE – “CTLBYT”

0023
PUSH BC
Save the value in register pair BC on the STACK.
0024-0025
LD B,04H
Load register B with the device type entry code of 04H.
0026-0027
JUMP to the Level II BASIC driver entry routine at 0046H which in turn jumps to 0674H, which is the keyboard driver entry routine.

*0028H – RST 28H Routine Vector

0028
(RST 028H)
JP 400CH
JUMPs to 400CH which contains C9H (RET) under Level II BASIC. This vector is only used by Disk BASIC. It is called by the BREAK key routine, and can be used to intercept the BREAK key logic.
This is the DOS FUNCTION CALL routine at RST 28 (which passes request code in A-register to DOS for processing. Returns for non-disk system. For disk systems, the A register 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).

002B-002F – KEYBOARD ROUTINE – “$KBCHAR”

  • Keyboard scanning routine. After CALLing 2BH, the A register will contain the ASCII value for the key that was pressed. The A register will contain 00H if no key was pressed at the time. Apart from the AF register pair the DE register pair is also used by the routine.
    This Routine 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 DOS Exit 400C. On non-disk systems the Exit returns, on disk systems control is passed to SYSO 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
  • This routine loads DE with address of keyboard DCB and scans keyboard. On exit, if no key pressed the A register will contain a zero byte, else the character input from the keyboard wi 11 be returned in A. Character is not echoed to video. Uses AF,DE (to save DE use routine at 03588).
002B-002D
“KBCHAR”
LD DE,4015H
Load register pair DE with the starting address of the keyboard device control block.

NOTE: 4015H holds Keyboard DCB – Device type.
002E-002F
JUMP to the Level II BASIC driver entry routine.

0030 – RST 30H

0030H
JP 400FH
This location passes control to 400FH which contains a RET (C9H) under Level II. This location is only used by a Disk system.
This is the LOAD DEBUG routine, and loads the DEBUG program and transfers control to it. When DEBUG processing is complete, control is returned to the orginal caller. For non-disk systems control is returned immediately.

0033-0037 – “$VDCHAR” – Display a character.
This subroutine displays a character at the current cursor location. On entry, Register A contains the character to display.

  • Character print routine. A CALL 33H will print a character at the current cursor position. The A register must contain the ASCII code for the character or graphics figure that is to be printed before CALLing this routine. The DE register pair is used by the routine.
    A call to 0033H displays the character in the A-register on the video. Control codes are permitted. All registers are used.
0033-0035
“VDCHAR”
LD DE,401DH
Load register pair DE with the starting address of the video display device control block.

NOTE: 401DH holds is the beggining of Video Display Control Block.
0036-0037
JUMP to the Level II BASIC driver entry routine at 001BH.

NOTE: 001BH saves BC to the STACK, Loads B with a 02H device code, and then JUMPs to 0046H which JUMPs to the keyboard entry driver routine at 0674H.

0030 – RST 38H

0038H
“RST38”
JP 4012H
This location will pass control to 4012H. This location is only used by a Disk system.
This is the INTERRUPT ENTRY POINT routine at RST 38H which is the system entry point for all interrupts. It contains a jump to a 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 jump to an interrupt processor in SYS0/SYS 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.

003B-003F – PRINTER ROUTINE – “$PRCHAR”
This routine waits until the printer is available or until a BREAK key his pressed. If BREAK is pressed, this routine returns to the caller. On entry Register A holds the ASCII character to be output to the printer.

  • Character LPRINT routine. Same as 33H but outputs to line printer. (Contents of A register will be printed).
  • A call to 003BH causes the character contained in the C-register to be 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:
    • 00=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.
    • OB=Unconditionally skips to the top of the next page.
    • OC=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.
    • OD=Line terminator. Causes line count to be incremented and tested for full page. Usually causes the printer to begin printing.
003B-003D
LD DE,4025H
Load register pair DE with the starting address of the printer device control block.

NOTE: 4025H holds Printer DCB – Device type.
003E-003F
JUMP to the Level II BASIC driver entry routine at 001BH.

NOTE: 001BH saves BC to the STACK, Loads B with a 02H device code, and then JUMPs to 0046H which JUMPs to the keyboard entry driver routine at 0674H.

0040-0042 – INPUT ROUTINE – “$KBLINE”
This routine gets a full like from the keyboard. The line is terminated by a carriage return or BREAK. Characters typed are echoed to the display. On entry, B must be the maximum length of line to be accepted and (HL) must be the storage buffer which should be set to B+1. On Exit, CARRY will be set if the BREAK key was hit, Register B will contain the number of characters entered, and (HL) will contain the line from the keyboard followed by the terminating character. Register paid DE is altered in this routine.

0040-0042
“KBLINE”
JUMP to the “WAIT FOR NEXT LINE” keyboard input routine at 05D9H (which takes keyboard entry until a carriage return, a break, or buffer overrun occurs).
0043
RET
0044
NOP
0045
NOP
0043-0045
JUMP to 0434H to print the character held in C.

0046-0048 – DRIVER ENTRY ROUTINE – Part 2 – “DRIVRV”

*0046-0048
JUMP to 0674H.

NOTE: 0674H is the Level II BASIC keyboard driver entry routine.

Difference between M1 and M3: The jump is to the I/O driver entry routine, located at 03C2H in the Model I but relocated to 0674H in the Model III.

*0049-004F – KEYBOARD ROUTINE – “$KBWAIT” – Go scan the keyboard and return with the key pressed, if any, in register A.
A CALL to this memory location 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. If BREAK is hit, then it will be returned in Register A just like any other key (as an 01H). The characters are not echoed to the display.

  • A call to 0049H returns as soon as any key on keyboard is pressed. ASCII value for character entered is returned in A register.
*0049
“KBWAIT”
Character input routine. This routine is the same as 2BH (=Scan the Keyboard routine) except that it will not return until a key is pressed.
*004C
OR A
Check the value in register A to see if a key was pressed.
*004D
RET NZ
Return if a key was pressed.
*004E-004F
Loop until a key is pressed.

*0050-0053 – “$RSRCV” – Receive a character from the RS-232-C Interface
If the RS-232-C wait is enabled, this routine will wait for a character to be received, unless a BREAK is pressed. If the wait is NOT enabled, it returns whether a character is received or not. The character is stored in 16872. A 0 means no character received.

Difference between M1 and M3: In the Model I, locations 0050H through 005FH are a lookup table for special characters associated with the keyboard scan routine. These same locations in the Model III contain the entry points for routines associated with the RS-232-C interface C Receive character at 00S0H, Transmit character at 00SSH, Initialize RS-232-C at 00SAH). In both models, 0060H is the start of a time-delay routine, but in the Model III the three bytes starting at 0060H have been changed to a JP 01FBH instruction. The actual time delay routine (same as in the Model I except that an extra instruction is added to compensate for the faster clock speed of the Model III) has been moved to 01FBH in the Model III. Note that entry at 0063H has the same effect in both models, that is, the time delay will occur only if the z flag is reset (NZ).

*0050
“RSRCV”
LD DE,41E5H
Load DE with the RS-232 Input DCB of 41E5H.
*0053
Input a Byte from the RS-232

*0055-0058 – “$RSTX” – Transmit a character to the RS-232-C Interface
If the RS-232-C wait is enabled, this routine will wait until the character is transmitted unless a BREAK is pressed. If the wait is NOT enabled, it returns whether a character is transmitted or not. The character is stored in Register A.

*0055
“RSTX”
LD DE,41EDH
Load DE with the RS-232 Output DCB of 41EDH
*0058
Output a Byte to the RS-232

*005A-005F – “$RSINIT” – Initialize the RS-232-C Interface
Initialize the RS-232-C interface to the following: Baud=300, Word Length=8, Parity=None, Stop Bits=One, Wait for completion of character I/O.

*005A
“RSINIT”
LD DE,41F5H
Load DE with the RS-232 Controller DCB of 41F5H
*005D
Set up the RS-232
*005F
NOP

*0060-0065 – “$DELAY” – This is a general purpose routine to be used whenever you want to pause before continuing with a program.
On entry, BC must be loaded with the delay multiplier. The actual delay will be 2.46 + (14.8 * BC) microseconds. When BC is zero, the maximum delay is used (65,535) which is about 1 second. Routine uses BC and A.

*0060
“DELAY”
JUMP to the delay routine at 01FBH, which uses BC as a loop counter. It RETs when done, so the next instruction is NOT a pass-through!
*0063
If the ZERO flag is not set, run that delay routine again.
*0065
RET
Return
*0063
This is jumped to by 377EH and JUMPs to 041FH (all printer stuff).
*0066
Go to the non-maskable interrupt routine at 3039H.
Difference between M1 and M3: Pressing the RESET button causes a non-maskable interrupt, which in turn forces a jump to 0066H. In the Model I, a portion of the code that handles non-maskable interrupts is located from 0066H to 0071H. In the Model III, 0066H contains a jump to 3039H (the non-maskable interrupt routine in the Model III), 0069H contains a jump to 0452H (routine to initialize all I/O drivers), and 006CH is the beginning of the routine to route I/O ( loads DE with 421DH and then jumps to 001BH).

*0069 – “$INITIO” – A call to $INITIO restores all I/O drivers to their initial default conditions, including I/O routes. No entry conditions. All registers are altered.

*0069
“INITIO”
Initialize all I/O Drivers by jumping to 0452

*006C – “$ROUTE” – Change I/O Device Routing
On entry store the source device of KI, DO, RI, RO, or PR into 4222H and 4223H as the destination device in 4220H and 4221H.

*006C
“ROUTE”
LD DE,421DH
Load DE with the $ Routine DCB at 421DH
*006F
Set the I/O Routine by jumping to 001BH
*0071
NOP
*0072
JUMP to 06CCH which decrements BC, gets the character at (BC) and checks to see if it is an “R”.
*006C
RET
It does not appear that this byte is ever used.
*006D-006F
LD BC,1A18H
Load BC with the memory address of the routine to return to Level II BASIC because the next JP requires a memory address in BC. This new code is the jump point for hitting a BREAK during a SYSTEM request for FILENAME. The Model III used to reboot. With this code, it goes back to the READY prompt via THIS routine.
*0070-0072
JUMP to 19EAH which is the middle of the startup routine. With BC as it is, the variables will get reset and we will return to Level II BASIC.

0075-0104 – INITIALIZATION ROUTINE

  • This is part of the Level II initialization procedure. It moves a block of memory from 18F7H to l9lEH up to 4080H to 40A7H. (reserved RAM. area).

    NOTE: 4080H-408DH is a division support routine.
0075-0077
“CSTLII”
LD DE,4080H
Load register pair DE with the ROM storage location of the Level II BASIC division routine.

NOTE: 4080H-408DH is a division support routine.
0078-007A
LD HL,18F7H
Load register pair HL with the RAM storage location of the Level II BASIC division routine.
007B-007D
LD BC,0027H
Load register pair BC with the length of the Level II BASIC division routine (39 bytes).
007E-007F
LDIR
Move the Level II BASIC division routine in ROM (18F7H-191DH) to RAM (4080H-40A6H).
*0080-0082
LD HL,42E5H
Continue with the communication region initialization by loading register pair HL with 42E5H.
Difference between M1 and M3: The instruction starting at 0080H loads HL with 41E5H in the Model I, 42E5H in the Model III. Following this, three memory locations (starting with the one pointed to by HL) are loaded with the values 3AH, 00H, and 2CH respectively. HL is then incremented once more and the result (41E8H or 42E8H) points to the start of the input buffer (and is stored at 40A7H).
0083-0084
LD (HL),3AH
Save a 3AH at the location of the memory pointer in register pair HL.

NOTE: 3AH is the Z-80 Instruction of LOAD A, (xxH)
0085
INC HL
Increment the memory pointer in register pair HL.
0086
LD (HL),B
Zero out the location of the memory pointer in register pair HL.
0087
INC HL
Increment the memory pointer in register pair HL.
0088-0089
LD (HL),2CH
Save a 2CH at the location of the memory pointer in register pair HL.

NOTE: 2CH is the Z-80 Instruction INC L.
008A
INC HL
Increment the memory pointer in register pair HL.
008B-008D
LD (40A7H),HL
This loads the input buffer pointer (held at 40A7H) with the keyboard buffer location address of 42E8H. (40A7H is the I/O buffer pointer and can be changed to relocate the buffer.). Save the value in register pair HL as the starting address of the keyboard input buffer area.

NOTE: 40A7H-40A8H holds the input Buffer pointer.
008E-0090
LD DE,012DH
In prepartaion for a jump, load register pair DE with the starting address of the ?L3 ERROR routine.

0091-0104 – The rest of the initialization routine. Asks MEMORY SIZE ?, sets the memory pointers accordingly and prints RADIO SHACK LEVEL II BASIC , then it jumps to 1A19H which is the entry point for the BASIC command mode.

Top of a DJNZ loop of 28 iterations.

0091-0092
LD B,1CH
Load register B with the number of times disk commands (=28) to save the jump to the ?L3 ERROR routine.
0093-0095
LD HL,4152H
Load register pair HL with the starting address of the Disk Basic links (which is 4152H) in preparation for generating an error if disk basic commands are attempted.

NOTE: 4152H-41A3H holds Disk Basic links.
0096-0097
LD (HL),C3H
Save a C3H to the location of the memory pointer in register pair HL.

NOTE: C3H is the first byte of a 3 byte JUMP xxxxH command.
0098
INC HL
Increment the memory pointer in register pair HL to the 2nd instruction of a 3 byte JUMP xxxxH command.
0099
LD (HL),E
Save the LSB of the ?L3 ERROR routine’s starting address in register E (i.e., a 2DH) to the location of the memory pointer in register pair HL.

NOTE: Now we have JUMP 2Dxx as the instruction.
009A
INC HL
Increment the memory pointer in register pair HL to the 3rtd instruction of a 3 byte JUMP xxxxH command.
009B
LD (HL),D
Save the MSB of the ?L3 ERROR routine’s starting address in register D (i.e., a 01H) to the location of the memory pointer in register pair HL.

NOTE: Now we have JUMP 2D01H as the instruction. 012DH is the JUMP point for a ?L3 ERROR.
009C
INC HL
Increment the memory pointer in register pair HL to the next extnry in the Disk Basic links table.
009D-009E
Do this for all 28 disk basic commands until all of the Disk Basic links have been set to jump to the ?L3 ERROR routine.

End of the DJNZ loop of 28 iterations.

009F-00A0
LD B,15H
Load register B with the number of DOS links (=21) to set to RETs.

NOTE: A DJNZ loop uses Register B to count down, so to prep for that loop, Register B has to be filled with the number of iterations.
00A1-00A2
LD (HL),C9H
Save a C9H to the location of the memory pointer in register pair HL.

NOTE: C9H is a RET instruction.
00A3
INC HL
Increment the memory pointer in register pair HL a total of 3 times, as a JUMP is 3 instructions, but RET is just 1 instruction.
00A4
INC HL
Increment the memory pointer in register pair HL.
00A5
INC HL
Increment the memory pointer in register pair HL.
00A6-00A7
Loop back to 00A1 until all 28 of the DOS links have been set to RETs.

001B-001F – VIDEO AND PRINTER ROUTINE

*00A8-00AA
LD HL,43E8H
Load register pair HL with the starting address of user RAM (which is 42E8H).
Difference between M1 and M3: The instruction starting at 00A8H loads HL with 42E8H in the Model I, 43E8H in the Model II I. This memory location is then zeroed (BASIC programs begin at the FOLLOWING memory location in non-disk systems).
00AB
LD (HL),B
Zero 42E8H (i.e., the location of the memory pointer in register pair HL).
*00AC-00AE
LD SP,42F8H
Set the current STACK pointer to 42F8H.
Difference between M1 and M3: Instruction starting at 00ACB loads the Stack Pointer with 41F8H in the Model I and 42F8H in the Model III.
00AF-00B1
GOSUB to 1B8FH to initialize the Level II BASIC variables and pointers.
*00B2-00B4
NOP
NOP
NOP
Difference between M1 and M3: In the Model I, a CALL to 01C9H (the “clear screen” routine) in located here (just prior to printing the “MEMORY SIZE?” prompt on the video display). In the Model III this has been replaced by three zero bytes (NOPs).
00B5-00B7
LD HL,0105H
Load register pair HL with the starting address of the MEMORY SIZE? message.
00B8-00BA
We need to display the MEMORY SIZE? prompt so we must call the WRITE MESSAGE routine at 28A7H.
NOTE:
  • The routine at 28A7 displays the 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 41D0H (JP 5B99H).
00BB-00BD
Print a ? and get input from the keyboard.
00BE-00BF
If the BREAK key was pressed (because the CARRY FLAG was set), ask again.
00C0
RST 10H
Since we now need to increment the input buffer pointer until it points to the first character of the input, call the EXAMINE NEXT SYMBOL routine at RST 10H.
NOTE:
  • The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
  • Blanks and control codes 09H and 0BH are ignored causing the following character to be loaded and tested.
  • The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one.
  • The string must be terminated by a byte of zeros.
00C1
OR A
Set the status flag based on if the character at the location of the input buffer pointer in register A is an end of the input character (00H).
00C2-00C3
JUMP forward to 00D6H (to skip the next instructions which attempt to calculate the memory size) if there was a response to the MEMORY SIZE? question.
*00C4-00C6
“MEMSIZ”
LD HL,444CH
If we are here then just an ENTER was hit in response to the MEMORY SIZE? question, so we need to figure it out dynamically, so load register pair HL with the starting address for the memory size check.Difference between M1 and M3: The instruction starting at 00C4H loads HL with 434CH in the Model I, 444CH in the Model III. If only “ENTER” was pressed in response to the “MEMORY SIZE?” prompt, a memory test is initiated starting at the location pointed to by HL, and continuing upward until the end of memory (or a bad memory location) is reached.
00C7
INC HL
We are going to start testing RAM at 444DH (Decimal: 17485) toward 65535, so increment the memory pointer in register pair HL.
00C8-00C9
LD A,H
OR L
The easiest way to test a 2 byte register for zero is to load the MSB into A and then OR it with the LSB. if the MSB was 0 and the LSB was 0, then A will be 0. So … first, load register A with the MSB of the current memory pointer in register H.
00CA-00CB
If HL has gone all the way up to 0000H (which means the last test tested 65535), JUMP to out of this testing routine to 00E7H.
00CC
LD A,(HL)
Load register A with the value at the location of the current memory pointer in register pair HL.
00CD
LD B,A
Load register B with the value in register A to preserve it, as A is about to get used.
00CE
CPL
Complement the value in register A (which is basically a test pattern).
00CF
LD (HL),A
Save the test pattern in register A to the location of the current memory pointer in register pair HL.
00D0
CP (HL)
Check to see if the value at the location of the memory pointer in register pair HL is the same as the value in register A.
00D1
LD (HL),B
Put back the original memory value (which was saved in B) to the location of the memory pointed in register pair HL.
00D2-00D3
If the address exists, loop back to 00C7H until the end of memory is found.
00D4-00D5
If the address didn’t exist, jump to 00E7H (which goes to he next address and tries again).

00D6 – Interpret the MEMORY SIZE response (whether it was actual via a JUMP from 00C2H or determined via a pass through), and do a memory test.

00D6-00D8
Here the MEMORY SIZE? answer is in HL so call the ASCII TO INTEGER routine at 1E5AH (which will put the answer into DE in integer format).
NOTE:
  • The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
00D9
OR A
Set the FLAGS based on A.
00DA-00DC
Display a ?SN ERROR if register A is not equal to zero.
00DD
EX DE,HL
Swap DE (where the integer version of the MEMORY SIZE? answer is located) and HL, so that register pair HL now has with the MEMORY SIZE answer again, but in integer format.
00DE
DEC HL
Decrement the MEMORY SIZE? in register pair HL.
00DF-00E0
LD A,8FH
Load register A with a memory test value of 8FH (Binary: 1000 1111).
00E1
LD B,(HL)
Load register B with the value at the location of the MEMORY SIZE? pointer in register pair HL (to save the data thats there).
00E2
LD (HL),A
Put the test pattern (in A which is 8FH) into that the location of the MEMORY SIZE? pointer in register pair HL.
00E3
CP (HL)
Check to see if the value in the memory location set in HL matches the test pattern in A.
00E4
LD (HL),B
Restore the old memory contents back.
00E5-00E6
The test at MEMORY SIZE? -1 failed so we have to ask MEMORY SIZE again by jumping to 00B5H.
00E7
DEC HL
Decrement the memory size pointer in register pair HL, so it is the amount of memory – 2.
*00E8-00EA
LD DE,4514H
Load register pair DE with the minimum MEMORY SIZE? response (held at 4514H).
Difference between M1 and M3: The instruction starting at 00E8H loads DE with 4414H in the Model I and 4514H in the Model III. This is the minimum “MEMORY SIZE” that can be specified by the user.
00EB
RST 18H
Now we need to check to see if the MEMORY SIZE? pointer (in HL) is less than the minimum MEMORY SIZE? response (in DE), so we call the COMPARE DE:HL routine, which 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=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal).
00EC-00EE
If C is set, then the amount of actual memory (in HL) is less than the minimum memory required (in DE), so we have to go to the Level II BASIC error routine and display an OM ERROR.
00EF-00F1
LD DE,FFCEH
Load register pair DE with the default size of the string area (i.e., negative fifty).
00F2-00F4
LD (40B1H),HL
Save the MEMORY SIZE? amount (which is in HL) to 40B1H (which holds the MEMORY SIZE? pointer).
00F5
ADD HL,DE
Subtract the size of the string data (which was -50) from the highest memory address (stored in HE).
00F6-00F8
LD (40A0H),HL
Save the start of string space pointer (which is now held register pair HL) to 40A0H.

NOTE: 40A0H-40A1H holds the start of string space pointer.
00F9-00FB
Go initialize/reset the Level II BASIC variables and pointers.
00FC-00FE
LD HL,0111H
Load register pair HL with the starting address of the RADIO SHACK LEVEL II BASIC message. 00FF-0101H Go display the RADIO SHACK LEVEL II BASIC message.
*00FF
JP 37EBH or CALL 021BH
Different ROM Versions handle this differently. Both will display the message pointed to by HL.
Difference between M1 and M3: The instruction previous to this loads HL with the starting address of the opening message (“RADIO SHACK…”). In the Model I, a CALL to 28A7H (the “display message” routine) is stored here, while in the Model III this has been changed to a jump to 37EBH.
*0102
If the ROM used the JUMP command in the prior instruction, we won’t get here. Otherwise, jump to 01E7H (which seems odd since it is jumping right in the middle of the print screen routine).
*00FF
CALL 021BH or CALL 021BH
GOSUB to 021BH to display the message pointed to by HL.
*0102
JUMP to 01E6H to display the copyright message, turn on TIME$, and then JUMP to 022EH to will enable interrupts, show the READY prompt, and RETURN. This was changed by Frank Durda because he moved all the routines from the end of the 3Fxx into where the PRINT SCREEN routine used to be.

0105 – “MEMORY SIZE” Storage Area

*0105
“MEMORY SIZE” + 00H
MEMORY SIZE message storage area.
Difference between M1 and M3: “EMORY” changed to “emory” and “IZE” changed to “ize”.

0111 – “RADIO SHACK MODEL-III BASIC” Storage Area

*0111
“RADIO SHACK MODEL-III BASIC” + 0DH
RADIO SHACK MODEL-III BASIC message storage area.
Difference between M1 and M3: “ADIO” changed to “adio”, “HACK” changed to “hack”, “LEVEL” changed to “Model”, etc.

012D-0131 – ?L3 ERROR ROUTINE – “L3ERR”

012D-012E
LD E,2CH
Load register E with the ?L3 ERROR code of 2CH.
012F-0131
Go to the Level II BASIC error routine with 2CH loaded into Register E.

0132-0134 – LEVEL II BASIC “POINT” COMMAND ENTRY POINT

0132
RST 10H
Since we need to bump the current BASIC program pointer until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.
NOTE:
  • The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
  • Blanks and control codes 09H and 0BH are ignored causing the following character to be loaded and tested.
  • The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one.
  • The string must be terminated by a byte of zeros.
0133
XOR A
A will wind up being 0 if the POINT command was entered … otherwise.
0134
013E80
Z-80 Trick! The byte at this memory location, 01H, is there to turn the real instruction that follows (the operative action of the SET command) into a harmless LD BC,xxxx. This way, they didn’t have to jump over SET or RESET to get to the common graphics code. If parsing straight down, this loads BC with 0380H and then moves to 0136H. But if jump straight to 0136H, you skip that 01H opcode, and get a real instruciton of 3EH 80H.

0135-0137 – LEVEL II BASIC SET COMMAND ENTRY POINT

0135-0136
LD A,80H
Load register A with 80H (Decimal:1 28) which is SET.
0136
1A
Z-80 Trick – See the note at 0134H for an explanation.

0138-0139 – LEVEL II BASIC RESET COMMAND ENTRY POINT
“RESET”

0138-0139
LD A,01H
Load register A with 01H which is RESET.

013A-019CH GRAPHICS ROUTINE
“GRAPH”

  • Common code for SET/RESET/POINT – A will be 0 if POINT, 80H if SET and 1 for RESET.
013A
PUSH AF
Save the graphics mode in register A on the STACK so we can use A for other things.
013B-013C
RST 08H
28H
Since SET/RESET/POINT all need a “(” to start with, call the COMPARE SYMBOL routine which comparess 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 Register A 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).
013D-013F
Go evaluate the expression at the location of the current BASIC program pointer in register pair HL (which is the X variable) and return with the 8-bit value in register A.
0140-0141
CP 80H
Check to see if the X value in register A is greater than 80H (Decimal: 128) by testing A-80H. Results:
  • If A=80H it sets the ZERO FLAG
  • If A<80H then the CARRY FLAG will be set
  • If A>=80H then the NO CARRY FLAG will be set
0142-0144
If A is greater than 128, go to 1E4AH to display a ?FC ERROR.
0145
PUSH AF
Save the X value in register A on the STACK.
0146-0147
RST 08H
“,”
At this point we have SET/RESET/POINT, an open parenthesis, and an X variable, so now we must find a ,. To do this call the COMPARE SYMBOL routine which comparess 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 Aregister 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).
0148-014A
Go evaluate the expression at the location of the current BASIC program pointer in register pair HL (which is the Y variable) and return with the 8-bit value in register A.
014B-014C
CP 30H
Check to see if the Y value in register A is greater than 30H (Decimal: 48). If A=30H it sets the ZERO FLAG. If A<30H then the CARRY FLAG will be set and if A>=30H then the NO CARRY FLAG will be set.
014D-014F
If the Y value is greater than 48, display a ?FC ERROR by JUMPing to 1E4AH.

A this point, we have valid cordinates of X <= 128 and a Y <= 47.

0150-0151
“SETRES”
LD D,FFH
Prepare to divide Y coordinate by 3 … load register D with starting quotient of FFH (which will turn into 00 once it enters the loop).

These next few instructions divide the “Y” coordinate by subtraction. It will keep subtracting 3 (and tracking the number of times it does that in D) until the CARRY FLAG gets set, and then will add 3 to get the remainder.

0152
INC D
Increment the quotient in register D.
0153-0154
SUB 03H
Divide by subtraction … subtract 3 from register A.
0155-0156
Loop back to 0152H to subtract again until we get to a subtraction where the CARRY FLAG gets set. At that point, register D equals the Y value divided by 3 and we know we can’t divide by 3 anymore.
0157-0158
ADD 03H
Add 3 to Register A so then we have the remainder.
0159
LD C,A
Save the remainder (in Register A) to Register C.

These next few instructions fetch the “X” coordinate and do fun math to it together with the “Y” results go get a video memory offset for the graphic.

015A
POP AF
Get the X value from the STACK and put it in register A.
015B
ADD A,A
A = A + A.
015C
LD E,A
Load register E with the X value times two in register A.
015D-015E
LD B,02H
Load register B with the number of times to shift register pair DE (which is 2).
015F
LD A,D
Load register A with the adjusted Y value in register D.
0160
RRA
Divide the adjusted Y value in register A by two.
0161
LD D,A
Save the new Y value in register A in register D.
0162
LD A,E
Load register A with the adjusted X value in register E.
0163
RRA
Divide the adjusted X value in register A by two.
0164
LD E,A
Load register E with the new X value in register A.
0165-0166
Loop until the memory offset in register pair DE has been figured.
0167
LD A,C
Now we need to compute the position of the point so load register A with the value in register C.
0168
ADC A,A
Multiply the value in register A by two and add the value of the CARRY FLAG to register A.
0169
INC A
Increment the value in register A.
016A
LD B,A
Save the bit position in register A in register B.
016B
XOR A
Zero register A and reset the CARRY FLAG.
016C
SCF
Set the CARRY FLAG.
016D
ADC A,A
Multiply the value in register A by two and add the value of the CARRY FLAG to register A.
016E-016F
Loop to the prior instruction until the graphic mask has been completed in register A.
0170
LD C,A
Save the graphic mask in register A in register C.
0171
LD A,D
Load register A with the MSB of the video memory offset in register D.
0172-0173
OR 3CH
Set the bits of the MSB of the video memory offset in register A to turn on Bits 2, 3, 4, and 5 (3H = Decimal: 0011 1100) so that it will point to the correct location in video memory. The only possible resulting values are 3CH-3FH, 7CH-7FH, BCH-BFH, and FCH-FFH.
0174
LD D,A
Save the revised MSB of the video memory pointer in register A in register D.

We now have the location in video memory for the graphic character. Since SET/RESET/POINT use the graphic ASCII character rather than plotting dots, we first need to make sure there is at least a graphic character already at the location.

0175
LD A,(DE)
Load register A with the character at the location of the video memory pointer in register pair DE.
0176
OR A
Set the flags. To help with the next instruction here are a few pointers. The lowest graphic character on the TRS-80 is 80H (Decimal: 128; Binary: 1000 0000). When dealing with bits, a high bit 7 is also utilized to check the sign of something
0177-0179
If the character at (DE) has the sign bit HIGH, it is a graphic character, so skip the next opcode if the character in register A is a graphic character.
017A-017B
LD A,80H
Load register A with a blank graphic character which is CHR$(128).
017C
LD B,A
Save the graphic character (held in Register A) into Register B.
017D
POP AF
Get the graphic character from the STACK (Register B) and put it in register A.
017E
OR A
Set the flags according to the graphic mode in register A.
017F
LD A,B
Get the graphic character from register B and put it in register A.
0180-0181
JUMP forward to 0192H if the graphic mode is POINT.

If we are here, then we are dealing with either SET or RESET, as we would have jumped away in the prior instruction if it was the only other possible alternative, POINT.

0182
LD (DE),A
Save the graphic character in register A at the location of the video memory pointer in register pair DE.
0183-0185
JUMP forward to 018FH if the graphic mode is SET.

If we are here, then we are dealing with RESET, as we would have jumped away otherwise.

0186
LD A,C
Load register A with the graphic mask in register C.
0187
CPL
Reverse the graphic mask in register A.
0188
LD C,A
Load register C with the adjusted graphic mask in register A.
0189
LD A,(DE)
Load register A with the character at the location of the video memory pointer in register pair DE.
018A
AND C
RESET the graphic bit by combining the graphic mask in register C with the graphic character in register A.

Inside the RESET routine. This is common code though. It will just put the graphic character, representing the SET or RESET (held in A) onto the screen (at the location held in DE).

018B
LD (DE),A
Save the adjusted graphic character in register A at the location of the video memory pointer in register pair DE.

Inside the RESET routine. The character has been displayed (if a character was to be displayed), but we still need to make sure that we had proper syntax, so next we check for the close parenthesis and RETURN if we have it or ERROR if we do not.

018C-018D
RST 08
“)”
We need to check HL against 29H (ASCII: )) so we call the COMPARE SYMBOL routine which comparess 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 Aregister 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).
018E
RET
Return.

Inside the SET routine. All this does is change the character accordingly and then jump back up into RESET where it displays the character, checks for the ) and RETurns.

018F
OR C
SET the graphic bit by combining the graphic mask in register C with the graphic character in register A.
0190-0191
JUMP back a few bytes to 018BH.

Next is the POINT routine.

0192
AND C
POINT the graphic bit by combining the graphic mask in register C with the graphic character in register A.
0193-0194
ADD FFH
Subtract one from the value in register A.
0195
SBC A,A
Adjust the value in register A so that A will equal zero if the bit was off in register A.
0196
PUSH HL
Save the current BASIC program pointer in register pair HL on the STACK.
0197-0199
Save the value in register A as the current result in REG 1 (i.e., 4121H).
019A
POP HL
Get the current BASIC program pointer from the STACK and put it in register pair HL.
019B-019C
JUMP to 018CH.

019D-01C8 – LEVEL II BASIC – “INKEY” – INKEY$ ROUTINE

019D
RST 10H
Since we need to bump the current BASIC program pointer in register pair HL until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.
NOTE:
  • The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
  • Blanks and control codes 09H and 0BH are ignored causing the following character to be loaded and tested.
  • The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one.
  • The string must be terminated by a byte of zeros.
019E
PUSH HL
Save the current BASIC program pointer in register pair HL on the STACK.
019F-01A1
LD A,(4099H)
Put the last key pressed (stored at 4099H) into Register A.
01A2
OR A
Set the status flags.
01A3-01A4
JUMP to 01ABH (to skip the next character scan) if a key has been pressed.
01A5-01A7
GOSUB to 0358H to scan the keyboard.
01A8
OR A
Set the status flags.
01A9-01AA
JUMP down to 01BCH if a key wasn’t pressed.

If we are here, a key was pressed and it has been stored in Register A

01AB
PUSH AF
Save the key pressed in register A on the STACK.
01AC
XOR A
Zero register A and clear the status flags.
01AD-01AF
LD (4099H),A
Save the value in register A to (4099H).

NOTE: 4099H holds the last key pressed.
01B0
INC A
Increment the value in register A (which is going to represet the size of the character string to be built).
01B1-01B3
Make sure there is room for this character string by calling 2857H to make an entry in string space.
01B4
POP AF
Get the last key pressed from the STACK and put it in register A.
01B5-01B7
LD HL,(40D4H)
Load register pair HL with the string’s starting address (which is kept in 40D4H).
01B8
LD (HL),A
Save the last key pressed in register A at the location of the string pointer in register pair HL.
01B9-01BB
Go save the string’s VARPTR as the current result.
01BC-01BE
LD HL,1928H
Load register pair HL with the starting address of the “READY” message (which is stored at 1928H).
01BF-01C1
LD (4121H),HL
Save the address in register pair HL as the current result in REG 1 (i.e., 4121H).
01C2-01C3
LD A,03H
Load register A with a string number type flag.
01C4-01C6
LD (40AFH),A
Save the value in register A as the current number type.

Note: 40AFH holds the current number’s type flag as follows:
  • 2: Integer
  • 3: String
  • 4: Single precision
  • 8: Double precision
01C7
POP HL
Get the current BASIC program pointer from the STACK and put it in register pair HL.
01C8
RET
Return.

01C9-01D2 – “$VDCLS” – Clear the video display screen.

  • A CALL lC9H will clear the screen, select 64 characters and home the cursor. All registers are used.
  • To use a ROM call to clear the screen, CALL 01C9H. The cursor is reset to the home position, which is 3C00H.
01C9-01CA
“$VDCLS”
LD A,1CH
Load register A with the ASCII character to home the cursor.
01CB-01CD
GOSUB to 033AH to send the character in register A (i.e., the ASCII character to home the cursor) to the video display.
01CE-01CF
LD A,1FH
Load register A with the ASCII character to clear to the end of the screen.
01D0-01D2
JUMP to 033AH to send the character in register A (i.e., the ASCII character to clear to the end of the screen) to the video display. By JUMPing intead of CALLing, the RET in that routine will act as the RET for this routine.

01D3-01D8 – LEVEL II BASIC RANDOM ROUTINE
RANDOM

  • This is part of the RANDOM routine which takes a value out of the REFRESH register, stores it in location 40ABH and then returns.
    A call to 01D3H reseeds the random number seed (location 40AB) with the current contents of the refresh register.
  • NOTE: To run a RANDOM (seed the random number generator) via a ROM call just call CALL 01D3H. This causes the contents of R (memory refresh) to be stored in 40ABH. The entire 24 bit seed is stored in 40AAH-40ACH.
01D3
LD A,R
Load register A with the current value of the refresh register.
01D5-01D7
LD (40ABH),A
Save the value of the refresh register, as a pseudi-random value, to memory location 40ABH (the random number seed).
01D8
RET
Return.

*01D9-01F7H- Print Screen Routine – “$PRSCN”
This routine copies all 1024 characters from the screen to the printer. If the printer is unavailable, this routine waits until the printer becomes available. If BREAK is pressed, this routine returns to the caller.

*01D9
“PRSCN”
LD HL,3C00H
Load HL with the memory location for the beginning of the video RAM.
Difference between M1 and M3: The routine to print the contents of the screen on the line printer is located from 01D9H to 01F4H on the Model III. On the Model I, 01D9H – 01F7H contains the routine to output one bit to the cassette.
*01DC
LD A,(HL)
Put the character at the screen location stored in HL into A.
*01DD
CP 80H
Check A against 80H, which represets the lowest graphic character. If A < 80H then the character is NOT graphic and the the CARRY will be set. Otherwise NC is set to show that the character is a graphic character.
*01DF
If the CARRY FLAG is set, we have a non-graphic characters, so skip the next instruction.
*01E1
LD A,2EH
Overwrite the current character held in Register A with a ., so that all graphic characters are printed as .‘s.
*01E3
Call the PRINT CHARACTER routine at 003B (which sends the character in the A register to the printer).
*01E6
INC HL
Bump HL to the next character on the screen.
*01E7
BIT 6,H
Check the 6th Bit in H to see if we are at the end of the line (meaning that H is now 64; 1 character beyond the 63 maximum per lime).
*01E9
If we are at 64, then JUMP to 0214H for a new line.
*01EB
LD A,L
Prepare to test of end of line by loading Register A with Register L.
*01EC
AND 03FH
AND the contents of A with 3FH (Binary: 00111111) to turn off Bits 7 and 6, making the maximum number A can be 3FH (Decimal: 63).
*01EE
JR NZ,01DCH
If any of the bits 5-0 are still “1”, then we are not at the end of the line. With this, loop back to 01DCH for the next character.
*01F0
GOSUB to 0214H for a new line.
Difference between M1 and M3: 01F0H contains CALL 0221H instruction on Model I, and CALL 0214H instruction on Model III.
*01F3
JR 01DCH
Loop back to 01DCH for the next character.
Difference between M1 and M3: Contains LD B,5CH instruction on Model I, JR 01DCH instruction on Model III.
*01F5
UNUSED
*01F7
RET
Return

*01D9-01E5H – Subroutine to wait for PRINTER READY, but Honor a BREAK Key. This routine used to be at 0440-044A.

*01D9-01DB
JP 3027H
JUMP to 3027H which is the VECTOR JUMP to 3781H which is the Print Screen Routine that used to be here.
*01DC-01DE
CALL 044BH
GOSUB to 044BH to check to see if PRINTER READY by polling port F8H. Printer will be READY if Z is set.
*01DF
RET Z
If it is ready (because Z is set) then RETURN.
*01E0-01E2
CALL 028DH
if we are here, the printer is not ready. GOSUB to 028DH to check for a BREAK key being pressed.
*01E3-01E4
JR Z,01DCH
Loop back to 01DCH if BREAK wasn’t pressed.
*01E5
RET
RETURN.

*01E6H-01EC – Display the Copyright Message. This routine used to be at 37EBH-37F5H.

*01E6-01E8
LD HL,0202H
Load HL with 0202H.

NOTE: 0202H points to the message ‘(C) “80 Tandy”‘.
*01E9
NOP
*01EA-01EC
GOSUB to 021BH.

NOTE: 021BH will display the message pointed to by HL.

*01EDH-01F7H – – Enable the TIME$ Command – This routine used to be at 37DCH.

*01ED-01EF
LD HL,3030H
Load HL with 3030H.

NOTE: 3030H is the STRING=DATE$+””+TIME$ routine.
*01F0-01F2
LD (4177H),HL
Load the memory location held at 4177H with HL.

NOTE: 4176H is the TIME$ vector as is currently set to be JP ?L3 ERROR as the M1/M3 ROM considered that to be a DOS command. It is not a DOS command for a Model III so that jump needs to be changed. In this case, it is changed from JP ?L3 ERROR to JP 3030H.
*01F3-01F5
JUMP to 022EH to continue.

NOTE: 022EH will enable interrupts, show the READY prompt, and RETURN.
*01F6
NOP
*01F7
NOP

*01F8 – Turn Off The Cassette Motor – “$CSOFF”
After writing data to the cassette, this routine should be called to turn off the cassette drive. There are no entry conditions and no registers are modified.

*01F8
“CSOFF”
JUMP to 300CH to turn the cassette off.
Difference between M1 and M3: In the Model I, the routine to turn off the cassette recorder is located from 01F8H to 0211H. In the Model III, 01F8H contains a jump to 300CH ( the location of a vector to the “turn off cassette” routine in the Model III). 01FBH through 0201H contain the time delay routine (see notes on 0060H), and 0202H through 020FH contains the text “(c) ’80 Tandy” and a carriage return.

*01FB-0201 – DELAY ROUTINE – “$DELAY”

  • This is a delay loop. The BC register pair is used as the loop counter. The duration of the delay, in microseconds, is the value of BC times 14.65. Register A is used.
*01FB
LD A,A
A = A * 2
*01FC
DEC BC
Decrement the counter in register pair BC
*01FD-01FE
LD A,B
OR C
The easiest way to test a 2 byte register for zero is to load the MSB into A and then OR it with the LSB. If the MSB was 0 and the LSB was 0, then A will be 0.
*01FF
Loop until the counter in register pair BC is equal to zero.
*0201
RET
Return.

*202 – Message Storage Location

*0202
(C) “80 Tandy” + 0DH
Copyright message storage area.

0210 – These instructions are never called or used.

*0210-0211
LD E,3DH
I do not see that this command is ever executed as it is never called. However, it loads E with 3DH, most likely to toss off an error.
*0210-0211
NOP
NOP

0212H – This continues a subroutine and was JUMPed to from 022CH. It zeroes A and all flags everything and RETURNs.
Difference between M1 and M3: In the Model I, routines to define cassette drive (0212H – 021DH), reset the cassette input port FFH (021EH – 022BH), and to blink the asterisk while reading a cassette (022CH – 0234H). In the Model III, a routine to insure compatibility with programs that define the cassette drive (XOR A followed by RET, located at 0212H & 0213H), a subroutine used by the routine that begins at 01D9H (0214H 0227H), a couple of cassette-related segments (0228H – 022DH), and an EI instruction followed by JP 1Al9H (enable interrupts and return to BASIC “READY”, located at 022EH – 0231H).

*0212
XOR A
Set A to ZERO and clear all status flags.
*0213
RET
Return.

0216-021A – Display a Carriage Return

*0214
LD A,0DH
Load A with 0DH (ASCII: Carriage Return).
*0216
Call the PRINT CHARACTER routine at 003B (which sends the character in the A register to the printer).
*0219
XOR A
Set A to ZERO and clear all status flags.
*021A
RET
Return.

021B-0227 – “$VDLINE” – Display a Line Until 03H or 0DH Reached.
This subroutine displays a line. The line must be terminated with an ASCII ETX (X’03’) or carriage return (X’0D’). If the terminator is a carriage return, it will be printed; if it is an ETX, it will not be printed. This allows VDLINE to position the cursor to the beginning of the next line or leave it at the position after the last text character. On entry (HL) shuold contain the output text, terminated by a 03H or a 0DH.

*021B
“VIDLINE”
LD A,(HL)
Put the memory contents of (HL) into Register A.
*021C
INC HL
Bump HL.
*021D
CP 03H
Check those memory contents against 03H to see if it is the end of message.
*021F
RET Z
If it was the end of message, RETURN.
*0220
If it was NOT the end of message, call the PRINT CHARACTER routine at 003B (which sends the character in the A register to the printer).
*0223
CP 0DH
Check to see if it was a carriage return.
*0225
If it was NOT a carriage return, loop back to load A with the next character.
*0227
RET
If it WAS a carriage return, RETURN.

0228H – This continues a subroutine and was JUMPed to from 023DH. It puts 3000H into the memory location pointed to by the stack pointer, and JUMPs to 302AH.

*0228
EX (SP),HL
Put HL (which presumably has a return address in it) into the memory location of the STACK pointer.
*0229
JUMP to 302AH.

NOTE: 302AH is an entry in a jump vector table that JUMPs to 31F7H. 31F7H checks to see if we have a PRINT #.

022CH – BLINK ASTERISK routine – This routine is CALLED from 02E7 and alternatively displays and clears an asterisk in the upper right hand corner of the video display.

*022C
JUMP to 0212H to zero the flags and RETURN.
*022E
EI
Enable Interrupts.
*022F
Show READY prompt by jumping to 1A19H.

0232 – These instructions are never called or used.

*0232
CCF
*0233
INC A
*0234
RET
*0232
NOP
*0233
NOP
*0234
NOP

*0235-0240 – CASSETTE ROUTINE – Read a Byte from Cassette – “CSIN”
After the completion of a $CSHIN call, this $CSIN routine begins inputting data, one byte at a time. This routine MUST be called often enough to keep up with the baud rate. There are no entry conditions. A is modified to hold the data byte.
Difference between M1 and M3: In the Model I, 0235H – 0240H contains the routine to read one byte from the cassette, and 0241H – 0260H contains the routine to get one bit from the cassette. In the Model III, 0235H – 023CH contain the start of the Model III routine to read one byte from cassette, 023DH – 0242H is part of the routine that begins at 0287H (writes cassette leader and sync byte), 0243H – 024CH is the actual start of the routine to search for the cassette leader and aync byte, 024DH – 0252H is the actual start of the routine to write a byte to tape, and 0253H – 025EH is a subroutine used by the system to select 500 or 1500 baud tape speed.

*0235
“CSIN”
PUSH DE
Save the value in register pair DE on the STACK.
*0236
PUSH BC
Save the value in register pair BC on the STACK.
*0237
PUSH HL
Save the value in register pair HL on the STACK.
*0238
LD HL,(420EH)
Put the TAPE READ VECTOR (stored at 420EH) into HL.
*023B
EX (SP),HL
Put the TAPE READ VECTOR (stored at 420EH) at the top of the stack, and what used to HL at the top of this routine into Register Pair HL.
*023C
RET
Go to the TAPE READ VECTOR.
NOTE: When a routine is CALLed, the RETurn address is put at the top of the stack; so RET jumps to the value at the top of the STACK.

023D – – This continues a subroutine and was JUMPed to from 028BH to to set the cassette write vector. It just PUSHes HL, puts 3000H into HL, and JUMPs out to 0228H.

*023D
PUSH HL
Save the value in register pair HL on the STACK.
*023E
LD HL,3000H
Load HL with 3000H.
*0241
JUMP back to 0228H.

*0243-024B – CASSETTE ROUTINE – Read a Byte from Cassette

*0243
DI
Disable interrupts.
*0244
GOSUB to 300FH to start the cassette.
*0247
PUSH HL
Save the value in register pair HL on the STACK.
*0248-024A
LD HL,3006H
HL = 3006H
*024B
JUMP back to 0228H.

*024D-0252 – CASSETTE ROUTINE – Write a Byte to Cassette

*024D
PUSH HL
Save the value in register pair HL on the STACK.
*024E
LD HL,(420CH)
Load HL with the memory contents of the TAPE WRITE VECTOR.
*0251
EX (SP),HL
Put the TAPE WRITE VECTOR (stored at 420CH) into the memory location pointed to by the STACK, and the memory location pointed to the STACK into HL.
*0252
RET
RETURN to the memory address held in the TAPE WRITE VECTOR.
NOTE: When a routine is CALLed, the RETurn address is put at the top of the stack; so RET jumps to the value at the top of the STACK.
*0253
EX (SP),HL
Take the RETURN ADDRESS of whoever called this routine and put it into HL.
*0254
LD A,(4211H)
Load A with the contents of memory location 4211H. Memory location 4211H is the Cassette Baud Rate Select. It will be Z for 500 baud, and NZ for 1500 baud.
*0257
OR A
Set flags for A.
*0258
If A was a zero, jump to 025DH to leave the routine with HL as is.
*025A
INC HL
If A was not zero, bump HL 3 times to move to the fast vector.
*025B
INC HL
(Bump 2).
*025C
INC HL
(Bump 3).
*025D
EX (SP),HL
Put HL as the RETURN ADDRESS and restore HL.
*025E
RET
RETURN.
*025F
POP BC
Clean out the STACK.
*0260
RET
RETURN.
*0261
GOSUB to the very next instruction.

0264 – “$CSOUT” – Output a byte to cassette.
After writing the header with $CSHWR, use this $CSOUT to write the data, one byte at a time. You MUST call $CSOUT often enough to keep up with the baud rate. Register A needs to hold the data byte on entry.
Difference between M1 and M3: In the Model I, 0264H – 0283H contains the routine to output one byte to the cassette. In the Model III, 0264H – 0266H contains a jump to 024DH (the start of the Model III routine to output one byte to cassette), followed by time data (60 seconds, 60 minutes, 24 hours) at 0266H – 0268H, followed by twelve bytes which contain the length of each of the twelve months (0264H – 0274H). This is followed by two NOPs, then starting at 0277H is a 1DH byte, a 1EH byte, the message “Diskette?”, and finally a 03H byte (at 0282H).

*0264
JUMP to 024DH to write a byte to cassette.

0266 – Storage location for the maximum number of seconds in a minute, minutes in an hour, hours in a day, and days in a month.

*0266
3C 3C 18
Time Data (60, 60, 24).
*0269
1F 1C 1F 1E
Month Lengths.
*026D
1F 1E 1F 1F
For DATE$.
*0271
1E 1F 1E 1F
*0275
00 00
Unused.
*0277
1D
Group Separator.
*0278
1E
Record Separator.
*0279
“DISKETTE?” + 03H
Message Space.
*0283
F2
UNUSED.

0284 – This subroutine is called by 2076H to turn the tape on, no header – it jumps out to 023DH.
Difference between M1 and M3: In the Model I, this area contains several cassette I/O routines, including turn on cassette, write leader and sync byte (0284H); write leader and sync byte (0287H); turn on cassette, search for leader and sync byte (0293H); search for leader and sync byte (0296H), put 2 asterisks in upper right corner of video ( part of previous routines, begins at 029FH). In the Model III, 0284H contains a JP 0287H instruction (faster than three NOPs), while 0287H is the start of the routine to turn on the cassette, write leader and sync byte. 028DH – 0292H contains the fast routine to check if BREAK is depressed. 0293H contains a JP 0243H instruction, while 0296H contains a JR 0243H (0243H is the actual start of the routine to turn on the cassette, search for leader and sync byte). 0298H – 02A0H is the machine language routine to turn on the built-in clock display (in the upper right hand corner of the video display), while 02A1H – 02A8H is the location of the corresponding routine to turn the clock display back off.

*0284
JUMP to 0287H (the very next instruction anyway!), which was the the “$CSHWR” routine in the Model I ROM. That routine writes tape leader and the A5H sync byte. DE and HL are unchanged.

Load register B with the number of bytes to be written.

0287 – Write Leader and Sync Byte – “$CSHWR”
Each cassette record begins with a header consisting of a leader sequence and a synchronization byte. This $CSHWR routine turns on the cassette and writes out this header. There are no entry conditions. A is altered by this routine.

*0287
“CSHWR”
DI
Disable Interrupts.
*0288
GOSUB to 300FH to turn on the cassette.
*028B
JUMP to 023DH to set the CASSETTE WRITE VECTOR.

028DH – “$KBBRK” -Check for a BREAK key only. This is a fast key scan routine which looks solely for the BREAK key. Use this routine if you want to minimize the keyboard scan time without totally locking out the keyboard. On exit NZ will be set if BREAK was set. This subroutine is called by 0444H (in the middle of the PRINTER ROUTINE) to check for a BREAK key.

*028D
“KBBRK”
LD A,(3840H)
Check for BREAK Key. First, load A with the memory contents of 3840H (which is the keyboard scan of 14400, the 7th keyboard line), to check for a BREAK. 14400 is ENTER (01) CLEAR (02) BREAK (04) RIGHT ARROW (08) LINE FEED (16) LEFT ARROW (32) SPACE (64)
*0290
AND 4
AND the memory contents of 3840H with 04H (Binary: 0000 0100) to isolate only Bit 3. This a precursor to a future test to see if it was a BREAK key.
*0292
RET
RETURN.

0293 – CASSETTE ROUTINE – Read the Header and Sync Bytes

*0293
JUMP to 0243H to read the cassette header.

0296 – CASSETTE ROUTINE – “CSHIN” – Search for Cassette Header and Sync Byte
Each cassette record begins with a header consisting of a leader sequence and synchronization byte. $CSHIN turns on the cassette drive and begins searching for this header information. The subroutine returns to the calling program after the sync-byte has been read. There are no entry conditions. Register A is altered by the routine.

*0296
JUMP to 0243H to read the cassette header.

0298 – Enable the Clock Display – “CLKON”
No entry conditions. A is altered by this routine.

*0298
“CLKON”
LD A,(4210H)
Put the contents of memory location 4210H into A.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls.
*029B
SET 0,A
Set BIT 0 of A.
*029D
LD (4210H),A
Put the modified Clock Bit (stored in A) into the memory location 4210H.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls.
*02A0
RET
RETURN.

02A1 – Disable the Clock Display – “CLKOFF”
No entry conditions. A is altered by this routine.

*02A1
“CLKOFF”
LD A,(4210H)
Put the clock bit stored in memory location 4210H into A.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls.
*02A4
RES 0,A
Reset BIT 0 of A.
*02A6
JUMP to 029DH.

02A8 – These instructions are never called or used.

*02A8
RET
*02A8
NOP

02A9-02B1 – LEVEL II SYSTEM ROUTINE-ENTRY POINT- “GSYSTR”

02A9-02AB
Go read 2 bytes from the cassette, which should be the execution address, and return with it in register pair HL.
02AC-02AE
LD (40DFH),HL
Save the just read execution address from HL into 40DFH.

NOTE: 40DFH-40E0H is used by DOS.
02AF-02B1
GOSUB to 01F8H to turn off the cassette motor.
02B2-02B4
“SYSTEM”
CALL 41E2H
Go call the DOS link at 41E2H.
In NEWDOS 2.1, this is called during a SYSTEM operation.
02B5-02B7
LD SP,4288H
Set the STACK pointer to 4288H (which is the assumed load address). This location passes control to the routine used by the BASIC command SYSTEM.
02B5-02B7
LD SP,42E8H
Set the STACK pointer to 42E8H (which is the assumed load address). By Frank moving this from 4228H to 42E8H he has avoided stepping on a lot of DOS memory locations.
02B8-02BA
Go display a carriage return on the video display if necessary.
02BB-02BC
LD A,2AH
Load register A with an * character (which will form the next prompt).
02BD-02BF
Go display the * character in register A on the video display.
02C0-02C2
We need a filename now with a “?: prompt so GOSUB to 1BB3H to get the input from the keyboard.
02C3-02C5
If a BREAK key was hit (because the CARRY FLAG is now on from the 1BB3H call), go to 06CCH which is in the middle of a token routine looking for REM. This is a BUG. The jump this way will cause the system to reboot.
02C3-02C5
If a BREAK key was hit (because the CARRY FLAG is now on), go to the Level II BASIC READY routine at 006D. The original code jumped to an address which was inappropriate and would cause a reboot.
02C6
RST 10H
Since we need to bump the input buffer pointer in register pair HL until it points to the first character input, call the EXAMINE NEXT SYMBOL routine at RST 10H.
NOTE:
  • The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
  • Blanks and control codes 09H and 0BH are ignored causing the following character to be loaded and tested.
  • The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one.
  • The string must be terminated by a byte of zeros.
02C7-02C9
JUMP to 1997H to display a ?SN ERROR if there wasn’t any input.
02CA-02CB
CP 2FH
Check to see if the character at the location of the input buffer pointer in register A is a / character. “/” is 2FH.
02CC-02CD
JUMP to 031DH if the character at the location of the input buffer pointer in register A is a /.
02CE-02D0
Go turn on the cassette motor.
02D1-02D3
Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (whichh reads one byte from the cassette drive specified in register A, and returns the byte in register A).
02D4-02D5
CP 55H
Check to see if the byte read from the cassette in register A is a header byte.
02D6-02D7
Loop until the header byte is found.
02D8-02D9
LD B,06H
Load register B with the length of the filename to read from the cassette (which is 6 characters).

Top of a DJNZ loop of 06 characters.

02DA
LD A,(HL)
Load register A with the character at the location of the current input buffer pointer in register pair HL.
02DB
OR A
Check to see if the character at the location of the current input buffer pointer in register A is an end of input character.
02DC-02DD
JUMP out of this ‘read the filename from the cassette’ routine if the character at the location of the current input buffer pointer in register A is an end of input character.
02DE-02E0
Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (which reads one byte from the cassette drive specified in register A, and returns the byte in register A).
02E1
CP (HL)
Check to see if the character at the location of the current input buffer pointer in register pair HL is the same as the character read from the cassette in register A.
*02E2
INC HL
Increment the input buffer pointer in register pair HL.
Difference between M1 and M3: This is part of the SYSTEM tape load routine. In the Model I, these locations contain a JR NZ,02D1H instruction followed by an INC HL instruction. In the Model III, these instructions have been in effect reversed C INC HL followed by JR NZ,02D1H). Since this area is not referenced by any other part of the ROM, it is POSSIBLE that this change may have been implemented in order to correct some problem that occured while reading the filename on a SYSTEM tape.
*02E3-02E4
JUMP to 02D1H (skip to the next program on cassette) if the character at the location of the current input buffer pointer in register pair HL isn’t the same as the character read from the cassette in register A.
02E5-02E6
Loop until the whole of the filename has been read from the cassette and checked against the user response.

End of the DJNZ loop of 06 characters.

02E7-02E9
GOSUB to 022CH which just zeroes A and all flags and jumps back here.
02EA-02EC
GOSUB to READ ONE BYTE FROM CASSETTE routine at 0235H (whichh reads one byte from the cassette drive specified in register A, and returns the byte in register A).
02ED-02EE
CP 78H
Check to see if the byte read from the cassette in register A is an execution address header byte (which is 78H).
02EF-02F0
JUMP if the byte read from the cassette in register A is an execution address header byte.
02F1-02F2
CP 3CH
Check to see if the byte read from the cassette in register A is a file block header byte (which is 3CH).
02F3-02F4
Loop until either an execution address header byte or a file block header byte is read from the cassette.
02F5-02F7
Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (which reads one byte from the cassette drive specified in register A, and returns the byte in register A).
02F8
LD B,A
In preparation for the next DJZ loop, load register B with the number of bytes to be loaded in register A.
02F9-02FB
Go read the file block’s starting address from the cassette and return with it in register pair HL.
02FC
ADD A,L
Add the LSB of the file block’s starting address in register L to the MSB of the file block’s starting address in register A.
02FD
LD C,A
Load register C with the file block’s starting checksum in register A.
02FE-0300
Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (which reads one byte from the cassette drive specified in register A, and returns the byte in register A).
0301
LD (HL),A
Save the byte read from the cassette in register A at the location of the memory pointer in register pair HL.
0302
INC HL
Increment the memory pointer in register pair HL.
0303
ADD A,C
Add the value of the current checksum in register C to the value in register A.
0304
LD C,A
Load register C with the updated checksum in register A.
0305-0306
Loop until the whole file block has been read.
0307-0309
Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (which reads one byte from the cassette drive specified in register A, and returns the byte in register A).
030A
CP C
Check to see if the computed checksum in register C is the same as the checksum read from the cassette in register A.
030B-030C
If its the same, jump to 02E7H because the next instructions are for bad checksums.
030D-030E
LD A,43H
Load register A with a C character.
030F-0311
LD (3C3EH),A
Display a C on the video display (at 15422).
0312-0313
JUMP to 02EAH and keep reading bytes.

0314-0316 – This subroutine reads two bytes from tape (providing that the tape is already running) and puts them in the HL register pair. It is used by the SYSTEM routine to read the last two bytes on tape which give the entry point. A JP (HL) can then be executed to jump to the location specified, when used for this purpose. Only HL is used by this routine.

0314
“GETADR”
GOSUB to the READ ONE BYTE FROM CASSETTE routine at 0235H (whichh reads one byte from the cassette drive specified in register A, and returns the byte in register A).
0317
LD L,A
Load register L with the byte read from the cassette in register A (which is the LSB of the 16 bit value).
0318-031A
GOSUB to the READ ONE BYTE FROM CASSETTE routine at 0235H (whichh reads one byte from the cassette drive specified in register A, and returns the byte in register A).
031B
LD H,A
Load register H with the byte read from the cassette in register A (which is the MSB of the 16 bit value).
031C
RET
Return.

031D – “SYSGO” – This subroutine checks to see if we have a starting address from the “*?” prompt and if not, default to 40DFH, and then JUMP to whatever that address is.

031D
EX DE,HL
Load register pair DE with the input buffer pointer in register pair HL.
031E-0320
LD HL,(40DFH)
Load register pair HL with the current execution address (which is stored at 40DFH).

NOTE: 40DFH-40E0H is used by DOS.
0321
EX DE,HL
So that we can run a RST 10H in the next instruction, we need to exchange the execution address in register pair HL with the input buffer pointer in register pair DE.
0322
RST 10H
Since we need to bump the current input buffer pointer in register pair HL until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.
NOTE:
  • The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
  • Blanks and control codes 09H and 0BH are ignored causing the following character to be loaded and tested.
  • The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one.
  • The string must be terminated by a byte of zeros.
0323-0325
Call the ASCII TO INTEGER routine at 1E5AH.
NOTE:
  • The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
0326-0327
JUMP if it turns out there weren’t any digits in the input.
0328
EX DE,HL
Since there were digits (or else we would have jumped in the prior instruction), exchange the input buffer pointer in register pair HL with the execution address in register pair DE.
0329
JP (HL)
JUMP to the execution address (i.e. “/xxxx”) which is in register pair HL.

032A-0347 – OUTPUT ROUTINE – “OUTCHR” or “DSPCHR”

  • This is a general purpose output routine which outputs a byte from the A register to video, tape or printer. In order to use it, the location 409CH must be loaded with -1 for tape, 0 for video or 1 for the line printer.
    Note: 409CH holds the current output device flag:
    • -1: Cassette
    • 0: Video
    • 1: Printer
  • This routine outputs a byte to device determined by byte stored at (409CH) – FFH=Tape, 0=Video, l=Printer. When calling, A = output byte. Uses AF. Warning: This routine CALLs a Disk BASIC link at address 41ClH which may have to be “plugged” with a RETurn (C9H) instruction.
032A
PUSH BC
We are going to need to use Register C, so push register pair BC into the STACK.
032B
LD C,A
Load register C with the character to be output in register A.
032C-032E
CALL 41C1H
Go call the DOS link at 41ClH.
In NEWDOS 2.1, this writes to the system output device.
032F-0331
LD A,(409CH)
Load register A with the current output device number stored in 409CH.

NOTE: 409CH holds the current output device flag:
  • -1: Cassette
  • 0: Video
  • 1: Printer
0332
OR A
Set the flags.
0333
LD A,C
A = C (the character to be output).
0334
POP BC
Get the value from the STACK and put it in register pair BC.
0335-0337
If the character in register A is to be sent to the cassette (because A was NEGATIVE) then JUMP to the the WRITE ONE BYTE TO CASSETTE routine at 0264H (which writes the byte in the A register to the cassette drive selected in the A register).
0338-0339
If the character in register A is to be sent to the printer (because A was NOT ZERO) then JUMP to 039CH.

033A-0347 – “CRTOUT” OUTPUT ROUTINE

  • To use a ROM call to print a single character at the current cursor position, and to update the cursor position, load the ASCII value of the character into the A register and then CALL 033AH.
  • To display special functions using a ROM call, load the A register with the value given below for the special function and then CALL 033AH.
    1. Backspace and erase previous character – 08H
    2. Carriage return and linefeed – 0DH
    3. Turn on cursor – 0EH
    4. Turn off cursor – 0FH
    5. Convert to 32 characters per line mode – 17H
    6. Backspace cursor – 18H
    7. Advance cursor one position – 19H
    8. Downward line feed – 1AH
    9. Upward line feed – 1BH
    10. Home (cursor to upper left corner) – 1CH
    11. Move cursor to beginning of current line – 1DH
    12. Erase from cursor position to end of line – 1EH
    13. Erase from cursor position to end of screen – 1FH
033A
PUSH DE
If we’re here, then that value in A wasn’t going to the cassette or the printer, so it must be going to the video. This routine performs the same function as 33H except that it doesn’t destroy the contents of the DE register pair. This means that all the general purpose registers are saved, which is often desirable.

Save the value in register pair DE on the STACK.
033B-033D
Call the DISPLAY A CHARACTER routine at 0033H (which puts the character in register A on the video screen).
033E
PUSH AF
Save the character in register A on the STACK.
033F-0341
Go update the current cursor position and test to see if the display memory is full.
0342-0344
LD (40A6H),A
Save the current cursor line position stored in 40A6H to register A.

NOTE: 40A6H holds the current cursor line position.
0345
POP AF
Get the character from the STACK and put it in register A.
0346
POP DE
Get the value from the STACK and put it in register pair DE.
0347
RET
Return.

0348-0357 – VIDEO ROUTINE – Get the cursor location (taking into account whether we are in 32 or 64 character mode)

This is a bug in the Model III code. The code is a holdover from the Model I to test whether or not the video display is currently in the 32-character mode. The next 2 instructions (LD A,403DH and AND 08H) was supposed to test bit 3 of memory location 403DH to make that determination, but 403DH does not hold the 32 character flag on the Model III! To fix this bug, the next 2 instructions should be LD A,(4210H) and AND 04H. This bug results in the improper operation of the TAB function when the video display is in the 32 character mode.

0348-034A
LD A,(403DH)
Load register A with the 32/64 character per line flag (which is stored in 403DH).
034B-034C
AND 08H
MASK register A with a 08H (Binary: 0000 1000) to leave only BIT 3 live enabling a test for the 32/64 character per line flag in register A, and set the flags (so if Bit 3 was a 0 then Z FLAG is set).
034D-034F
LD A,(4020H)
Load register A with the LSB of the current cursor position.

NOTE: 4020H-4021H holds Video DCB – Cursor location.
0350-0351
JUMP to 0355H if this is the 64 character per line mode.
0352
RRCA
Divide the LSB of the current cursor position in register A by two.
0353-0354
AND 1FH
Mask the cursor line position in register A for a 32 character per line (AND against 0001 1111) to force its position to be no less than 3C00H.
0355-0356
AND 3FH
Mask the cursor line position in register A for 64 characters per line (AND against 0011 1111) to force its position to be no more than 3FFFH.
0357
RET
Return.

0358-0360 – KEYBOARD ROUTINE – “KBD2”
Here is the routine to simulate the INKEY$ function. It performs exactly the same function as 2BH but it restores all registers, whereas 2BH destroys the contents of the DE register pair. This makes 35BH more useful than 2BH.

0358-035A
CALL 41C4H
GOSUB to the DOS link at 41C4H.
035B
PUSH DE
Since the next routine uses DE, save the value in register pair DE on the STACK.
035C-035E
GOSUB to the SCAN KEYBOARD routine at 002BH.
035F
POP DE
Restore Register Pair DE from the stack.
0360
RET
Return.

0361-0383 – INPUT ROUTINE
“LINP2”

  • This is one of the general purpose input routines (see 05D9 and 1BB3 also). This routine inputs a string from the keyboard, up to a maximum of 240 characters (F0H), and echoes them to the screen. It puts this data into a buffer located at the address pointed to by the buffer pointer at 40A7H. (e.g. If 40A7H contains 5000H the data will be stored from 5000H onwards). The string is terminated with a zero byte. The program returns from this routine as soon as the ENTER key has been pressed. When it does so, HL contains the start address of the input string and B contains the length of the string. (RST 10H can be used to make HL point to the first character of the string, if required.).

    NOTE: 40A7H-40A8H holds the input Buffer pointer.
0361
XOR A
Zero register A.
0362
LD (4099H),A
Save the value in register A as the last key pressed (which is stored in 4099H).

NOTE: 4099H holds the last key pressed.
0365
LD (40A6H),A
Save the value in register A as the current cursor line position (which is stored in 40A6H).

NOTE: 40A6H holds the current cursor line position.
0368
CALL 41AFH
GOSUB the DOS link at 41AFH.
In NEWDOS 2.1, this is the start of keyboard input.
036B
PUSH BC
Save the value in Register Pair BC to the STACK.
036C
LD HL,(40A7H)
Load register pair HL with the starting address of the input buffer (which is stored in 40A7H).

NOTE: 40A7H-40A8H holds the input Buffer pointer.
036F
LD B,F0H
Load register B with the length of the input buffer (which is 240).
0371
GOSUB to the “WAIT FOR NEXT LINE” keyboard input routine at 05D9H (which takes keyboard entry until a carriage return, a break, or buffer overrun occurs).
0374
PUSH AF
Save the flags on the STACK.
0375
LD C,B
Load register C with the length of the input in register B.
0376
LD B,00H
Zero register B so that register pair BC will have the length of the input.
0378
ADD HL,BC
Add the length of the input in register pair BC to the starting address of the input buffer in register pair HL.
0379
LD (HL),00H
Save an end of the input character at the location of the end of input pointer in register pair HL.
037B
LD HL,(40A7H)
Load register pair HL with the starting address of the input buffer (which is 40A7H).

NOTE: 40A7H-40A8H holds the input Buffer pointer.
037E
POP AF
Get the flags from the STACK.
037F
POP BC
Get the value from the STACK and put it in register pair BC.
0380
DEC HL
Decrement the input buffer pointer in register pair HL (so that HL is the input area pointer – 1).
0381
RET C
Return if the BREAK key was pressed.
0382
XOR A
Otherwise (i.e., the BREAK key was not pressed), zero all the status flags.
0383
RET
Return.

0384-038A – KEYBOARD ROUTINE – “KBWT2” – Waits for keypress

0384
Go scan the keyboard.
0387
OR A
Check to see if a key was pressed.
0388
RET NZ
Return if a key was pressed (meaning OR A was set to NZ).
0389
Loop until a key is pressed.

038B-039B – PRINTER ROUTINE

  • This routine resets device type flag at 409CH to zero (output to video display), also outputs a carriage return to the line printer if printer is not at beginning of line (determined by checking the contents of the printer line position flag at 409B – if flag contains zero, printer is at start of line). Note that if printer line position flag does not contain zero and the printer is not on line, the computer will “hang up” waiting for a “printer ready” signal.
038B
XOR A
Zero register A, which then means it contains the device code for VIDEO.
038C-038E
LD (409CH),A
Save the value in register A (the current output device code of video) to 409CH.

NOTE: 409CH holds the current output device flag:
  • -1: Cassette
  • 0: Video
  • 1: Printer
038F-0391
LD A,(409BH)
Load register A with the current printer carriage position (which is stored at 409BH).

NOTE: 409BH holds the printer carriage position.
0392
OR A
Check to see if the carriage position in register A is equal to zero.
0393
RET Z
Return if the carriage position in register A is equal to zero.
0394-0395
LD A,0DH
Load register A with a carriage return character (i.e., 0DH).
0396
PUSH DE
Save the value in register pair DE on the STACK.
0397-0399
Go send the carriage return character in register A to the printer.
039A
POP DE
Get the value from the STACK and put it in register pair DE.
039B
RET
Return.

039C-03C1 – PRINTER ROUTINE

  • This is the LPRINT routine. All registers are saved. The byte to be printed should be in the A register.
039C
PUSH AF
Save the value in register pair AF on the STACK.
039D
PUSH DE
Save the value in register pair DE on the STACK.
039E
PUSH BC
Save the value in register pair BC on the STACK.
039F
LD C,A
Load register C with the character to be sent to the printer in register A.
03A0
LD E,00H
Zero register E (which will ultimately hold the new character/line count of 0CH, 0DH, or 0AH).
03A2
CP 0CH
Check to see if the character to be sent to the printer in register A is equal to 0CH (which is ‘skip to next line’).
03A4
JUMP to 03B6H if the character to be sent to the printer in register A is equal to 0CH.
03A6
CP 0AH
Check to see if the character to be sent to the printer in register A is a line feed character (i.e., 0AH).
03A8
JUMP to 03ADH if the character to be sent to the printer in register A isn’t a line feed character.
03AA
LD A,0DH
Load register A with a carriage return character (i.e., 0DH).
03AC
LD C,A
Load register C with the character to be sent to printer in register A.
03AD
CP 0DH
Check to see if the character to be sent to the printer in register A is a carriage return character.
03AF
JUMP to 03B6H if the character to be sent to the printer in register A is a carriage return character.
03B1
LD A,(409BH)
Load register A with the current printer carriage position (stored in 409BH).

NOTE: 409BH holds the printer carriage position.
03B4
INC A
Increment the current carriage position in register A.
03B5
LD E,A
Load register E with the current carriage position in register A.

03B6H – If we are here, the character sto be sent to the printer was a SKIP TO NEXT LINE (0CH) or a CARRIAGE RETURN (0DH).

03B6
LD A,E
Load register A with the current carriage position in register E. Why do this since its obviously already done? Because this is a jump point!
03B7
LD (409BH),A
Put Register A (the current carriage position) into 409BH.

NOTE: 409BH holds the printer carriage position.
03BA
LD A,C
Load register A with the character to be sent to the printer in register C.
03BB
Call the PRINT CHARACTER routine at 003B (which sends the character in the C register to the printer).
03BE
POP BC
Get the value from the STACK and put it in register pair BC.
03BF
POP DE
Get the value from the STACK and put it in register pair DE.
03C0
POP AF
Get the value from the STACK and put it in register pair AF.
03C1
RET
Return.

*03C2H-0451H – PRINTER ROUTINE

Difference between M1 and M3: Start of I/O driver area which has been totally rearranged in the Model III. Specifically, in the Model I the area from 03C2H through 0SD0H was arranged as follows: 03C2H – 03E2H is the I/O driver entry routine, 03E3H – 0457H is the keyboard driver routine, 0458H – 058CH is the video driver routine, and 058DH – 0SD0H is the line printer driver routine. In the Model III, 03C2H – 0451H is the line printer driver routine, 0452H – 0468H is the actual location of the routine to initialize all I/O drivers, 046BH – 0472H is a routine used by the RUN/EDIT/NEW commands to unprotect the video display and to load HL with the start of BASIC program pointer at 40A4H-40A5H, and 0473H-05D0H is the video driver routine and the keyboard driver begins at 3024H in the Model III).

*03C2
LD A,C
A = C (the current character).
*03C3
CP 20H
Check to see if the character is a control character by testing A – 20H. Results:
  • If A=20H it sets the ZERO FLAG
  • If A<20H then the CARRY FLAG will be set
  • if A>=20H then the NO CARRY FLAG will be set.
If A is a CONTROL CHARACTER then C will be set.
*03C5
If A was >= a SPACE, the NC would be set meaning A is a control character, jump to 03E5H to skip a bunch of needless tests.
*03C7
CP 0DH
Check to see if the character is a carriage return.
*03C9
If it is a carriage return, jump to 03F5H.

NOTE: 03F5H prints a character while maintaining page height and width.
*03CB
CP 0CH
Check to see if the character is a FORM FEED.
*03CD
JUMP to 03FFH if it is not a FORM FEED.
*03CF
LD A,(IX+03H)
If we are here then the character must be a printable one, so we need to get the number of lines left in the page and put them into B for a DJNZ countdown.
*03D2
SUB (IX+04H)
Subtract the number of lines printed from A.

NOTE: IX+4 is the number of lines printed.
*03D5
LD B,A
LET B = A
*03D6
GOSUB to 0440H to wait until the printer is ready (honoring BREAK, if hit).
*03D9
LD A,0AH
Put a LINE FEED character into A.
*03DB
OUT (0F8H),A
Output the LINE FEED character to port 0F8H.
NOTE: 0F8H is the printer port. If you put data to it, it prints it. Otherwise, Bits 4-7 hold printer status.
*03DD
JUMP back to 03D6H until the number of lines left in the page is zero.
*03DF
LD (IX+05H),00H
Load the memory location pointed to by IX+5 with a zero. NOTE: IX+5 is the number of characters printed.
*03E3
JUMP to 0439H to set the number of lines printed to 01 and exit

03E5H – Inside the PRINTER ROUTINE – If we are here, the characters to be sent to the printer are NOT control characters, so test for graphics (and jump away), and if not, put the character from the PRINTER LOOKUP TABLE into C.

*03E5
CP 80H
Test for a graphics character by comparing A to 80H. If it is a graphics character than NC will be set.
*03E7
JUMP to 0419H to handle the graphics character.
*03E9
LD B,00H
Load B with a 00 (to set a MSB = 0).
*03EB
SUB 20H
Subtract 20H from A to adjust the character to the table.
*03ED
LD C,A
Load C with A. Now BC has the adjusted character value.
*03EE
LD HL,3145H
Load HL with 3145H.

NOTE: 3145H is the PRINTER CHARACTER LOOKUP TABLE.
*03F1
ADD HL,BC
Add BC to HL so that HL will have the character location in the character table.
*03F2
LD C,(HL)
Load C with the character at the position of HL in the character table.
*03F3
JUMP to 0403H to continue.

*03F5-0424 – Inside the PRINTER ROUTINE – Print A Character Honoring Page Height and Width

*03F5
LD A,(IX+05H)
Load the A with the number of characters printed.

NOTE: IX+5 is the number of characters printed.
*03F8
OR A
Set the flags for A, including a test for zero/none.
*03F9
LD A,C
Put the character held in C into A.
*03FA
If there were ANY characters printed (so A is not zero), jump to 033FH.
*03FC
LD A,0AH
If there weren’t sny characters printed, the load A with 0AH.
*03FE
LD C,A
Load C with 0AH.
*03FF
CP 20H
Check to see if the character is a control character by testing A – 20H. If A=20H it sets the ZERO FLAG. If A<20H then the CARRY FLAG will be set and if A>=20H then the NO CARRY FLAG will be set. If A is a CONTROL CHARACTER then C will be set.
*0401
If it is a control character, jump to 0419H.

*0403 – Inside the PRINTER ROUTINE – If we are here, then C holds the printable character to be printed as determined by the PRINTER CHARACTER TABLE.

*0403
LD A,(IX+06H)
Load A with the MAXIMUM PRINT WIDTH.

NOTE: IX+06H holds the MAXIMUM PRINT WIDTH.
*0406
INC A
Bump A to one beyond that (i.e., unlimited).
*0407
If the maximum print width is unlimited, jump to 0419H.
*0409
CP (IX+05H)
Check to see if the line is full by comparing A with IX+5.

NOTE: IX+5 is the number of characters printed.
*040C
If the line is NOT full, jump to 0419H.
*040E
GOSUB to 0440H to wait until the printer is ready (honoring BREAK, if hit).
*0411
LD A,0DH
Load A with a carriage return.
*0413
OUT (0F8H),A
Send the carriage return to port 0F8H.

NOTE: 0F8H is the printer port. If you put data to it, it prints it. Otherwise, Bits 4-7 hold printer status.
*0415
LD (IX+05H),00H
Set the number of characters printed to zero.

NOTE: IX+5 is the number of characters printed.
*0419
GOSUB to 0440H to wait until the printer is ready (honoring BREAK, if hit).
*041C
LD A,C
Restore the character held in C back into A.
*041D
OUT (F8H),A
Send the character to port F8H.

NOTE: F8H is the printer port. If you put data to it, it prints it. Otherwise, Bits 4-7 hold printer status.
*041F
INC (IX+05H)
Bump the number of characters printed.

NOTE: IX+5 is the number of characters printed.
*0422
CP 0DH
Check A for a carriage return.
*0424
If A was a carriage return, skip the next few instructions and jump to 042AH.
*0426
CP 0AH
Check to see if the character in register A is 0AH (ASCII: LINE FEED character).
*0428
IF A is not a LINE FEED then jump to 043DH.

042A – Inside the PRINTER ROUTINE – If we are here, then we have a LINE FEED or a CARRIAGE RETURN in A.

*042A
LD (IX+05H),00H
Reset the number of characters printed.

NOTE: IX+5 is the number of characters printed.
*042E
INC (IX+04H)
Bump IX+04.

NOTE: IX+4 is the number of lines printed.
*0431
LD A,(IX+04H)
Load A with the number of lines printed.
*0434
CP (IX+03H)
Compare that to the maximum number of lines per page.

NOTE: IX+3 is the maximum number of lines per page.
*0437
Skip the next instruction by JUMPing to 043DH if the number of lines printed is less than maximum number of lines per page.
*0439
LD (IX+04H),01H
We must be at top of page so set the number of lines printed to 01.

NOTE: IX+4 is the number of lines printed.
*043D
XOR A
Clear A and the status bits.
*043E
LD A,C
Load the character into A.
*043F
RET
RETURN.

*0440-044A – Inside the PRINTER ROUTINE – Subroutine to wait for PRINTER READY, but Honor a BREAK Key

+*0440
GOSUB to 044BH to check the printer.
|*0443
RET Z
If it is ready (because Z is set) then RETURN.
|*0444
if we are here, the printer is not ready. GOSUB to 028DH to check for a BREAK key being pressed.
+*0447
Loop back to 0440H if BREAK wasn’t pressed.
*0449
POP AF
Restore AF from the STACK.
*044A
RET
RETURN.

*03C2H-0451H – PRINTER ROUTINE

*03C2
LD A,C
A = C (the current character).
*03C3
CP ‘ ‘
Check to see if the character is a control character by testing A – 20H. Results:
  • If A=20H it sets the ZERO FLAG
  • If A<20H then the CARRY FLAG will be set
  • if A>=20H then the NO CARRY FLAG will be set.
If A is a CONTROL CHARACTER then C will be set.
*03C5
JR NC,03E9H
If A was >= a SPACE, the NC would be set meaning A is a control character, jump to 03E9H to skip a bunch of needless tests.
*03C7
CP 0DH
Check to see if the character is a carriage return.
*03C9
JR Z,0414H
If it is a carriage return, jump to 0414H to deal with that.
*03CB
CP 0CH
Check to see if the character is a FORM FEED.
*03CD
JR NZ,041DH
JUMP to 041DH if it is not a FORM FEED.
*03CF
LD A,(IX+03H)
If we are here then the character must be a printable one, so we need to get the number of lines left in the page and put them into B for a DJNZ countdown.
*03D2
SUB (IX+04H)
Subtract the number of lines printed from A.

NOTE: IX+4 is the number of lines printed.
*03D5
LD B,A
LET B = A
*03D6
CALL 01DCH
GOSUB to 01DCH to wait until the printer is ready (honoring BREAK, if hit).
*03D9
LD A,0AH
Put a LINE FEED character into A.
*03DB
OUT (F8H),A
Output the LINE FEED character to port 0F8H.
NOTE: 0F8H is the printer port. If you put data to it, it prints it. Otherwise, Bits 4-7 hold printer status.
*03DD
DJNZ 03D6H
JUMP back to 03D6H until the number of lines left in the page is zero.
*03DF
LD (IX+05H),00H
Load the memory location pointed to by IX+5 with a zero. NOTE: IX+5 is the number of characters printed.
*03E3
LD (IX+04H),01H
We must be at top of page so set the number of lines printed to 01.

NOTE: IX+4 is the number of lines printed.
*03E7
JR 0448H
JUMP to 0448H to restore the character to Register A, clear all flags, and RETURN.

*03E9-03F5 – Inside the PRINTER ROUTINE – Subroutine if the character is a CONTROL CHARACTER.

*03E9
LD A,(41FBH)
Load the memory contents of (41FBH) into Register A.

NOTE: Frank appears to have introduced 41FBH to flag a CONTROL CHARACTER
*03EC
OR A
Set the flags
*03ED
JR Z,03F6H
If the memory contents of (41FBH) held in Register A are zero then JUMP to 03F6H.
*03EF
CP 01H
Check to see if A is a “01H” (which is Start of Heading).
*03F1
JP Z,3045H
If A is 01H, JUMP to 3045H, which I guess is Frank’s shot at Z-80 trick. This jumps in the middle of the OPCODE at 3044H, but in doing so, turns that into a JUMP to 376AH.
*03F4
JR 041FH
If A is not 01H then JUMP to 041FH.

*03F6-4000 – Inside the PRINTER ROUTINE – Subroutine if the memory contents of 41FBH are zero.

*03F6
LD A,(41FCH)
Load the memory contents of (41FCH) into A.

NOTE: DURDA NOTE
*03F9
OR A
Set the flags
*03FA
JR NZ,040AH
If the memory contents of (41FCH) held in Register A are zero then JUMP to 040AH.
*03FC
LD A,C
A = C (the current character).
*03FD
CP A0H
Check to see if A is a “A0H” (Decimal: 160) or higher. Results:
  • If A=A0H it sets the ZERO FLAG
  • If A<A0H then the CARRY FLAG will be set
  • if A>=A0H then the NO CARRY FLAG will be set.
*03FF
JR C,041FH
If A<A0H then JUMP to 041FH.
*0401
CP C0H
If we are here then A>=A0H, so lets further test to see if A is “C0H” or higher. Results:
  • If A=C0H it sets the ZERO FLAG
  • If A<C0H then the CARRY FLAG will be set
  • if A>=C0H then the NO CARRY FLAG will be set.
*0403
JR NC,040FH
If A>=C0H (Decimal: 192; meaning A is above the highest graphic) then JUMP to 040FH.
*0405
ADD A,40H
If we are here then A>=A0H, but A<C0H (i.e., betweem 160 and 191), so add 40H (Decimal: 64; or 1 character below “A”) to Register A.
*0407
LD C,A
Let C = A.
*0408
JR 041FH
JUMP to 041FH.

*040AH-040EH – Inside the PRINTER ROUTINE – Subroutine if the memory contents of 41FCH are zero.

*040A
LD A,C
Load the character into A.
*040B
CP C0H
Check to see if A is “C0H” or higher. Results:
  • If A=C0H it sets the ZERO FLAG
  • If A<C0H then the CARRY FLAG will be set
  • if A>=C0H then the NO CARRY FLAG will be set.
*040D
JR C,041FH
If A<C0H then JUMP to 041FH.
*040F
SUB 20H
Subtract 20H from A to adjust the character to the table.
*0411
LD C,A
Load C with A. Now BC has the adjusted character value.
*0412
JR 041FH
JUMP to 041FH.

*0414H-040EH – Inside the PRINTER ROUTINE – We have a CARRIAGE RETURN to print.

*0414
LD A,(IX+05H)
Load the A with the number of characters printed.

NOTE: IX+5 is the number of characters printed.
*0417
OR A
Set the flags for A, including a test for zero/none.
*0418
JR NZ,0434H
If there are characters to be printed, JUMP to 0434H.
*041A
LD A,0AH
Let A = 0AH (Decimal: 10; ASCII: Line Feed).
*041C
LD C,A
Let C = A.
*041D
JR 0434H
JUMP to 0434H.

*041F – Inside the PRINTER ROUTINE – If we are here, then C holds the printable character to be printed as determined by the PRINTER CHARACTER TABLE.

*041F
LD A,(IX+06H)
Load A with the MAXIMUM PRINT WIDTH.

NOTE: IX+06H holds the MAXIMUM PRINT WIDTH.
*0422
INC A
Bump A to one beyond that (i.e., unlimited).
*0423
JR Z,0434H
If the maximum print width is unlimited, jump to 0434H.
*0425
CP (IX+05H)
Check to see if the line is full by comparing A with IX+5.

NOTE: IX+5 is the number of characters printed.
*0428
JR NC,0434H
If the line is NOT full, jump to 0434H.
*042A
CALL 01DCH
GOSUB to 01DCH to wait until the printer is ready (honoring BREAK, if hit).
*042D
LD A,0DH
Load A with a carriage return.
*042F
OUT (F8H),A
Send the carriage return to port 0F8H.

NOTE: 0F8H is the printer port. If you put data to it, it prints it. Otherwise, Bits 4-7 hold printer status.
*0431
CALL 3048H
DURDA NOTE.

*0434 – Inside the PRINTER ROUTINE – It seems that if something jumps here, we have a valid character in C to print.

*0434
CALL 01DCH
GOSUB to 01DCH to wait until the printer is ready (honoring BREAK, if hit).
*0437
LD A,C
Restore the character held in C back into A.
*0438
OUT (F8H),A
Send the character to port F8H.

NOTE: F8H is the printer port. If you put data to it, it prints it. Otherwise, Bits 4-7 hold printer status.
*043A
INC (IX+05H)
Bump the number of characters printed.

NOTE: IX+5 is the number of characters printed.
*043D
CP 0DH
Check A for a carriage return.
*043F
JR Z,0445H
If Register A holds a CARRIAGE RETURN then JUMP to 0445H.
*0441
CP 0AH
Check to see if the character in register A is 0AH (ASCII: LINE FEED character).
*0443
JR NZ,0448H
If the character in Resgister A is not a LINE FEED, then JUMP to 0448H which restores the character to A, clears all flags, and RETURNS.
*0445
CALL 3048H
If we are here, then the character in Register A is a LINE FEED or CARRIAGE RETURN so GOSUB to 3048 to DURDA NOTE.
*0448
XOR A
Clear A and the status bits.
*0449
LD A,C
Load the character into A.
*044A
RET
Return.

*044B-0451 – Inside the PRINTER ROUTINE – Subroutine to check to see if PRINTER READY by polling port F8H

*044B
IN A,(F8H)
Set A with the Printer Status Byte.

NOTE: F8H is the printer port. If Bit 7 is set, the printer is not busy. If Bit 6 is set the printer is not out of paper. If bit 5 is set, the device is selected. If Bit 4 is set, no printer fault.
*044D
AND 0F0H
AND A against F0H (Binary: 11110000) to strip off BITS 3-0, leaving BITS 7-4 intact.
*044F
CP 30H
Check the already masked A against 30H (Binary: 00110000) to see if the printer is ready.

NOTE: This translates to PRINTER NOT BUSY (Bit 7=0), PRINTER NOT OUT OF PAPER (Bit 6=0), PRINTER SELECTED (Bit 5=1), and NO PRINTER FAULT (Bit 4=1).
*0451
RET
Return.

*0452-0468 – Initialize KB, DI, PR, RI, RO and RN

*0452
LD HL,36BFH
Initialize to Keyboard, Display Drive, and Printer …
*0455
LD DE,4015H
… by moving the 24 bytes starting at 36BFH …
*0458
LD BC,0018H
… to 4015H-402DH.
*045B
LDIR
*045D
LD HL,36F9H
Initialize RI, RO, and RN …
*0460
LD DE,41E5H
… by moving the 24 bytes starting at 36F9H …
*0463
LD BC,0018H
… to 41E5H-41FDH.
*0466
LDIR
*0468
RET
RETURN.

0469-046A – These instructions are never called or used.

*0469-046A
JR NZ,00DAH
JUMP to 00DA to JUMP to display a ?SN ERROR.
*0469-046A

*046B-0472 – This subroutine zeroes out the PROTECTED SCREEN LINES (if any) and point HL to the start of data

*046B
XOR A
Clear A and all Status Bits.
*046C
LD (4214H),A
Set memory location 4214H to zero.
NOTE: 4214H is the number of protected video lines.
*046F
LD HL,(40A4H)
Load HL with the memory contents of 40A4H.
Note: 40A4 is the DATA POINTER.
*0472
RET
Return.

*0473H-04B1H – Cursor Management

*0473
DI
Disable Interrupts.
*0474-0479
LD L,(IX+03H)
LD H,(IX+04H)
Load HL with the MSB and LSB of the current cursor position (Held in IX+3 and IX+4).
*047A
LD A,(IX+05H)
Load A with the character at the current cursor position.

NOTE: IX+05H holds the character at the cursor position.
*047D
OR A
Set flags. It will be Z if the cursor is off.
*047E
Skip the next instruction (i.e., JUMP to 0481H) if the cursor is off.
*0480
LD (HL),A
If we are here, the cursor is on so display the character held in A at the current cursor position held in HL.
*0481
LD A,C
Load A with C (which should be the character to display).
*0482
CP 20H
Check to see if the character is a control character by comparing A to 20H. Results:
  • If A=20H it sets the ZERO FLAG.
  • If A<20H then the CARRY FLAG will be set
  • If A>=20H then the NO CARRY FLAG will be set.
If A is a CONTROL CHARACTER then the CARRY FLAG will be set.
*0484
If the CARRY FLAG is set (i.e., we have a control character), JUMP to 0521H.
*0487
CP C0H
Check to see if the character is a control character by comparing A to 20H. Results:
  • If A=C0H it sets the ZERO FLAG.
  • If A<C0H then the CARRY FLAG will be set
  • If A>=C0H then the NO CARRY FLAG will be set.
If A is a TAB or SPECIAL CHARACTER then NC will be set.
*0489
If the CARRY FLAG is NOT set (i.e., we have a TAB or SPECIAL CHARACTER), JUMP to 04B7H.

*048B – Inside the CURSOR MANAGEMENT ROUTINE – If we are here, the character is not a control character, tab, or special characters.

*048B
GOSUB to 0576H to display the character on the screen.
*048E
LD A,H
Now we need to make sure the cursor is still on the screen. First Load A with H (which is the MSB of the screen location).
*048F
AND 03H
Mask A against 03H (0000 0011), so that only the last 2 bits are live (so it can be only 0, 1, 2 or 3).
*0491
OR 3CH
OR it against 3CH (0011 1100), so that it is 0011 11xx where xx are those 2 bits (so it can be only 60, 61, 62, or 63).
*0493
LD H,A
Load H with the masked A.
*0494
LD D,(HL)
Get the character at the cursor position (held in the memory location pointed to by HL) and put it in D.
*0495
LD A,(IX+05H)
Load A with IX+5 to see if the cursor is on.

NOTE: IX+05H holds the character at the cursor position.
*0498
OR A
Set flags for A.
*0499
If the cursor is NOT on (A is Zero), then jump to 04A8H.
*049B
LD (IX+05H),D
The cursor is on so put the character which is supposed to be there, there.

NOTE: IX+05H holds the character at the cursor position.
*049E
LD A,(IX+06H)
Load A with the cursor character.

NOTE: IX+6 holds the cursor character.
*04A1
CP 20H
Check to see if the character is a control character by testing A – 20H. If A=20H it sets the ZERO FLAG. If A<20H then the CARRY FLAG will be set and if A>=20H then the NO CARRY FLAG will be set. If A is a CONTROL CHARACTER then C will be set.
*04A3
If it is not a control character, us it by jumping to 04A7H.
*04A5
LD A,0B0H
If it is a control character, then load A with the default cursor of B0H.

NOTE: B0H is a two pixel wide graphic character located below the letter line.
*04A7
LD (HL),A
Display the character held in A into the memory location pointed to be HL. This should display the cursor.
*04A8
LD (IX+03H),L
Save the cursor position by loading IX+3 with L and …
*04AB
LD (IX+04H),H
… by loading IX+4 with H.
*04AE
XOR A
Zero A and clear all status flags.
*04AF
LD A,C
Load A with the character.
*04B0
EI
Enable Interrupts.
*04B1
RET
RETURN.

*04B2 – Cursor Management – Move to the start of the line.

*04B2
LD A,L
Load register A with the LSB of the current position in register L.
*04B3-04A3
AND C0H
Point to the beginning of the line by ANDing it against 1100 0000 to keep only Bits 6 and 7 (so it will be XX00H, XX40H, XX80H, or XXC0H).
*04B5
LD L,A
Load register L with the updated value in register A.
*04B6
RET
Return with the new video buffer address stored in HL.

*04B7 – Cursor Management – We have EITHER a TAB or SPECIAL CHARACTER, so figure it out, and proceed accordingly.

*04B7
LD A,(IX+07H)
Load A with IX+7 to check for TABS or SPECIAL CHARACTERS.
*04BA
OR A
Set the Flags for A.
*04BB
LD A,C
Put the current character into A.
*04BC
If A is Not Zero, jump to 048BH to display the special character set.
*04BE
SUB C0H
Subtract C0H (Binary: 1100 0000) to compute a TAB.
*04C0
If TAB(0) then jump to 048EH.
*04C2
LD B,A
Load B with the number of spaces needed.
*04C3
LD A,20H
Load A with a SPACE.
*04C5
GOSUB to 0576H to display the character on screen.
*04C8
Loop back 2 Instructions until B is exhausted.
*04CA
JUMP to 048EH.

*04CC – Cursor Management – CURSOR ON.

*04CC
LD A,(HL)
Store the character at the cursor into A.
*04CD
LD (IX+05H),A
Put the character held in A at the cursor position.

NOTE: IX+05H holds the character at the cursor position.
*04D0
RET
RETURN.

*04D1 – Cursor Management – CURSOR OFF (Jumped to from 0539H)

*04D1
XOR A
Zero A and all Flags.
*04D2
JUMP to 04CDH to put the character held in A at the cursor position.

*04D4 – Cursor Management – HOME CURSOR

*04D4
LD HL,3C00H
Getting ready to HOME the cursor, so load HL with 3C00H.

NOTE: 3C00H is the start of the video display RAM.
*04D7
LD A,(4210H)
Load A with the memory contents of 4210H.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls. In this case, we are looking for the bit which holds whether we are in LARGE characters or SMALL characters.
*04DA
AND FBH
Mask A with FBH (Binary: 1111 1011) to turn off Bit 2.
*04DC
GOSUB to 0570H Put A into memory location 4210H (4210H holds the bit mask for port ECH) and then output A to Port ECH.
*04DF
LD A,(4214H)
Load A with the memory contents of 4214H.

NOTE: 4214H is the number of protected video lines.
*04E2
AND 07H
AND A with 07H (Binary: 0000 0111) to keep only Bits 0, 1, and 2. This means that the only possibilities for A are 0-7.
*04E4
RET Z
If A is ZERO (no lines to protect) then RETURN.
*04E5
Since A is not ZERO, we have to protect some lines. First, GOSUB to 0504H to move the cursor down.
*04E8
DEC A
Decrement A.
*04E9
Loop back to 04E4H to either RETURN if we are at zero, or move down another line and try again.

*04EB – Cursor Management – BACKSPACE

*04EB
DEC HL
Decrement HL to back up the cursor.
*04EC
LD A,(4210H)
Load A with the memory contents of 4210H.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls. In this case, we are looking for the bit which holds whether we are in LARGE characters or SMALL characters.
*04EF
AND 04H
Mask A with 04H (0000 0100) to leave only bit 3 live, allowing Z to be set if Bit 3 is high, and NZ to be set if Bit 3 is low.
*04F1
If it is Z is set, then we have small characters, so jump to skip the next instruction.
*04F3
DEC HL
Decrement HL to back up the cursor another space.
*04F4
LD (HL),20H
Put a space in the current cursor position.
*04F6
RET
RETURN.

*04F7 – Cursor Management – CURSOR BACK

*04F7
LD A,(4210H)
Load A with the memory contents of 4210H.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls. In this case, we are looking for the bit which holds whether we are in LARGE characters or SMALL characters.
*04FA
AND 04H
Mask A with 04H (0000 0100) to leave only bit 3 live, allowing Z to be set if Bit 3 is high, and NZ to be set if Bit 3 is low.
*04FC
If A is not zero (which means A is 4), then GOSUB to the next instruction, which is a clever way to run that routine twice since we are in LARGE type.
*04FF
LD A,L
Put the contents of L into A.
*0500
AND 3FH
Mask A with 3F (0011 1111) to strip off Bits 6 and 7. A can now be no higher than 3F (Decimal: 63).
*0502
DEC HL
Decrement HL to back up the cursor.
*0503
RET NZ
RETURN if we are not at the start of the screen.

*0504 – Cursor Management – CURSOR DOWN

*0504
LD DE,0040H
(If we are at the start of the screen) we need to move down one line, so load DE with 40H (64).
*0507
ADD HL,DE
Add DE (64 characters) to HL (current cursor position).
*0508
RET
RETURN.

*0509 – Cursor Management – CURSOR FORWARD.

*0509
INC HL
HL should be holding the current cursor position. Bump HL one forward.
*050A
LD A,L
Load A with L to check the position in the line.
*050B
AND 3FH
Mask A with 3F (0011 1111) to keep only Bits 0-5, so that it will be no higher than 3F/63.
*050D
RET NZ
If A is not zero, then we are not at the end of the line, so RETURN.

*050E – Cursor Management – CURSOR UP

*050E
LD DE,FFC0H
If we are here, then we are at the end of the line, so we need to move up one line. Start by putting FFC0H into DE.

NOTE: FFC0H is -64, or 1 line length.
*0511
ADD HL,DE
Subtract 64 (the length a line on screen) from HL to move it to the previous line.
*0512
RET
RETURN.

*0513-0520 – Cursor Management – Turn on DOUBLE SIZE and put the cursor on EVEN columns only.

*0513
LD A,(4210H)
Load A with the memory contents of 4210H.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls. In this case, we are looking for the bit which holds whether we are in LARGE characters or SMALL characters.
*0516
OR 04H
OR A against 04 (0000 0100) to turn on the 3rd bit. This will turn on DOUBLE SIZE characters.
*0518
GOSUB to 0570H to put A into memory location 4210H (4210H holds the bit mask for port ECH) and then output A to Port ECH.
*051B
INC HL
Bump HL to move the cursor + 1.
*051C
LD A,L
Load A with the LSB of the cursor position.
*051D
AND FEH
Mask A (the LSB of the cursor position) with FE (1111 1110) which turns off BIT 0. This is to set to an even position.
*051F
LD L,A
Put the newly “evened” A into L. This will then make HL only be on every other column.
*0520
RET
RETURN.

*0521-055F – Cursor Management – Process Special Characters

*0521
LD DE,048EH
Put 048EH into DE. This will eventually act as the RETURN location and is the routine that makes sure the cursor is still on the screen.
*0524
PUSH DE
Put that RETurn address into the STACK.
*0525
CP 08H
Compare A with 08H.

NOTE: 08H is a BACKSPACE.
*0527
If A is BACKSPACE, jump to 04EBH to deal with it.
*0529
CP 0AH
Compare A with 0AH.

NOTE: 0AH is a LINE FEED.
*052B
If A is LINE FEED, jump to 05AFH to deal with it.
*052E
CP 0DH
Compare A with 0DH.

NOTE: 0DH is a CARRIAGE RETURN.
*0530
If A is CARRIAGE RETURN, jump to 05AFH to deal with it.
*0533
CP 0EH
Compare A with 0EH.

NOTE: 0EH is a CURSOR ON.
*0535
If A is CURSOR ON, jump to 04CCH to deal with it.
*0537
CP 0FH
Compare A with 0FH.

NOTE: 0FH is a CURSOR OFF.
*0539
If A is CURSOR OFF, jump to 04D1H to deal with it.
*053B
SUB 15H
Subtract 15H (Decimal: 21) from A to bring it down into the control character range.
*053D
If A is 0, jump to 0560H to deal with it.
*053F
DEC A
Decrement A by 1. This would test for special and alternative characters.
*0540
If A is 0, jump to 056BH to deal with it.
*0542
DEC A
Decrement A by 1. This would test for DOUBLE SIZE.
*0543
If A is DOUBLE SIZE, jump to 0513H to deal with it.
*0545
DEC A
Decrement A by 1. This would test for CURSOR BACK.
*0546
If A is CURSOR BACK, jump to 04F7H to deal with it.
*0548
DEC A
Decrement A by 1. This would test for CURSOR FORWARD.
*0549
If A is CURSOR FORWARD, jump to 0509H to deal with it.
*054B
DEC A
Decrement A by 1. This would test for CURSOR DOWN.
*054C
If A is CURSOR DOWN, jump to 0504H to deal with it.
*054E
DEC A
Decrement A by 1. This would test for CURSOR UP.
*054F
If A is CURSOR UP, jump to 050EH to deal with it.
*0551
DEC A
Decrement A by 1. This would test for HOME CURSOR.
*0552
If A is HOME CURSOR, jump to 04D4H to deal with it.
*0555
DEC A
Decrement A by 1. This would test for RESTART LINE.
*0556
If A is RESTART LINE, jump to 04B2H to deal with it.
*0559
DEC A
Decrement A by 1. This would test for CLEAR TO END OF LINE.
*055A
If A is CLEAR TO END OF LINE, jump to 05BCH to deal with it.
*055C
DEC A
Decrement A by 1. This would test for CLEAR TO END OF SCREEN.
*055D
If A is CLEAR TO END OF SCREEN, jump to 05C5H to deal with it.
*055F
RET
RETURN (to 048EH to makes sure the cursor is still on the screen).

*0560 – Cursor Management – Control Characters.

*0560
LD A,(IX+07H)
Load A with the contents of IX+07H, which toggles TAB and ALTERNATIVE.
*0563
AND 01H
MASK A with 0000 0001, to keep only the character flag bit.
*0565
XOR 01H
XOR A with 0000 0001 to toggle the character flag bit.
*0567
LD (IX+07H),A
Put the MASKED and XORed value back into IX+07H, which toggles TAB and ALTERNATIVE.
*056A
RET
RETURN.

*056B – Cursor Management – Special and Alternative Characters

*056B
LD A,(4210H)
Put the contents of memory location 4210H into A.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls.
*056E
XOR 08H
XOR A with 08H (0000 1000). This will toggle bit 3 to deal with special/alternative characters.

NOTE: Bit 3 of ECH is the SPECIAL CHARACTER SELECT. It will be 0 for KANA and 1 for MISC.
*0570
LD (4210H),A
Put the toggled A back into memory location 4210H.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls.
*0573
OUT (ECH),A
Output A to Port ECH.
*0575
RET
RETURN.

0576 – This routine displays a character, moves forward either 1 or 2 spaces depending on if we are double size or not, and advances the screen if that character pushed the cursor beyond the end of the screen.

*0576
LD (HL),A
Display the character on screen.

NOTE: HL should be the current screen location and A should be the character.
*0577
INC HL
Bump HL to advance the cursor.
*0578
LD A,(4210H)
Put the contents of memory location 4210H into A.

NOTE: 4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls.
*057B
AND 04H
Mask A with 04H (0000 0100), so the only possibilties are 4 (0000 0100) or 0 (0000 0000).
*057D
If it is zero, then we are SMALL SIZE, and JUMP to 0580H.
*057F
INC HL
If we are here, then we are DOUBLE SIZE, so need to bump HL again to advance the cursor (even columns only).
*0580
LD A,H
We need to test to see if we just fell off the screen, so load A with the MSB of the cursor location.
*0581
CP 40H
Compare the MSB of the cursor location held in A against 40H (Binary: 0100 0000, Decimal: 64).
*0583
RET NZ
If it is not zero then we did not fall off the screen, then RETURN.
*0584
If we are here then we fell off the screen so first GOSUB to 050EH to move up a line.
*0587
PUSH HL
Save the cursor location held in HL to the STACK.

*0588 – Cursor Management – Scroll the Screen

*0588
LD A,(4214H)
Load A with the memory contents of 4214H.

NOTE: 4214H is the number of protected video lines.
*058B
AND 07H
AND A with 07H (0000 0111) to turn off all bits except for Bits 0, 1, and 2. This means that the only possibilities for A are 0-7.
*058D
LD HL,3C00H
Load HL with the start of the screen.
*0590
LD DE,0400H
Load DE with the size of the screen (1024 characters).
*0593
PUSH BC
Save the value in Register Pair BC to the STACK.
*0594
LD BC,0040H
Load BC with the number of characters per line (64 characters).
*0597
INC A
Increase A which is holding the number of lines to protect.
*0598
ADD HL,BC
Add BC (the number of characers per line) to HL (the current cursor position), which then moves us down one line.
*0599
EX DE,HL
Swap DE and HL which will then reduce the screen size by one line.
*059A
OR A
Set the flags for A.
*059B
SBC HL,BC
Subtract, with carry, BC from HL.
*059D
EX DE,HL
Swap DE and HL.
*059E
DEC A
Reduce A by one, so that we have one less line to protect.
*059F
Loop back to 0598H until we have finished this for all protectable lines.
*05A1
PUSH DE
Save DE to the STACK.
*05A2
PUSH HL
Save HL to the STACK.
*05A3
OR A
Set the flags for A, as we prepare to move the start back up.
*05A4
SBC HL,BC
Subtract, with carry, BC from HL to move up one line.
*05A6
EX DE,HL
Swap DE and HL so that the source is now the start of screen plus one line.
*05A7
POP HL
Restore HL from the STACK. HL will be the START OF SCREEN.
*05A8
POP BC
Restore BC from the STACK. BC will be the COUNT = SCREEN SIZE – ONE LINE.
*05A9
LDIR
Scroll the unprotected portions of the screen.
*05AB
POP BC
Restore BC from the STACK (it was pushed in 0593H).
*05AC
EX DE,HL
Swap DE and HL, so now HL = CURSOR POSITION.
*05AD
JUMP to 05C6H to clear to the end of screen without changing HL.

*05AF – Cursor Management – CARRIAGE RETURN or LINE FEED

*05AF
GOSUB to 04B2H to move to the start of the line.
*05B2
PUSH HL
Save HL (the cursor position) to the STACK.
*05B3
GOSUB to 0504H to move the cursor down one line.
*05B6
LD A,H
We need to test to see if we just fell off the screen, so load A with the MSB of the cursor location.
*05B7
CP 40H
Compare the MSB of the cursor location held in A against 40H (64).
*05B9
If we fell off the screen the JUMP to 0588H to scroll the screen.
*05BB
POP DE
Otherwise restore DE from the STACK to get the old cursor position.

*05BC – Cursor Management – CLEAR TO END OF LINE

*05BC
PUSH HL
Save HL (contaning the NEW CURSOR POSITION) to the STACK.
*05BD
LD D,H
DE currently holds the END OF LINE. Put the MSB into H.
*05BE
LD A,L
Put the LSB into A.
*05BF
OR 3FH
MASK the LSB of the END OF THE LINE with 3F (63).
*05C1
LD E,A
Load E with the masked value of the END OF THE LINE.
*05C2
INC DE
Bump DE by one so it now points to the start of the next line.
*05C3
JUMP to 05C9H to clear to the end of the line.

*05C5 – Cursor Management – CLEAR TO END OF SCREEN

*05C5
PUSH HL
Save HL (containing the CURSOR POSITION) to the STACK.
*05C6
LD DE,4000H
Set DE to 4000H which is 1 character off the screen.
+*05C9
LD (HL),20H
Put a BLANK into the current cursor position.
|*05CB
INC HL
Bump the current cursor position by one.
|*05CC
RST 18H
We need to check to see if the integer value in HL is greater than or equal to DE (which is 1 character off the screen) so we call the COMPARE DE:HL routine, which 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=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal).
+*05CD
If that RST 18H call is not zero, then we are not off the screen, so loop back to 05C9H until we are done.
*05CF
POP HL
We have cleared the screen so now restore the cursor position back to HL from the STACK.
*05D0
RET
RETURN.

*05D1 – These instructions are never called or used. This was used to hide the name “RON”

Difference between M1 and M3: Rumor has it that this is a malicious destruction of the “printer ready” test routine found at 05D1H-05D8H in the Model I. In the Model III, the first three bytes of the routine are changed from a LD A,(37E8H) instruction to 52H, 4FH, and 4EH (LD D,D; LD C,A; and LD C,(HL); or the ASCII characters “RON”) breaking an otherwise perfectly good routine. An equivalent routine that does work (and which would also have fit nicely into this space) resides from 044BH to 0451H in the Model III (part of the printer driver routine).

*05D1-05D3
“RON”
*05D4-05D5
AND F0H
*05D6-05D7
CP 30H
*05D8
RET

*05D1 – Message Storage Area

*05D1-05D8
0EH + “Cass ? + 03H”

*05D9-0673 – ACCEPT KEYBOARD INPUT ROUTINE
“KLINE” or “LINP1” – WAIT FOR NEXT LINE (take keyboard entry until a carriage return, a break, or buffer overrun occurs).

  • This is the most basic of the string input routines and is used by the two others (1BB3H and 0361H) as a subroutine. To use it, load HL with the required buffer address and the B register with the maximum buffer length required. Keyboard input over the specified maximum buffer length is ignored, and after pressing the (ENTER) key it will return with HL containing the original buffer address and B with the string length.
    A call to this memory location 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.
    On exit the registers contain: HL=Buffer address, B=Number of characters transmitted excluding last, C=Orginal buffer size, A=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.
  • To use a ROM call to accept a restricted number of keyboard characters for input (n), use:
    LD HL,(40A7H)
    LD B,n
    CALL 05D9H
    Up to n characters will be accepted, after which the keyboard will simply be ignored until the ENTER (or LEFT ARROW, or BREAK, or CLEAR) key is pressed. These characters will be stored in consecutive memory cells starting at the address contained in 40A7H-40A8H (the keyboard buffer area), with a 0DH (carriage return) byte at the end. Upon completion, the HL register pair will contain the address of the first character of the stored input, and the B register will contain the number of characters entered. NOTE: No “?” is displayed as a result of the execution of the above program. If the “?” display is desired to prompt the typing of the input, precede the above program segment with:
    LD A,3FH
    CALL 033AH
    LD A,20H
    CALL 033AH
05D9
PUSH HL
Save the start of the input buffer area pointer in register pair HL on the STACK.
05DA-05DB
LD A,0EH
Load register A with a turn on the cursor character.
05DC-05DE
Display a cursor by calling the DISPLAY A CHARACTER routine at 0033H (which puts the character in register A on the video screen).
05DF
LD C,B
Load register C with the size of the input buffer in register B.
05E0-05E2
Call the “WAIT FOR KEYBOARD INPUT” routine at 0049H, so as to wait until a key is pressed.
05E3-05E4
CP 20H
Check to see if the character is a control character by testing A – 20H. Results:
  • If A=20H it sets the ZERO FLAG
  • If A<20H then the CARRY FLAG will be set
  • If A>=20H then the NO CARRY FLAG will be set
  • If A is a CONTROL CHARACTER then C will be set.
05E5-05E6
JUMP if the key that was pressed in register A is greater than or equal to a SPACE, meaning that it is a printable cahracter.
05E7-05E8
CP 0DH
Check to see if the key that was pressed in register A is a CARRIAGE RETURN.
05E9-05EB
JUMP if the key that was pressed in register A is a CARRIAGE RETURN.
05EC-05ED
CP 1FH
Check to see if the key that was pressed in register A is the CLEAR key.
05EE-05EF
JUMP if the key that was pressed in register A is the CLEAR key.
05F0-05F1
CP 01H
Check to see if the key that was pressed in register A is the BREAK key.
05F2-05F3
JUMP if the key that was pressed in register A is the BREAK key.
05F4-05F6
LD DE,05E0H
Load register pair DE with the return address of 05E0H.
05F7
PUSH DE
Save the return address in register pair DE on the STACK.
05F8-05F9
CP 08H
Check to see if the key that was pressed in register A is a backspace (which is 08) the cursor and erase character.
05FA-05FB
JUMP if the key was pressed in register A is a backspace the cursor and erase character.
05FC-05FD
CP 18H
Check to see if the key that was pressed in register A is a backspace character.
05FE-05FF
JUMP if the key that was pressed in register A is a backspace character.
0600-0601
CP 09H
Check to see if the key that was pressed in register A is a tab character.
0602-0603
JUMP if the key that was pressed in register A is a tab character.
0604-0605
CP 19H
Check to see if the key that was pressed in register A is a turn on the 32 character per line mode character.
0606-0607
JUMP if the key that was pressed in register A is a turn on the 32 character per line mode character.
0608-0609
CP 0AH
Check to see if the key that was pressed in register A is a line feed character of CHR$(10).
060A
RET NZ
Return (to 05E0H) if the key that was pressed in register A isn’t a line feed character.
060B
POP DE
Get the return address from the STACK and put it in register pair DE (so that it isn’t 05E0H anymore).
060C
LD (HL),A
We now know that the key pressed is a printable character so save the key that was pressed in register A at the location of the input buffer pointer in register pair HL.
060D
LD A,B
Load register A with the length of the buffer remaining in register B.
060E
OR A
Check to see if there is any more of the input buffer remaining (and set status).
060F-0610
JUMP to 05E0H if the end of the input buffer has been reached.
0611
LD A,(HL)
Now we know the end of the input buffer has not been reached, so load register A with the value at the location of the input buffer pointer in register pair HL.
0612
INC HL
Increment the input buffer pointer in register pair HL.
0613-0615
Display the character by calling the DISPLAY A CHARACTER routine at 0033H (which puts the character in register A on the video screen).
0616
DEC B
Decrement the number of bytes remaining in the input buffer area in register B.
0617-0618
JUMP to 05E0H to get the next character.

Inside the ACCEPT KEYBOARD INPUT ROUTINE. If we are here, the CLEAR key was hit.

0619-061B
Call the CLEAR SCREEN routine at 01C9H (which clears the screen, changes to 64 characters, and homes the screen).
061C
LD B,C
Load register B with the length of the input buffer in register C (which resets the counter of characters transmitted).
061D
POP HL
Get the starting address for the input buffer area from the STACK and put it in register pair HL (which resets the buffer address).
061E
PUSH HL
Save the starting address for the input buffer area in register pair HL on the STACK.
061F-0621
JUMP to 05E0H (to get the next character, which is now the first character in the buffer).
0622-0624
GOSUB to wait for the next key and back up the input buffer pointer in register pair HL if necessary.
0625
DEC HL
Backup to the previous character (the one before the CARRIAGE RETURN) by decrementing the input buffer pointer in register pair HL.
0626
LD A,(HL)
Load register A with the character at the location of the input buffer pointer in register pair HL.
0627
INC HL
Increment the input buffer pointer in register pair HL to the net availabile position.
0628-0629
CP 0AH
Check to see if the character in register A is the line feed character of CHR$(10).
062A
RET Z
Return if the character in register A is a line feed character.
062B
LD A,B
Now we know that character wasn’t a line feed, so we need to test for a buffer full. This loads register A with the number of bytes remaining in the input buffer area in register B.
062C
CP C
Check to see if the number of characters remaining in the input buffer area in register A is the same as the length of the input buffer area in register C.
062D-062E
JUMP to 0622H if there is room for more characters.
062F
RET
The buffer is full! Return.

0630 – This subroutine processes a backspace. On entry, B is the number of characters received, and C is the size of the buffer.

0630
LD A,B
Load register A with the number of bytes remaining in the input buffer area in register B.
0631
CP C
Compare the number of bytes remaining in the input buffer (held in Register A) against the size of the buffer (held in Register C) to see if the buffer is full.
0632
RET Z
Return if the input buffer area is full.
0633
DEC HL
Decrement the input buffer area pointer in register pair HL to backspace the previous character …
0634
LD A,(HL)
… and then get that character into Register A.
0635-0636
CP 0AH
Check to see if the character in register A is the line feed character of CHR$(10).
0637
INC HL
Increment the input buffer area pointer in register pair HL.
0638
RET Z
Return if the character in register A is a line feed character.
0639
DEC HL
Decrement the input buffer area pointer in register pair HL to backspace the previous character in the buffer …
063A-063B
LD A,08H
Load register A with a backspace of CHR$(08) and then …
063C-063E
Effectuate the backspace by calling the DISPLAY A CHARACTER routine at 0033H (which puts the character in register A on the video screen).
063F
INC B
Increment the number of characters remaining in the input buffer area in register B.
0640
RET
Return.

0641 – This subroutine sends the position command.

0641-0642
LD A,17H
Load register A with 17H (Decimal: 23) so as to turn on the 32 character per line mode character.
0643-0645
Call the DISPLAY A CHARACTER routine at 0033H (which puts the character in register A on the video screen). Since that is the 32 character per line mode, that’s what happens.
0646-0648
GOSUB to 0348H to get the cursor line position and return with it in register A.
0649-064A
AND 07H
Mask the cursor line position in register A by ANDing it against 0000 0111, leaving A to be only between 0 and 7.
064B
CPL
Invert the value in register A (Binary: 1111 1xxx).
064C
INC A
Increment the value in register A so that it is 1 <= A <= 8.
064D-064E
ADD 08H
Add 08H (Binary: 0000 1000) to A to clear the upper bits of the counter (because they were all 1’s from the invert, so this will push them all to zero).
064F
LD E,A
Load register E with the number of spaces to be added in register A.
+0650
LD A,B
Load register A with the number of bytes remaining in the input buffer area in register B.
|0651
OR A
Set the flags to check to see if the buffer is full.
|0652
RET Z
Return if the input buffer is full.
|0653-0654
LD A,20H
Load register A with a space character.
|0655
LD (HL),A
Save the space character in register A at the location of the input buffer area pointer in register pair HL.
|0656
INC HL
Increment the input buffer area pointer in register pair HL.
|0657
PUSH DE
Save the value in register pair DE on the STACK.
|0658-065A
Display the space by calling the DISPLAY A CHARACTER routine at 0033H (which puts the character in register A on the video screen).
|065B
POP DE
Get the value from the STACK and put it in register pair DE.
|065C
DEC B
Since you just displayed one of the spaces, decrement the number of bytes remaining in the input buffer area in register B …
|065D
DEC E
… and decrement the number of spaces to be added in register E.
|065E
RET Z
Return if the number of spaces has been added to the input buffer.
+065F-0660
Loop back to 0650H until all the spaces have been added to the input buffer.

0661 – This subroutine is called when a BREAK key is hit.

0661
SCF
Set the CARRY FLAG.

0662H – Inside the BREAK KEY routine – Jumps here if an ENTER was hit, to have the same result, but with the CARRY FLAG untouched.

0662
PUSH AF
Save the value in register pair AF on the STACK.
0663-0664
LD A,0DH
Load register A with a carriage return character.
0665
LD (HL),A
Save the carriage return character in register A at the location of the input buffer area pointer in register pair HL.
0666-0668
Display the carriage return by calling the DISPLAY A CHARACTER routine at 0033H (which puts the character in register A on the video screen). Since that is a CARRIAGE RETURN, that’s what happens.
0669-066A
LD A,0FH
Load register A with a turn off the cursor character.
066B-066D
Turn off the cursor by calling the DISPLAY A CHARACTER routine at 0033H (which puts the character in register A on the video screen).
066E
LD A,C
Load register A with the length of the input (=buffer size) in register C.
066F
SUB B
Subtract the number of bytes remaining in the input buffer area in register B from the length of the input buffer area in register A.
0670
LD B,A
Load register B with the number of characters in the input buffer area in register A.
0671
POP AF
Get the value from the STACK and put it in register pair AF. This also sets the CARRY FLAG if BREAK and unsets it if CARRIAGE RETURN.
0672
POP HL
Get the starting address of the input buffer area from the STACK and put it in register pair HL.
0673
RET
Return.

*0674 – KEYBOARD DRIVER ENTRY ROUTINE

Difference between M1 and M3: In the Model I, this is part of the power-up routine and includes the disk bootstrap routine (06A1H – 06CBH), the preferred BASIC re-entry routine (06CCH-06D1H), and the RST vectors and I/O Device Control Blocks which are relocated to RAM on power-up (06D2H-0707H, relocated to 4000H – 4035H). In the Model III, this area contains the I/O driver entry routine (0674H – 0699H) and additional code used by the LIST and LLIST commands (069AH – 0707H). Note that a jump to 06CCH will no longer get you back into BASIC in the Model III. This might be considered a major blunder in the design of the Model III ROM, both because so many available programs use this re-entry point to BASIC, and because the ROM itself has two jumps to 06CCH (one at 0072H that appears to be unused, and one at 02C3H, which is used if the BREAK key is pressed under the SYSTEM command – a bona fide BUG in the Model III ROM). A substitute re-entry to BASIC that will work with either model is to LD BC,1A18H and then JP 19AEH (this is the code presently found at 06CCH in the Model I).

*0674
PUSH HL
Save register pair HL to the STACK.
*0675
PUSH IX
Save Special Index Register IX to the STACK.
*0677
PUSH DE
Save register pair DE (= the starting address of the device control block) to the STACK.
*0678
POP IX
Get the starting address of the device control block from the STACK and put it in Special Index Register IX.
*067A
PUSH DE
Save register pair DE (= the starting address of the device control block) to the STACK.
*067B
LD HL,0694H
Load register pair HL with a return address of 0694H (to restore all registers and RETurn).
*067E
PUSH HL
Save the return address in register pair HL on the STACK.
*067F
LD C,A
Save the character to output (current held in register A) to register C.
*0680
LD A,(DE)
Load register A with the device type code at the location of the device control block pointer in register pair DE.
*0681
BIT 7,A
Test Bit 7 of A, which is the bit for a DISK FILE.
*0683
If not a disk file, then skip the next 3 instructions and JUMP to 068AH.
*0685
AND B
Isolate the device code bits in A by AND’ing with the device codes in B.
*0686
CP B
Check to see if the updated device type code in register A is the same as the driver entry code in register B.
*0687
JP NZ,4033H
JUMP to the DOS exit link at 4033H if the updated device type code in register A isn’t the same as the driver entry code in register B.
*068A
AND B
Masking A against B also sets Z for WRITE.
*068B
CP 02H
At this point we know that the updated device type code in A is the same as the driver code entry, so let’s move on. First, reset the flags.
*068D
LD L,(IX+01H)
Load register L with the LSB of the driver entry address at the location of the device control block pointer in Special Index Register IX plus one.
*0690
LD H,(IX+02H)
Load register H with the MSB of the driver entry address at the location of the device control block pointer in Special Index Register IX plus one.
*0693
JP (HL)
JUMP to the driver entry address in register pair HL.
*0694
POP DE
Get the value from the STACK and put it in register pair DE.
*0695
POP IX
Get the value from the STACK and put it in Special Index Register IX.
*0697
POP HL
Get the value from the STACK and put it in register pair HL.
*0698
POP BC
Get the value from the STACK and put it in register pair BC.
*0699
RET
Return.

069AH – This subroutine CLEARS the DATA FLAG, sets up a buffer of 255 bytes (held in D) and JUMPS to 2B8DH.

*069A
XOR A
Clear A and all status flags.
*069B
LD (409FH),A
Load the DATA FLAG in 409FH with 0 (since A was just XOR’d against itself).
*069E
LD D,FFH
Load D with 255, which will represent a buffer of 255 bytes.
*06A0
JUMP to 2B8DH which is in the middle of the TOKENize routine. This address loads A with the current character at the BASIC line pointer, tests for end of line, puts it into the memory location pointed to by BC, and exits.
*06A3
AND FDH
Mask A with FDH (1111 1101) to turn off Bit 1.
*06A5
LD (409FH),A
Put A into the DATA FLAG held in 409FH. Note: Bit 0 HIGH means inside a quote. Bit 1 HIGH means inside a DATA. Bit 2 HIGH means inside a REM.
*06A8
LD A,3AH
Load A with 3AH (which is a :).
*06AA
OR A
Set the flags, to start a check for a reserved word.
*06AB
JUMP to 06E2H (to exit this routine back to 2B89H) if it is not a reserved word.
*06AE
LD A,(409FH)
Load A with the DATA FLAG in 409FH. This is to see if we are currently in a quote string.
*06B1
RRA
Rotate A right one bit, with the bit that falls off (BIT 0) being moved to the CARRY FLAG, and the CARRY FLAG is moved to BIT 7.
*06B2
If CARRY is set then we are in quoted string so JUMP to 06E2H which then JUMPs to 2B89H which is in the middle of the TOKENize routing. This address bumps BC (the input buffer pointer), reduces D (the buffer counter), moves the BASIC line pointer forward, and continues.
*06B4
RRA
Rotate A right one bit, with the bit that falls off (BIT 0) being moved to the CARRY FLAG, and the CARRY FLAG is moved to BIT 7.
*06B5
RRA
Rotate A right one bit, with the bit that falls off (BIT 0) being moved to the CARRY FLAG, and the CARRY FLAG is moved to BIT 7. This tests for a REM.
*06B6
If C is set, we are in a REM, so JUMP to 06F6H if we are NOT in a REM.
*06B8
LD A,(HL)
At this point, we assume this is a TOKEN. So load A with the contents of HL to get the token.
*06B9
CP FBH
Check A against FBH (Binary: 1111 1011) to see if it is a REM TOKEN.
*06BB
PUSH HL
Save HL (Position in Text) to the STACK.
*06BC
PUSH BC
Save BC (Position in Buffer) to the STACK.
*06BD
LD HL,06DFH
Set HL to 06DFH, which will act as a RETURN.
*06C0
PUSH HL
Save HL (the return) to the STACK.
*06C1
RET NZ
RETURN if this is NOT a REM TOKEN.

The next set of instructions tests the buffer backwards for M, E, and R, and RETURNS out if those are not found.

*06C2
DEC BC
Decrement the Buffer to back up one character.
*06C3
LD A,(BC)
Put the character in the buffer into A.
*06C4
CP 4DH
Test A for a 4DH (ASCII: M).
*06C6
RET NZ
If it is not a M then RETURN.
*06C7
DEC BC
Decrement the Buffer to back up one character.
*06C8
LD A,(BC)
Put the character in the buffer into A.
*06C9
CP 45H
Test A for a E.
*06CB
RET NZ
If it is not a E then RETURN.
*06CC
DEC BC
Decrement the Buffer to back up one character.
*06CD
LD A,(BC)
Put the character in the buffer into A.
*06CE
CP 52H
Test A for a R.
*06D0
RET NZ
If it is not a R then RETURN.

At this point BC, BC+1, and BC+2 were REM, so check backwards again for a : and if not, RETURN.

*06D1
DEC BC
Decrement the Buffer to back up one character.
*06D2
LD A,(BC)
Put the character in the buffer into A.
*06D3
CP 3AH
Test A for a :.
*06D5
RET NZ
If it is not a : then RETURN.

At this point BC, BC+1, BC+2, and BC+3 were :REM.

*06D6
POP AF
Restore AF from the STACK (to clear the STACK).
*06D7
POP AF
Restore AF from the STACK (to clear the STACK).
*06D8
POP HL
Restore HL from the STACK (to get the position).
*06D9
INC D
INC D
INC D
INC D
We need to decrease the buffer size by 4.
*06DD
JUMP to 0704H to load the next character held in (HL) into A and JUMP to 2BA0H to see if the current token is ELSE and then keep processing.
*06DF
POP BC
Restore BC (the buffer position) from the STACK.
*06E0
POP HL
Restore HL (the text position) from the STACK.
*06E1
LD A,(HL)
Put the character at the current text position into A.
*06E2
JUMP to 2B89H which is in the middle of the TOKENize routing. This address bumps BC (the input buffer pointer), reduces D (the buffer counter), moves the BASIC line pointer forward, and continues.

06E5H – This subroutine sets the DATA FLAG to “BIT 1 HIGH” to indicate that we are in a DATA command.

*06E5
LD A,(409FH)
Load A with the DATA FLAG in 409FH.
*06E8
OR 02H
OR A against 02H (0000 0010) to set BIT 1, the DATA bit.
*06EA
LD (409FH),A
Put the revised A into the DATA FLAG.
*06ED
XOR A
Clear A and all flags.
*06EE
RET
RETURN.

06EFH – This subroutine sets the DATA FLAG to “BIT 2 HIGH” to indicate that we are in a REM command.

*06EF
LD A,(409FH)
Load A with the DATA FLAG in 409FH.
*06F2
OR 04H
OR A against 04H (Binary: 0000 0100) to turn on Bit 2, the REM bit.
*06F4
RETURN.
*06F6
RLA
Rotate A left one bit, with the bit that falls off (BIT 7) being moved to the CARRY FLAG, and the CARRY FLAG is moved to BIT 0. If this results in the CARRY FLAG being set, then we are in a DATA statement.
*06F7
If A had Bit 7 high (which was rotated into CARRY for thsi test), then we are in a DATA statement, JUMP to 06E2H which then JUMPs to 2B89H which is in the middle of the TOKENize routing. This address bumps BC (the input buffer pointer), reduces D (the buffer counter), moves the BASIC line pointer forward, and continues.
*06F9
LD A,(HL)
Load the next character into A.
*06FA
CP 88H
Compare A to 88H to see if it is DATA.
*06FC
If it is DATA then GOSUB to 06E5H to set the flag accordingly.
*06FF
CP 93H
Compare A to 93H to see if it is REM.
*0701
If it is REM then GOSUB to 06EFH to set the DATA FLAG to indicate that we are inside a REM.
*0704
LD A,(HL)
Load the next character into A.
*0705
JUMP to 2BA0H to see if the current token is ELSE and then keep processing.

070B-070F – SINGLE PRECISION ADDITION, REG 1 = (HL) + REG 1

  • Single-precision addition (REG 1=(HL)+ACC) involving a buffer pointed to by the HL register pair and REG 1 (see arithmetic section in Part 2 of this manual for information on the ACC). This part of the program loads the BCDE registers with the value from the buffer, then passes control to 716H.
0708-070A
LD HL,1380H
Load register pair HL with the starting address of a single precision value stored in ROM at 1380H.
070B-070D
GOSUB to 09C2H (which loads a SINGLE PRECISION value pointed to by register pair HL into register pairs BC and DE).
070E-070F
JUMP to the SINGLE PRECISION ADD routine at 0716H (which adds the single precision value in (BC/DE) to the single precision value in REG 1 (i.e., 4121H). The sum is left in REG 1).

0710-0712 – SINGLE PRECISION SUBTRACTION, REG 1 = (HL) – REG 1

  • Single-precision subtraction (REG 1=(HL)-REG 1). This loads the BCDE registers with the value from (HL), then passes control to 0713H.
0710-0712
GOSUB to 09C2H (which loads a SINGLE PRECISION value pointed to by register pair HL into register pairs BC and DE).

0713-0715 – SINGLE PRECISION SUBTRACTION, REG 1 = BCDE – REG 1
“SUBSP”

  • Single-precision subtraction (REG 1=BCDE-REG 1). The routine actually inverts REG 1 (i.e., 4121H) and adds it to the contents of the BCDE registers which, in effect, is a subtraction. The result will be stored in the arithmetic work area (REG 1).
  • Note: If you wanted to subtract two single precision numbers, store the minuend in the BCDE registers and store the subtrahend in 4121H-4124H and then CALL 0713H. The result (in single precision format) is in 4121H-4124H in approximately 670 microseconds.

.

0713-0715
“SSUB”
Go reverse the sign of the single precision value in register pairs BC and DE.

0716-0752 – SINGLE PRECISION ADDITION, REG 1 = BCDE + REG 1
“ADDSP”

  • Single-precision addition (REG 1=BCDE+ACC). This routine adds two single-precision values and stores the result in REG 1 (i.e., 4121H) area.
  • Note: If you wanted to add 2 single precision numbers via a ROM call, store one input into BCDE (with the exponent in B and the LSB in E) and the other into 4121H-4124H, and then call 0716H. The single precision result will be in 4121H-4124H approximately 1.3 milliseconds later.
0716
“SADD”
LD A,B
Load register A with the exponent of the single precision value in register B.
0717
OR A
Check to see if the single precision value in register pairs BC and DE is equal to zero.
0718
RET Z
Return if the single precision value in register pairs BC and DE is equal to zero.
0719-071B
LD A,(4124H)
Load register A with the exponent of the single precision value in REG 1 (i.e., 4121H).
071C
OR A
Check to see if the single precision value in REG 1 (i.e., 4121H) is equal to zero.
071D-071F
JUMP to 09B4H (which moves the SINGLE PRECISION value in DC/DE into REG 1) if the single precision value in REG 1 (i.e., 4121H) is equal to zero.
0720
SUB B
Subtract the value of the exponent for the single precision value in register B from the value of the exponent for the single precision value in REG 1 (i.e., 4121H) in register A..
0721-0722
JUMP if the single precision value in register pairs BC and DE is smaller than the single precision value in REG 1 (i.e., 4121H).
0723
CPL
Adjust the difference in the exponents in register A so that it is positive.
0724
INC A
Increment the difference in the exponents in register A so that it will be the correct positive number.
0725
EX DE,HL
Load register pair HL with the 16-bit value in register pair DE.
0726-0728
Call 09A4 which moves the SINGLE PRECISION value in REG 1 (i.e., 4121H) to the STACK (stored in LSB/MSB/Exponent order).
0729
EX DE,HL
Load register pair DE with the 16-bit value in register pair HL.
072A-072C
Call 09B4H which moves the SINGLE PRECISION value in DC/DE into REG 1 (i.e., 4121H).
072D
POP BC
Get the 16-bit value from the STACK and put it in register pair BC.
072E
POP DE
Get the 16-bit value from the STACK and put it in register pair DE.
072F-0730
CP 19H
Check to see if the difference in the exponents in register A is greater than 24 (because if it is, the numbre cannot be added because of the difference in magnitude).
0731
RET NC
Return if the difference in the exponents is too great.
0732
PUSH AF
Save the difference in the exponents in register A on the STACK.
0733-0735
Set the sign bits for the single precision values and return with the equality of the sign bits in register A.
0736
LD H,A
Load register H with the equality of the sign bits in register A.
0737
POP AF
Get the difference of the exponents from the STACK and put it in register A.
0738-073A
Go shift the single precision value in register pairs BC and DE until it lines up with the single precision value in REG 1 (i.e., 4121H).
073B
OR H
Check to see if the sign bits are equal.
073C-073E
LD HL,4121H
Load register pair HL with the starting address of REG 1 (i.e., 4121H).
073F-0741
JUMP if the signs aren’t equal.
0742-0744
GOSUB to 07B7H to add the single precision value in BCDE to the single precision value in REG 1 (i.e., 4121H).
0745-0747
JUMP if the exponent remains unchanged.
0748
INC HL
Increment the memory pointer in register pair HL, so that it points to the exponent in REG 1 (i.e., 4121H).
0749
INC (HL)
Increment the exponent in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
074A-074C
If the exponent in REG 1 (i.e., 4121H) is too large, JUMP to 07B2H to output an OV ERROR message.
074D-074E
LD L,01H
Load register L with the number of bits to shift the single precision result in register pairs BC and DE.
074F-0751
GOSUB to 07EBH to shift the single precision result in register pairs BC and DE.
0752-0753
JUMP to 0796H.

0754-077C – SINGLE PRECISION MATH ROUTINE

0754
XOR A
Zero register A.
0755
SUB B
Subtract the 8-bit value in register B from the value in register A.
0756
LD B,A
Load register B with the result in register A.
0757
LD A,(HL)
Load register A with the value at the memory pointer in register pair HL.
0758
SBC A,E
Subtract the value in register E from the value in register A.
0759
LD E,A
Load register E with the result in register A.
075A
INC HL
Increment the memory pointer in register pair HL.
075B
LD A,(HL)
Load register A with the value at the location of the memory pointer in register pair HL (to subtract the middle orders).
075C
SBC A,D
Subtract the value in register D from the value in register A.
075D
LD D,A
Load register D with the result in register A.
075E
INC HL
Increment the memory pointer in register pair HL (to point to the high orders).
075F
LD A,(HL)
Load register A with the value at the location of the memory pointer in register pair HL to subtract the high orders.
0760
SBC A,C
Subtract the value in register C from the value in register A.
0761
LD C,A
Load register C with the result in register A.
0762-0764
Because we want a positive mantissa, check if we have to negate the number. If the CARRY FLAG is set, go convert the single precision value to a positive number.
0765
LD L,B
Load register L with the exponent of the original value in register pairs BC and DE.
0766
LD H,E
Load register H with the LSB of the single precision value in register E.
0767
XOR A
Zero register A.
0768
LD B,A
Load register B with the new exponent in register A.
0769
LD A,C
Load register A with the MSB of the single precision value in register C.
076A
OR A
Check to see if the value in register A is equal to zero.
076B-076C
JUMP if the MSB of the single precision value is nonzero.
076D
LD C,D
Shift the NMSB into the MSB by loading register C with the value in register D.
076E
LD D,H
Shift the LSB into the NMSB by loading register D with the value in register H.
076F
LD H,L
Load register H with the value in register L.
0770
LD L,A
Load register L with the value in register A.
0771
LD A,B
Load register A with the new exponent counter in register B.
0772-0773
SUB 08H
Subtract the number of bits just shifted from the new exponent counter in register A.
0774-0775
CP E0H
Compare A against E0H (Binary:1110 0000) to check to see if three bytes have been shifted.
0776-0777
Loop back to 0768H until shift is completed.

0778H – Zero Register 1 (i.e. 4124H)

0778
“RSETSA”
XOR A
Zero register A.
0779-077B
LD (4124H),A
Save the value in register A as the exponent of the single precision result in REG 1 (i.e., 4121H).
077C
RET
Return with a single precision value of zero in REG 1 (i.e., 4121H).

077D-07A7 – SINGLE PRECISION MATH ROUTINE

077D
DEC B
Decrement the new exponent counter in register B.
077E
ADD HL,HL
Shift the 16-bit value in register pair HL left one bit.
077F
LD A,D
Load register A with the NMSB in register D.
0780
RLA
Shift the NMSB in register A left one bit and shift a bit from register pair HL if necessary.
0781
LD D,A
Save the adjusted NMSB in register A into register D.
0782
LD A,C
Load register A with the MSB in register C.
0783
ADC A,A
Multiply the value in register A by two and add the value of the CARRY FLAG to register A.
0784
LD C,A
Load register C with the adjusted value in register A.
0785-0787
Loop until the most significant bit of the single precision value is equal to one.
0788
LD A,B
Load register A with the new exponent counter in register B.
0789
LD E,H
Load register E with the LSB of the single precision value in register H.
078A
LD B,L
Load register B with the value in register L.
078B
OR A
Check to see if there were any bits shifted.
078C-078D
JUMP if there weren’t any bits shifted.
078E-0790
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1 (i.e., 4121H).
0791
ADD A,(HL)
Add the value of the original exponent at the location of the memory pointer in register pair HL to the number of bits shifted in register A.
0792
LD (HL),A
Save the new exponent in register A at the location of the memory pointer in register pair HL.
0793-0794
JUMP if exponent is too small.
0795
RET Z
Return if exponent is equal to zero.
0796
LD A,B
Load register A with the LSB of the single precision value in register B.
0797-0799
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1 (i.e., 4121H).
079A
OR A
Check to see if the most significant bit of the value in register A is set.
079B-079D
Go check for overflow if the most significant bit in the value in register A is set.
079E
LD B,(HL)
Load register B with the exponent at the location of the memory pointer in register pair HL.
079F
INC HL
Increment the memory pointer in register pair HL.
07A0
LD A,(HL)
Load register A with the value of the sign at the location of the memory pointer in register pair HL.
07A1-07A2
AND 80H
Mask the sign bit in register A (1000 0000).
07A3
XOR C
Set the sign bit in register A.
07A4
LD C,A
Load register C with the adjusted MSB of the single precision value in register A.
07A5-07A7
JUMP to 09B4H (which moves the SINGLE PRECISION value in DC/DE into REG 1).

07A8-07B6 – SINGLE PRECISION MATH ROUTINE – Check for overflow if the most significant bit in the value in register A is set

07A8
INC E
Increment the LSB of the single precision value in register E.
07A9
RET NZ
Return if the adjusted LSB of the single precision value in register E is nonzero.
07AA
INC D
Increment the NMSB of the single precision value in register D.
07AB
RET NZ
Return if the adjusted NMSB of the single precision value in register D is nonzero.
07AC
INC C
Increment the MSB of the single precision value in register C.
07AD
RET NZ
Return if the adjusted MSB of the single precision value in register C is nonzero.
07AE-07AF
LD C,80H
Adjust the MSB of the single precision value in register C.
07B0
INC (HL)
Increment the exponent of the single precision value at the location of the memory pointer in register pair HL.
07B1
RET NZ
Return if the adjusted exponent of the single precision value at the location of the memory pointer in register pair HL is nonzero.
07B2-07B3
LD E,0AH
Load register E with an OV ERROR code.

This is the OV ERROR entry point.
07B4-07B6
Go to the Level II BASIC error routine and display an OV ERROR message if the value has overflowed.

07B7-07C2H SINGLE PRECISION MATH ROUTINE – Add the single precision value in BCDE to the single precision value in REG 1 (i.e., 4121H).

07B7
LD A,(HL)
Load register A with the LSB of the single precision value at the location of the memory pointer in register pair HL.
07B8
ADD A,E
Add the LSB of the single precision value in register E to the LSB of the single precision value in register A.
07B9
LD E,A
Load register E with the result in register A.
07BA
INC HL
Increment the memory pointer in register pair HL.
07BB
LD A,(HL)
Load register A with the NMSB of the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
07BC
ADC A,D
Add the NMSB of the single precision value in register D to the NMSB of the single precision value in register A.
07BD
LD D,A
Load register D with the result in register A.
07BE
INC HL
Increment the memory pointer in register pair HL.
07BF
LD A,(HL)
Load register A with the MSB of the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
07C0
ADC A,C
Add the MSB of the single precision value in register C to the MSB of the single precision value in register A.
07C1
LD C,A
Load register C with the result in register A.
07C2
RET
Return.

07C3-07D6 – SINGLE PRECISION MATH ROUTINE – Convert to a single precision number to positive.

07C3-07C5
LD HL,4125H
Load register pair HL with the address of the sign flag storage location.

NOTE: 4125H-4126H is used by floating point routines.
07C6
LD A,(HL)
Load register A with the value of the sign flag at the location of the memory pointer in register pair HL.
07C7
CPL
Complement the sign flag in register A.
07C8
LD (HL),A
Save the adjusted sign flag in register A at the location of the memory pointer in register pair HL.
07C9
XOR A
Zero register A.
07CA
LD L,A
Load register L with the value in register A.
07CB
SUB B
Figure the negative value for register B by subtracting the current value in register B from the value in register A.
07CC
LD B,A
Save the adjusted value in register A in register B.
07CD
LD A,L
Load register A with zero.
07CE
SBC A,E
Figure the negative LSB of the single precision value in register E by subtracting the current LSB of the single precision value in register E from the value in register A.
07CF
LD E,A
Load register E with the adjusted LSB of the single precision value in register A.
07D0
LD A,L
Load register A with zero.
07D1
SBC A,D
Figure the negative NMSB of the single precision value in register D by subtracting the current NMSB of the single precision value in register D from the value in register A.
07D2
LD D,A
Load register D with the adjusted NMSB of the single precision value in register A.
07D3
LD A,L
Load register A with zero.
07D4
SBC A,C
Figure the negative MSB of the single precision value in register C by subtracting the current MSB of the single precision value in register C from the value in register A.
07D5
LD C,A
Load register C with the adjusted MSB of the single precision value in register A.
07D6
RET
Return.

07D7-07F7 – SINGLE PRECISION MATH ROUTINE – Shift the single precision value in register pairs BC and DE until it lines up with the single precision value in REG 1 (i.e., 4121H).

07D7-07D8
LD B,00H
Load register B with zero.
07D9-07DA
SUB 08H
Check to see if the shift counter in register A still indicates at least 8 bits have to be shifted.
07DB-07DC
JUMP if less than 8 bits are left to be shifted.
07DD
LD B,E
Load register B with the LSB of the single precision value in register E.
07DE
LD E,D
Load register E with the NMSB of the single precision value in register D.
07DF
LD D,C
Load register D with the MSB of the single precision value in register C.
07E0-07E1
LD C,00H
Load register C with zero.
07E2-07E3
Loop until there is less than 8 bits left to be shifted.
07E4-07E5
ADD 09H
Adjust the shift counter in register A to its correct value.
07E6
LD L,A
Load register L with the shift counter in register A.
07E7
XOR A
Zero register A.
07E8
DEC L
Decrement the shift counter in register L.
07E9
RET Z
Return if there are no more bits to be shifted.
07EA
LD A,C
Load register A with the MSB of the single precision value in register C.
07EB
RRA
Shift the MSB of the single precision value in register A one place to the right.
07EC
LD C,A
Load register C with the adjusted MSB of the single precision value in register A.
07ED
LD A,D
Load register A with the NMSB of the single precision value in register D.
07EE
RRA
Shift the NMSB of the single precision value in register A one place to the right and pick up the value of the CARRY FLAG.
07EF
LD D,A
Load register D with the adjusted NMSB of the single precision value in register A.
07F0
LD A,E
Load register A with the LSB of the single precision value in register E.
07F1
RRA
Shift the LSB of the single precision value in register A one place to the right and pick up the value of the CARRY FLAG.
07F2
LD E,A
Load register E with the adjusted LSB of the single precision value in register A.
07F3
LD A,B
Load register A with the value in register B.
07F4
RRA
Shift the value in register A one place to the right and pick up the value of the CARRY FLAG.
07F5
LD B,A
Load register B with the adjusted value in register A.
07F6-07F7
Loop until all of the bits have been shifted.

07F8-07FB – SINGLE PRECISION CONSTANT STORAGE LOCATION

07F8-07FB
00 00 00 81
A single precision constant equal to 1.0 is stored here.

07FC-0808 – SINGLE PRECISION CONSTANTS STORAGE LOCATION2

07FC
03
The number of single precision constants which follows is stored here.
07FD-0800
AA 56 19 80
A single precision constant equal to .598978 is stored here.
0801-0804
F1 22 76 80
A single precision constant equal to .961471 is stored here.
0805-0808
45 AA 38 82
A single precision constant equal to 2.88539 is stored here.

0809-0846 – LEVEL II BASIC LOG ROUTINE – LOG

  • The LOG(n) routine, (REG 1=LOG (REG 1)). This routine finds the LOGarithm of the value in REG 1 (i.e., 4121H) area.
    A call to 0809H computes the natural log (base E) of the single precision value in REG 1 (i.e., 4121H). The result is returned as a single precision value in REG 1 (i.e., 4121H).
  • NOTE: To use a ROM call to find LOG(X), where X is a positive single precision variable, store the value of X in 4121H-4124H and then CALL 0809H. The result (in single precision format) is in 4121H-4124Hin approximately 19 milliseconds.

    NOTE: A fatal error occurs if the value of the input variable is zero or negative.
0809-080B
“LOG”
Go check the sign of the single precision value in REG 1 (i.e., 4121H).
080C
OR A
Check to see if the single precision value in REG 1 (i.e., 4121H) is negative or positive.
080D-080F
Go the Level II BASIC error routine and display a FC ERROR message if the current single precision value in REG 1 (i.e., 4121H) is negative.
0810-0812
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1 (i.e., 4121H).
0813
LD A,(HL)
Load register A with the exponent of the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
0814-0816
LD BC,8035H
Load register BC with the exponent and the MSB of a single precision constant (which is 32821).
0817-0819
LD DE,04F3H
Load register DE with the NMSB and the LSB of a single precision constant (which is 1267). Register pairs BC and DE are now equal to the single precision constant of .707107.
081A
SUB B
Subtract the exponent in register B from the exponent of the x-value in register A.
081B
PUSH AF
Save the difference between the two exponents in register A on the STACK.
081C
LD (HL),B
Save the exponent in register B as the exponent of the x-value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
081D
PUSH DE
Save the NMSB and the LSB of the single precision value in register pair DE on the STACK.
081E
PUSH BC
Save the exponent and the MSB of the single value in register pair BC on the STACK.
081F-0831
Go add the x-value to the single precision constant in register pairs BC and DE and return with the result in REG 1 (i.e., 4121H), by calling the SINGLE PRECISION ADD routine at 0716H (which adds the single precision value in (BC/DE) to the single precision value in REG 1 (i.e., 4121H). The sum is left in REG 1).
0822
POP BC
Get the exponent and the MSB of the single precision value from the STACK and put it in register pair BC.
0823
POP DE
Get the NMSB and the LSB of the single precision value from the STACK and put it in register pair DE.
0824
INC B
Multiply the single precision value in register pairs BC and DE by two by bumping the exponent in register B.
0825-0827
GOSUB to 08A2H to divide the single precision value in register pairs BC and DE by the x-value in REG 1 (i.e., 4121H) and return with the result in REG 1 (i.e., 4121H).
0828-082A
LD HL,07F8H
Load register pair HL with the starting address of a single precision constant (which is at 2040).
082B-082D
GOSUB to 0710H to subtract the x-value in REG 1 (i.e., 4121H) from the single precision constant of 1. 0 at the location of the memory pointer in register pair HL and return with the result in REG 1 (i.e., 4121H).
082E-0830
LD HL,07FCH
Load register pair HL with the starting address of a storage location for single precision constants to be used for a series of computations (which is at 2044).
0831-0833
Go do a series of computations and return with the result in REG 1 (i.e., 4121H).
0834-0836
LD BC,8080H
Load register BC with the exponent and the MSB of a single precision constant.
0837-0839
LD DE,0000H
Load register pair DE with the NMSB and the LSB of a single precision. Register pairs BC and DE are now equal to a single precision of -0.5.
083A-083C
GOSUB to 0716H to add the x-value in REG 1 (i.e., 4121H) to the single precision constant in register pairs BC and DE and return with the result in REG 1 (i.e., 4121H), by calling the SINGLE PRECISION ADD routine at 0716H (which adds the single precision value in (BC/DE) to the single precision value in REG 1 (i.e., 4121H). The sum is left in REG 1).
083D
POP AF
Get the difference between the two original exponents from the STACK and put it in register A.
083E-0840
GOSUB to 0F89H to convert the value in register A to a single precision number and add it to the x-value in REG 1 (i.e., 4121H). Return with the result in REG 1.
0841-0843
LD BC,8031H
Load register pair BC with the exponent and the MSB of a single precision constant.
0844-0846
LD DE,7218H
Load register pair DE with the NMSB and the LSB of a single precision constant. Register pairs BC and DE are now equal to a single precision value of 0.693147.

0847-0891 – SINGLE PRECISION MULTIPLICATION, REG 1 = BCDE * REG 1 – “MLTSP”

  • Single-precision multiplication (REG 1=BCDE*ACC).
    Multiplies the current value in WRAl by the value in (BC/DE). the product is left in WRAl.
  • Note: If you wanted to multiply two single precision numbers store one operand in the BCDE registers, the other in 4121H-4124H CALL 0847H. The result (in single precision format) is in 4121H-4124H in approximately 2.2 milliseconds.
0847-0849
“SMUL”
Go check to see if the single precision value in REG 1 (i.e., 4121H) is equal to zero.
084A
RET Z
Return if the single precision value in REG 1 (i.e., 4121H) is equal to zero.
084B-084C
LD L,00H
Load register L with a bit mask.
084D-084F
Go check for possible overflow and the single precision value in register pairs BC and DE equal to zero.
0850
LD A,C
Load register A with the single precision value’s MSB in register C.
0851-0853
LD (414FH),A
Save the MSB of the single precision value in register A at memory location 414FH.
0854
EX DE,HL
Load register pair HL with the NMSB and the LSB of the single precision value in register pair DE.
0855-0857
LD (4150H),HL
Save the NMSB and the LSB of the single precision value in register pair HL at memory locations 4150H and 4151H.
0858-085A
LD BC,0000H
Load register pair BC with zero.
085B
LD D,B
Load register D with the value in register B.
085C
LD E,B
Load register E with the value in register B.
085D-085F
LD HL,0765H
Load register pair HL with the return address.
0860
PUSH HL
Save the return address in register pair HL on the STACK.
0861-0863
LD HL,0869H
Load register pair HL with the return address.
0864
PUSH HL
Save the return address in register pair HL on the STACK.
0865
PUSH HL
Save the return address in register pair HL on the STACK.
0866-0868
LD HL,4121H
Load register pair HL with the starting address of the single precision value in REG 1 (i.e., 4121H).
0869
LD A,(HL)
Load register A with the LSB of the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
085A
INC HL
Increment the memory pointer in register pair HL.
085B
OR A
Check to see if the LSB of the single precision value in REG 1 (i.e., 4121H) in register A is equal to zero.
086C-086D
JUMP if the LSB of the single precision value in REG 1 (i.e., 4121H) is equal to zero.
086E
PUSH HL
Save the memory pointer in register HL on the STACK.
086F-0870
LD L,08H
Load register L with the bit shift counter.
0871
RRA
Shift the LSB of the single precision value in REG 1 (i.e., 4121H) in register A one place to the right.
0872
LD H,A
Load register H with the adjusted LSB in register A.
0873
LD A,C
Load register A with the MSB of the single precision value in register C.
0874-0875
JUMP forward to 0881H if BIT 0 in the LSB just shifted wasn’t set.
0876
PUSH HL
Save the value in register pair HL on the STACK.
0877-0879
LD HL,(4150H)
Load register pair HL with the NMSB and the LSB of the original value in register pairs BC and DE.
087A
ADD HL,DE
Add the NMSB and the LSB of the total figured so far in register pair DE to the NMSB and the LSB of the original value in register pair HL.
087B
EX DE,HL
Load register pair DE with the adjusted total in register pair HL.
087C
POP HL
Get the value from the STACK and put it in register pair HL.
087D-087F
LD A,(414FH)
Load register A with the MSB of the original value in register pairs BC and DE.
0880
ADC A,C
Add the MSB of the original value in register A to the MSB of the total figured so far in register C.
0881
RRA
Shift the adjusted MSB of the total in register A one place to the right.
0882
LD C,A
Load register C with the adjusted MSB of the total in register A.
0883
LD A,D
Load register A with the NMSB of the total in register D.
0884
RRA
Shift the NMSB of the total in register A one place to the right.
0885
LD D,A
Load register D with the adjusted NMSB of the total in register A.
0886
LD A,E
Load register A with the LSB of the total in register E.
0887
RRA
Shift the LSB of the total in register A one place to the right.
0888
LD E,A
Load register E with the adjusted LSB of the total in register A.
0889
LD A,B
Load register A with the value in register B.
088A
RRA
Shift the value in register A one place to the right.
088B
LD B,A
Load register B with the adjusted value in register A.
088C
DEC L
Decrement the bit counter in register L.
088D
LD A,H
Load register A with the LSB of the current value in register H.
088E-088F
Loop until 8 bits have been shifted.
0890
POP HL
Get the memory pointer from the STACK and put it in register pair HL.
0891
RET
Return.

0892-0896 – SINGLE PRECISION MATH ROUTINE
This is accomplished by a circular shift of BC/DE one byte – B is lost, C is replaced by A.

0892
LD B,E
Load register B with the LSB of the single precision value in register E.
0893
LD E,D
Load register E with the NMSB of the single precision value in register D.
0894
LD D,C
Load register D with the MSB of the single precision value in register C.
0895
LD C,A
Load register C with the value in register A.
0896
RET
Return.

0897-08Al – SINGLE PRECISION MATH ROUTINE – Divide a single precision number by 10.

0897-0899
Call 09A4 which moves the SINGLE PRECISION value in REG 1 (i.e., 4121H) to the STACK (stored in LSB/MSB/Exponent order).
089A-089C
LD HL,0DD8H
Load register pair HL with the starting address of a single precision constant equal to 10.
089D-089F
Call 09B1H (which moves a SINGLE PRECISION number pointed to by HL to REG 1).
08A0
POP BC
Get the exponent and the MSB of the single precision value on the STACK and put it in register pair BC.
08A1
POP DE
Get the NMSB and the LSB of the single precision value from the STACK and put it in register pair DE.

08A2-0903 – SINGLE PRECISION DIVISION, REG 1 = BCDE / REG 1

  • “DIVSP” – Single-precision division (REG 1=BCDE/REG 1). If REG 1=0 a ” /0 ERROR ” will result.
    This routine will divide the SINGLE PRECISION value in register pairs BC and DE by the single precision value in REG 1 (i.e., 4121H). The result is returned in REG 1.
  • To use a ROM call to divide two single precision numbers, store the dividend in registers BCDE, and the divisor in 4121H-4124H and then CALL 08A2H. The result (in single precision format) is in 4121H-4124H and then pproximately 4.8 milliseconds. Overflow or /0 will error out and return to Level II.
08A2-08A4
“SDIV”
Go check to see if the single precision value in REG 1 (i.e., 4121H) is equal to zero.
08A5-08A7
Go to the Level II BASIC error routine and display an /0 ERROR message if the single precision value in REG 1 (i.e., 4121H) is equal to zero.
08A8-08A9
LD L,FFH
Load register L with a bit mask.
08AA-08AC
Go adjust the exponent in REG 1 (i.e., 4121H) for division.
08AD
INC (HL)
Increment the value of the exponent for the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
08AE
INC (HL)
Increment the value of the exponent for the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
08AF
DEC HL
Decrement the value of the memory pointer in register pair HL.
08B0
LD A,(HL)
Load register A with the MSB of the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
08B1-08B3
LD (4089H),A
Save the MSB of the single precision value in REG 1 (i.e., 4121H) in register A at memory location 4089H.
08B4
DEC HL
Decrement the value of the memory pointer in register pair HL.
08B5
LD A,(HL)
Load register A with the NMSB of the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
08B6-08B8
LD (4085H),A
Save the NMSB of the single precision value in REG 1 (i.e., 4121H) in register A at memory location 4085H.
08B9
DEC HL
Decrement the value of the memory pointer in register pair HL.
08BA
LD A,(HL)
Load register A with the LSB of the single precision value in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
08BB-08BD
LD (4081H),A
Save the LSB of the single precision value in REG 1 (i.e., 4121H) in register A at memory location 4081H.
08BE
LD B,C
Load register B with the MSB of the single precision value in register C.
08BF
EX DE,HL
Load register pair HL with the NMSB and the LSB of the single precision value in register pair DE.
08C0
XOR A
Zero register A.
08C1
LD C,A
Zero the MSB of the total by loading register C with the value in register A.
08C2
LD D,A
Zero the NMSB of the total by loading register D with the value in register A.
08C3
LD E,A
Zero the LSB of the total by loading register E with the value in register A.
08C4-08C6
LD (408CH),A
Zero memory location 408CH.
08C7
PUSH HL
Save the NMSB and LSB of the dividend in register pair HL on the STACK.
08C8
PUSH BC
Save the MSB of the dividend in register B on the STACK.
08C9
LD A,L
Load register A with the LSB of the dividend in register L.
08CA-08CC
CALL 4080H
GOSUB to the Level II BASIC division routine.

NOTE: 4080H-408DH is a division support routine.
08CD-08CE
SBC 00H
Adjust the flags.
08CF
CCF
Invert the CARRY FLAG.
08D0-08D1
JUMP down to 08D9H (which is a Z-80 trick) if not done.
08D2-08D4
LD (408CH),A
Save the value in register A at memory location 408CH.
08D5
POP AF
Get the value from the STACK and put it in register pair AF.
08D6
POP AF
Get the value from the STACK and put it in register pair AF.
08D7
SCF
Set the CARRY FLAG.
08D8
D2
Z-80 Trick – See the note at 0134H for an explanation.
08D9
POP BC
Get the value from the STACK and put it in register pair BC.
08DA
POP HL
Get the value from the STACK and put it in register pair HL.
08DB
LD A,C
Load register A with the MSB of the total in register C.
08DC
INC A
Increment the MSB of the total in register A.
08DD
DEC A
Decrement the MSB of the total in register A.
08DE
RRA
Shift the MSB of the total in register A one place to the right.
08DF-08E1
JUMP back to 0797H if done.
08E2
RLA
Reset the CARRY FLAG.
08E3
LD A,E
Load register A with the LSB of the total in register E.
08E4
RLA
Multiply the LSB of the total in register A by two.
08E5
LD E,A
Load register E with the adjusted LSB of the total in register A.
08E6
LD A,D
Load register A with the NMSB of the total in register D.
08E7
RLA
Multiply the NMSB of the total in register A by two.
08E8
LD D,A
Load register D with the adjusted NMSB of the total in register A.
08E9
LD A,C
Load register A with the MSB of the total in register C.
08EA
RLA
Multiply the MSB of the total in register A by two.
08EB
LD C,A
Load register C with the adjusted MSB of the total in register A.
08EC
ADD HL,HL
Multiply the NMSB and the LSB of the dividend in register pair HL by two.
08ED
LD A,B
Load register A with the MSB of the dividend in register B.
08EE
RLA
Multiply the MSB of the dividend in register A by two.
08EF
LD B,A
Load register B with the adjusted MSB of the dividend in register A.
08F0-08F2
LD A,(408CH)
Load register A with the value at memory location 408CH.
08F3
RLA
Multiply the value in register A by two.
08F4-08F6
LD (408CH),A
Save the adjusted value in register A at memory location 408CH.
08F7
LD A,C
Load register A with the MSB of the total in register C.
08F8
OR D
Combine the NMSB of the total in register D with the value in register A.
08F9
OR E
Combine the LSB of the total in register E with the value in register A.
08FA-08FB
JUMP back to 08C7H if the total isn’t equal to zero.
08FC
PUSH HL
Save the NMSB and the LSB of the dividend in register pair HL on the STACK.
08FD-08FF
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1 (i.e., 4121H).
0900
DEC (HL)
Decrement the exponent in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
0901
POP HL
Get the NMSB and the LSB of the dividend from the STACK and put it in register pair HL.
0902-0903
JUMP back to 08C7H if the exponent in REG 1 (i.e., 4121H) isn’t equal to zero.

0904-0906 – DISPLAY OV ERROR MESSAGE

0904-0906
Display an ?OV ERROR.

0907-0913 – DOUBLE PRECISION MATH ROUTINE

0907-0908
LD A,FFH
Load register A with a bit mask of FFH.
0909
2E
Z-80 Trick – See the note at 0134H for an explanation.
090A
XOR A
Zero A and clear the flags.
090B-090D
LD HL,412DH
Load register pair HL with the address of the MSB in REG 2.
090E
LD C,(HL)
Load register C with the MSB of the value in REG 2 at the location of the memory pointer in register pair HL.
090F
INC HL
Increment the value of the memory pointer in register pair HL.
0910
XOR (HL)
Combine the value of the exponent in REG 2 at the location of the memory pointer in register pair HL with the bit mask in register A.
0911
LD B,A
Load register B with the adjusted exponent in register A.
0912-0913
LD L,00H
Load register L with a bit mask.

0914-0930 – SINGLE PRECISION MATH ROUTINE

0914
LD A,B
Load register A with the exponent in register B.
0915
OR A
Check to see if the exponent in register A is equal to zero.
0916-0917
JUMP to 0937H if the exponent in register A is equal to zero.
0918
LD A,L
Load register A with the bit mask in register L.
0919-091B
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1 (i.e., 4121H).
091C
XOR (HL)
Combine the value of the exponent at the location of the memory pointer in register pair HL with the bit mask in register A.
091D
ADD A,B
Add the value of the exponent in register B to the value of the exponent in register A.
091E
LD B,A
Load register B with the combined exponents in register A.
091F
RRA
Shift the value of the combined exponents in register A one place to the right.
0920
XOR B
Check to see if the CARRY FLAG was set by combining the two exponents.
0921
LD A,B
Load register A with the combined exponents value in register B.
0922-0924
JUMP to 0936H if overflow has occurred.
0925-0926
ADD 80H
Reload the new exponent into A and turn on bit 8 (80H = Binary 10000000).
0927
LD (HL),A
Save the value of the combined exponent in register A as the exponent in REG 1 (i.e., 4121H) at the location of the memory pointer in register pair HL.
0928-092A
JUMP if the combined exponent in register A is equal to zero.
092B-092D
Go turn on the sign bit of the MSB in REG 1 (i.e., 4121H) and register B and save the sign bits.
092E
LD (HL),A
Save the value in register A at the location of the memory pointer in register pair HL.
092F
DEC HL
Decrement the memory pointer in register pair HL so that it points to the exponent in REG 1 (i.e., 4121H).
0930
RET
Return.

0931-093D – SINGLE PRECISION MATH ROUTINE

0931-0933
GOSUB to 0955H to check the value of the sign bit for the value in REG 1 (i.e., 4121H).
0934
CPL
Reverse the result of the sign bit test in register A.
0935
POP HL
Get the value from the STACK and put it in register HL.
0936
OR A
Set the flags according to the value of the sign bit test.
0937
POP HL
Get the value from the STACK and put it in register pair HL.
0938-093A
JUMP to 0778H if the value in REG 1 (i.e., 4121H) is negative.
093B-093D
If its not negative, jump to 07B2H.

093E-0954 – SINGLE PRECISION MATH ROUTINE – Multiply the current value by 10

093E-0940
Call 09BF which loads the SINGLE PRECISION value in REG 1 (i.e., 4121H) into register pair BC/DE.
0941
LD A,B
Load register A with the value of the exponent in register B.
0942
OR A
Check to see if the exponent in register A is equal to zero.
0943
RET Z
Return if the single precision value in register pairs BC and DE is equal to zero.
0944-0945
ADD 02H
Multiply the value of the exponent in register A by four.
0946-0948
Display an ?OV ERROR if the adjusted exponent in register A is too large.
0949
LD B,A
Load register B with the adjusted exponent in register A.
094A-094C
Go add the original value in REG 1 (i.e., 4121H) to the adjusted value in register pairs BC and DE and return with the original result in REG 1 (i.e., 4121H) by calling the SINGLE PRECISION ADD routine at 0716H (which adds the single precision value in (BC/DE) to the single precision value in REG 1 (i.e., 4121H). The sum is left in REG 1).
094D-094F
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1 (i.e., 4121H).
0950
INC (HL)
Increment the value of the exponent in REG 1 at the location of the memory pointer in register pair HL. REG 1 now holds the original value times ten.
0951
RET NZ
Return if the new value in REG 1 is in an acceptable range.
0952-0954
Display an ?OV ERROR if the value of the exponent at the location of the memory pointer in register pair HL is too large.

0955-0963 – SINGLE PRECISION MATH ROUTINE – “SIGN”. Checks the value of the sign bit for the value in REG 1.

0955-0957
“SIGN”
LD A,(4124H)
First we need to check to see if the number is zero, so load register A with the value of the exponent in REG 1.
0958
OR A
Set the flags for Register A.
0959
RET Z
Return if the single precision value in REG 1 is equal to zero.
095A-095C
LD A,(4123H)
Since the number is not zero, step back 1 memory location and load register A with the MSB of the single precision value in REG 1.
095E
“FCOMPS”
CPL
Flip all the bits in A (= Inverse).
095F
“ICOMS”
RLA
Rotate A left one bit, which puts the value of the sign bit (bit 7) in register A into the CARRY FLAG.
0960
“SIGNS”
SBC A,A
Subtract A and the CARRY FLAG from A. This has the effect of making register A equal to -1 if the sign bit is negative or a value of 0 if the sign bit is positive.
0961
RET NZ
Return if the single precision value in REG 1 is negative.
0962
INC A
Increment the value in register A so that register A will be equal to 1 if the single precision value in REG 1 is positive.
0963
RET
Return.

0964-0976 – SINGLE PRECISION MATH ROUTINE – “FLOAT”. Float the signed number in B,A,D,E. Alters A,B,C,D,E,H,L

0964-0965
“FLOAT”
LD B,88H
Load register B with an exponent for an integer value.
0966-0968
LD DE,0000H
Load register pair DE with zero.
0969-096B
“FLOATR”
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1.
096C
LD C,A
Load register C with the MSB of the integer value.
096D
LD (HL),B
Save the exponent in register B in REG 1 at the location of the memory pointer in register pair HL.
096E-096F
LD B,00H
Load register B with zero.
0970
INC HL
Increment the memory pointer in register pair HL.
0971-0972
LD (HL),80H
Save the sign value at the location of the memory pointer in register pair HL.
0973
RLA
Shift the value of the sign bit for the MSB in register A into the CARRY FLAG.
0974-0976
JUMP to 0762H (“FADFLT”).

0977-0989 – LEVEL II BASIC MATH ROUTINE
ABS

  • ABS routine (REG 1=ABS(REG 1)) input and output can be integer, single-precision or double-precision, depending on what is placed in the NTF (NTF=2, 4 or 8).
    A call to 0977H converts the value in Working Register Area 1 (WRAl) to its positive equivalent. The result is left in REG 1. If a negative integer greater than 2** 15 is encountered, it is converted to a single precision value. The data type or mode flag (40AFH) will be updated to reflect any change in mode.
  • NOTE: To use a ROM call to find ABS(X),store the value of X in 4121H-4122H (integer), in 4121H-4124H (single precision), or in 411DH and then H (double precision), and store the variable type (2, 4, or 8, respectively) in 40AFH. Then CALL 0977H. The result (in the same format as the input variable) is in the same locations in which the input variable was stored. If the input was an integer, the result is also in the HL register pair.
0977-0979
“ABS”
Gosub to 0994H (“VSIGN”) to determine the sign of the current value in REG 1.
097A
RET P
Return if the value in REG 1 is positive, since that means we are done.

097BH – Convert the negative value in REG 1 to its positive equivalent. Alters A,B,C,D,E,H,L

097B
“VNEG”
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
097C-097E
If that test showed INTEGER, jump to 0C5BH (“INEG”)
097F-0981
If that test showed STRING, Jump to 0AF6H (“TMERR”) to display a ?TM ERROR message.
0982-0984
“NEG”
LD HL,4123H
Load register pair HL with the address of the MSB in REG 1 (which would be the sign).

NEGATE function for single-precision values (REG 1=-REG 1). Only BC and DE are saved.
0985
LD A,(HL)
Load register A with the MSB in REG 1 (the sign) held at the location of the memory pointer in register pair HL.
0986-0987
XOR 80H
Complement the sign bit.
0988
LD (HL),A
Save the adjusted MSB in register A in REG 1 (the sign) at the location of the memory pointer in register pair HL.
0989
RET
Return.

098A-0993 – LEVEL II BASIC MATH ROUTINE
SGN” – Alters A,H,L

  • SGN function (REG 1=SGN(REG 1)). After execution, NTF=2 and REG 1=-l, 0 or 1 depending on sign and value of ACC before execution.
  • NOTE: To use a ROM call to find SGN(X), store the value of X in 4121H-4122H (integer), in 4121H-4124H (single precision), or in 4124H (double precision) and then store the variable type (2, 4, or 8, respectively) in 40AFH and then CALL 098AH. The result (in integer format) is in 4121H-4122H and in the HL register pair.
098A-098C
“SGN”
GOSUB to 0994H (“VSIGN”) to test the sign of the current value in REG 1.
098D
“CONIA”
LD L,A
Load register L with the result of the sign test in register A.
098E
RLA
Shift the sign bit in register A into the CARRY FLAG.
098F
SBC A,A
Adjust the value in register A so that it will be equal to zero if the current value in REG 1 is positive and equal to -1 if the current value in REG 1 is negative.
0990
LD H,A
Save the adjusted value in register A in register H.
0991-0993
JUMP to 0A9AH (“MAKINT”) to return the result and set VALTYP.

0994-09A3 – LEVEL II BASIC MATH ROUTINE.
VSIGN” – Get the sign of the value in the FAC in A. Alters A,H,L

  • This routine checks the sign of the ACC. NTF must be set. After execution A register=00 if REG 1=0, A=01 if ACC > 0 or A=FFH if A < 1. The Flags are also valid.
0994
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0995-0997
If that test showed STRING, JUMP to 0AF6H (“TMERR”) to display a ?TM ERROR message.
0998-099A
P but NZ means single precision, or double precision, so JUMP to 0955H (“SIGN”) if the current value in REG 1 is single precision or double precision.
099B-099D
LD HL,(4121H)
At this point, we know we have an integer. Load register pair HL with the integer value in REG 1.
099E,099F
“ISIGN”
LD A,H
OR L
The best way to test a 2 register value against zero is to OR them, because the only way the Z flag will get set is if they both were zero.
09A0
RET Z
Return if the integer value in REG 1 is equal to zero.
09A1
LD A,H
If it isn’t zero, sign is in H so load register A with the MSB of the integer value in register H.
09A2-09A3
JUMP to 095FH (“ICOMPS”).

09A4-09B0 – SINGLE PRECISION MATH ROUTINE
“LDSTSA”

  • Loads Single-precision value from ACC to STACK ((SP)=ACC). To retrieve this value, POP BC followed by POP DE. A, BC and HL are unchanged by this function.
09A4
“SSTAK”
EX DE,HL
We need to save HL, so we load register pair DE with the value in register pair HL.
09A5-09A7
LD HL,(4121H)
Load register pair HL with the LSB and the NMSB of the single precision value in REG 1.
09A8
EX (SP),HL
Exchange the return address on the STACK with the NMSB and the LSB of the single precision value in register pair HL.
09A9
PUSH HL
Save the return address in register pair HL on the STACK.
09AA-09AC
LD HL,(4123H)
Load register pair HL with the exponent and the MSB of the single precision value in REG 1.
09AD
EX (SP),HL
Exchange the return address on the STACK with the exponent and the MSB of the single precision value in register pair HL.
09AE
PUSH HL
Save the return address in register pair HL on the STACK.
09AF
EX DE,HL
Get the old HL back by swapping register pair HL with register pair DE.
09B0
RET
Return.

09Bl-09BE – SINGLE PRECISION MATH ROUTINE
“LDSAHL”

  • This routine loads four bytes from the location pointed to by HL, into the ACC. (REG 1=(HL)).
  • It moves a number from memory [(HL)] to FAC. It alters B,C,D,E,H,L. Upon exit the number is in B,C,D,E and (HL):=(HL)+4
09B1-09B3
“SCOPY”
Call 09C2H (which loads a SINGLE PRECISION value pointed to by register pair HL into register pairs BC and DE).
09B4
“DSTOR”
EX DE,HL
Load register pair HL with the NMSB and the LSB of the single precision value in register pair DE.

This routine loads REG 1 with the contents of the BC and DE register pairs. (REG 1=BCDE). BC and HL remain unaltered.
09B5-09B7
LD (4121H),HL
Save the NMSB and the LSB of the single precision value in register pair HL in REG 1.
09B8
LD H,B
Load register H with the exponent of the single precision value in register B.
09B9
LD L,C
Load register L with the MSB of the single precision value in register C.
09BA-09BC
LD (4123H),HL
Save the exponent and the MSB of the single precision value in register pair HL in REG 1
09BD
EX DE,HL
Load register pair HL with the value in register pair DE.
09BE
RET
Return.

09BF-09CA – SINGLE PRECISION MATH ROUTINE
“LDRASA”

  • This routine is the opposite of the 09B4H routine. It loads four bytes from REG 1 (single-precision) into the BC and DE register pairs. (BCDE=ACC). A is unchanged.
  • Move FAC to registers (B,C,D,E). Alters B,C,D,E,H,L
09BF-09C1
LD HL,4121H
Load register pair HL with the starting address for a single precision value in REG 1.
09C2
“SGET”
LD E,(HL)
Load register E with the LSB of the single precision value in REG 1 at the location of the memory pointer in register pair HL.

This routine will load the BCDE register pairs with four bytes from the location pointed to by HL. (BCDE=(HL)),. With these types of data movements, the E register is loaded with the LSB and the B register. with the MSB.
09C3
INC HL
Increment the value of the memory pointer in register pair HL.
09C4
LD D,(HL)
Load register D with the NMSB of the single precision value in REG 1 at the location of the memory pointer in register pair HL.
09C5
INC HL
Increment the value of the memory pointer in register pair HL.
09C6
LD C,(HL)
Load register C with the MSB of the single precision value in REG 1 at the location of the memory pointer in register pair HL.
09C7
INC HL
Increment the value of the memory pointer in register pair HL.
09C8
LD B,(HL)
Load register B with the exponent of the single precision value in REG 1 at the location of the memory pointer in register pair HL.
09C9
INC HL
Increment the value of the memory pointer in register pair HL.
09CA
RET
Return.

09CB-09Dl – SINGLE PRECISION MATH ROUTINE
“LDHLSA”

  • This routine is the opposite of the 9B1H routine. It loads four bytes from REG 1 to the memory location pointed to by HL. ((HL)=ACC).
  • Move number from FAC to memory [(HL)]. Alters A,B,C,D,E,H,L
09CB-09CD
LD DE,4121H
Load register pair DE with the starting address for a single precision value in REG 1.
09CE-09CF
LD B,04H
Load register B with the number of bytes to be moved for a single precision value.

Data move routine. This moves four bytes from the location pointed to by DE into the location pointed to by HL. ((HL)=(DE)).
09D0-09D1
JUMP to 09D7H (which is the GENERAL PURPOSE MOVE routine and moves the contents of the B Register bytes from the address in DE to the address in HL).

09D2-09DE – MOVE VALUE POINTED TO BY HL TO THE LOCATION POINTED TO BY DE
“LDDEHL”

  • This is the VARIABLE MOVE Routine which moves the number of bytes specified in the type flag (40AFH) from the address in DE to the address in HL. Uses A, DE and HL.
  • Move number from (DE) to (HL). Alters A,B,C,D,E,H,L. Exits with (DE):=(DE)+4 : (HL):=(HL)+4
09D2
EX DE,HL
Exchange the value in register pair HL with the value in register pair DE.

Data move routine. The location pointed to by DE is loaded with bytes from the location pointed to by HL. The number of bytes moved is determined by the value in the NTF. ((DE)=(HL)).
09D3-09D5
“LDHLDE”
LD A,(40AFH)
Load register A with the current value of the number type flag (which is in 40AFH).

This routine is similar to 9D2H above. The only difference is that it moves data in the opposite direction. ((HL) = (DE)).

Note: 40AFH holds the current number’s type flag as follows:
  • 2: Integer
  • 3: String
  • 4: Single precision
  • 8: Double precision
09D6
“MOVEA”
LD B,A
Load register B with the number of bytes to be moved in register A.

This routine is the same as 9D3H except that the number of bytes moved depends on the value in the A register ((HL) = (DE)).
09D7
“MOVEB”
LD A,(DE)
Load register A with the value at the location of the memory pointer in register pair DE.

This routine is the same as 9D6H except that the number of bytes shifted is determined by the value in the B register ((HL)=(DE)).
This is the GENERAL PURPOSE MOVE routine and moves the contents of the B Register bytes from the address in DE to the address in HL).
09D8
LD (HL),A
Save the value in register A at the location of the memory pointer in register pair HL.
09D9
INC DE
Increment the value of the memory pointer in register pair DE.
09DA
INC HL
Increment the value of the memory pointer in register pair HL.
09DB
DEC B
Decrement the value of the byte counter in register B.
09DC-09DD
Loop until all of the bytes have been moved.
09DE
RET
Return.

09DF-09F3 – SINGLE PRECISION MATH ROUTINE

  • Unpack the FAC and the registers. Alters A,C,H,L. When the number in the FAC is unpacked, the assumed one in the mantissa is restored, and the complement of the sign is placed in FAC+1.
09DF-09E1
LD HL,4123H
Load register pair HL with the address of the MSB of the value in REG 1 (which would be the high order number and the sign).
09E2
LD A,(HL)
Load register A with the MSB of the value in REG 1 at the location of the memory pointer in register pair HL.
09E3
RLCA
Move the value of the sign bit in register A into the CARRY FLAG.
09E4
SCF
Set the CARRY FLAG.
09E5
RRA
Turn off the sign bit in register A by moving the value of the CARRY FLAG into register A and moving the previous value of the sign bit from BIT 0 of register A into the CARRY FLAG.
09E6
LD (HL),A
Save the adjusted MSB in register A in REG 1 at the location of the memory pointer in register pair HL.
09E7
CCF
Invert the value of the sign bit in the CARRY FLAG.
09E8
RRA
Move the inverted sign bit from the CARRY FLAG into register A.
09E9
INC HL
Increment the value of the memory pointer in register pair HL.
09EA
INC HL
Increment the value of the memory pointer in register pair HL. This sets up for a temporary sign byte.
09EB
LD (HL),A
Save the value in register A (the complemented sign) at the location of the memory pointer in register pair HL.
09EC
LD A,C
Load register A with the MSB of the single precision value in register C (which is the high order number and the sign).
09ED
RLCA
Move the value of the sign bit in register A into the CARRY FLAG.
09EE
SCF
Set the CARRY FLAG.
09EF
RRA
Turn on the sign bit in register A by moving the value of the CARRY FLAG into register A and moving the previous value of the sign bit from BIT 0 of register A into the CARRY FLAG.
09F0
LD C,A
Load register C with the adjusted MSB in register A to save it.
09F1
RRA
Move the value of the sign bit from the CARRY FLAG back into register A.
09F2
XOR (HL)
Combine the value of the sign bit for the single precision value in register A with the value of the sign bit for the single precision value at the location of the memory pointer in register pair HL.
09F3
RET
Return.

09F4-09FB – LEVEL II BASIC MATH ROUTINE

  • This routine is used by the double-precision logic. It moves a number of bytes (the number depending on the value stored in the NTF) from the AACC into the ACC. ((REG 1)=(AACC)).
  • Move any type value from memory [(HL)] to FAC. Alters A,B,D,E,H,L
09F4-09F6
LD HL,4127H
Load register pair HL with the starting address of REG 2.

NOTE: 4127H-412EH holds REG 2 with 412EH being the exponent.
09F7-09F9
“MVSAHL”
LD DE,09D2H
Load register pair DE with the return address.
09FA-09FB
JUMP down a few instructions to 0A02H.

09FC-0A0B – LEVEL II BASIC MATH ROUTINE

  • This is the opposite of 9F4H. ((AACC)=(REG 1)).
  • Move any type value from FAC to memory [(HL)]. Alters A,B,D,E,H,L.
09FC-09FE
“MVALT”
LD HL,4127H
Load register pair HL with the starting address of REG 2.

NOTE: 4127H-412EH holds REG 2 with 412EH being the exponent.
09FF-0A01
LD DE,09D3H
Load register pair DE with the return address (which is the address of the move subroutine).
0A02
PUSH DE
Save the return address in register pair DE on the STACK.
0A03-0A05
LD DE,4121H
Load register pair HL with the starting address for a single precision value in REG 1.
0A06
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0A07
RET C
If that test is anything other than double precision, return out of this subroutine.
0A08-0A0A
LD DE,411DH
Load register pair DE with the starting address of REG 1.

NOTE: 411DH-4124H holds REG l.
0A0B
RET
Return (to the move routine).

0A0C-0A25 – SINGLE PRECISION COMPARE
“CPSP”

  • Single-precision compare. Compares REG 1 with the contents of BCDE registers. After execution of this routine, the A register will contain: A=0 if REG 1=BCDE, A=1 if ACC>BCDE or A=FFH if ACC<BCDE.
  • NOTE: To use a ROM call to compare two single precision numbers, store the first input in registers BCDE, the second input in 4121H-4124H and then CALL 0A0CH. If the numbers are equal, the Z (zero) flag will be set. If they are not equal, the Z flag will be turned off. If the first input number is the smaller, the S (sign) and C (carry) flags will also be turned off. If the second input number is the smaller, the S and C flags will both be set.
0A0C
LD A,B
First we need to check to see if A is 0, so load register A with the value of the exponent in register B.
0A0D
OR A
Set the flags.
0A0E-0A10
JUMP to 0955H if the exponent in register A is equal to zero.
0A11-0A13
LD HL,095EH
The exponent in register A is NOT equal to zero, so load register pair HL with a return address to “FCOMPS”.
0A14
PUSH HL
Save the return address in register pair HL on the STACK.
0A15-0A17
GOSUB to 0955H to check the sign of the single precision numbers.
0A18
LD A,C
Load register A with the MSB of the single precision value in register C.
0A19
RET Z
Return if the signs of the single precision values aren’t equal.
0A10-0A1C
LD HL,4123H
Load register pair HL with the address of the MSB in register A.
0A1D
XOR (HL)
Test to see if the signs are different. Combine the MSB in REG 1 at the location of the memory pointer in register pair HL with the MSB in register A.
0A1E
LD A,C
Load register A with the MSB in register C.
0A1F
RET M
Return if the MSBs don’t match.
0A20-0A22
Go compare the single precision values.
0A23
RRA
Move the value of the CARRY FLAG from the comparison into register A.
0A24
XOR C
Combine the value of the MSB of the single precision value in register C with the value in register A.
0A25
RET
Return.

0A26-0A38 – SINGLE PRECISION COMPARISON ROUTINE

0A26
INC HL
Increment the value of the memory pointer in register pair HL so that it points to the exponent in REG 1.
0A27
LD A,B
Load register A with the value of the exponent for the single precision value in register B.
0A28
CP (HL)
Check to see if the exponent for the single precision value in REG 1 at the location of the memory pointer in register pair HL is the same as the value of the exponent for the single precision value in register A.
0A29
RET NZ
Return if the value of the exponent in REG 1 isn’t the same as the value of the exponent in register A.
0A2A
DEC HL
Decrement the value of the memory pointer in register pair HL to point to the MSB.
0A2B
LD A,C
Load register A with the MSB for the single precision value in register C.
0A2C
CP (HL)
Check to see if the MSB for the single precision value in REG 1 at the location of the memory pointer in register pair HL is the same as the value of the MSB for the single precision value in register A.
0A2D
RET NZ
Return if the value of the MSB in REG 1 isn’t the same as the value of the MSB in register A.
0A2E
DEC HL
Decrement the value of the memory pointer in register pair HL.
0A2F
LD A,D
Load register A with the NMSB of the single precision value in register D.
0A30
CP (HL)
Check to see if the NMSB for the single precision value in REG 1 at the location of the memory pointer in register pair HL is the same as the value of the NMSB for the single precision value in register A.
0A31
RET NZ
Return if the value of the NMSB in REG 1 isn’t the same as the value of the NMSB in register A.
0A32
DEC HL
Decrement the value of the memory pointer in register pair HL.
0A33
LD A,E
Load register A with the LSB of the single precision value in register E.
0A34
SUB (HL)
Check to see if the LSB for the single precision value in REG 1 at the location of the memory pointer in register pair HL is the same as the value of the LSB for the single precision value in register A.
0A35
RET NZ
Return if the value of the LSB in REG 1 isn’t the same as the value of the LSB in register A.
0A36
POP HL
Get the value from the STACK and put it in register pair HL.
0A37
POP HL
Get the value from the STACK and put it in register pair HL.
0A3B
RET
Return.

0A39-0A48 – INTEGER COMPARE

  • Integer compare. Compares HL with DE. After execution, A=0 if HL=DE, A=1 if HL>DE or A=FFH if HL<DE. The S and Z flags are valid.
  • NOTE: To use a ROM call to compare two integers, store the first input in DE, the second in HL and then CALL 0A39H. If the numbers are equal, the Z (zero) flag will be set. If they are not equal, the Z flag will be turned off. If the first input number is the smaller, the S (sign) and C (carry) flags will also be turned off. If the second input number is the smaller, the S and C flags will both be set.
0A39
LD A,D
Load register A with the MSB of the integer value in register D.
0A3A
XOR H
Check to see if the sign bit for the MSB of the integer value in register H is the same as the sign bit for the MSB for the integer value in register A.
0A3B
LD A,H
If the signs are not the same, then the answer is the sign of HL so load register A with the MSB of the integer value in register H.
0A3C-0A3E
If M is set, then the above test created a NEGATIVE number, meaning that the sign bits for the integer values aren’t equal. So JUMP to 095FH.
0A3F
CP D
Check to see if the MSB for the integer value in register D is the same as the MSB for the integer value in register A.
0A40-0A42
JUMP to 0960H if the MSB for the integer value in register D isn’t the same as the MSB for the integer value in register A.
0A33
LD A,L
Load register A with the LSB of the integer value in register L.
0A44
SUB E
Check to see if the LSB for the integer value in register E is the same as the LSB for the integer value in register A.
0A45-0A47
JUMP if the LSB for the integer value in register E isn’t the same as the LSB for the integer value in register A.
0A48
RET
Return.

0A49-0A77 – DOUBLE PRECISION COMPARE

  • Double-precision compare. Compares REG 1 with the AACC. After execution the A register will contain: A=0 if REG 1=AACC, A=1 if ACC > AACC or A=FFH if ACC < AACC. S and Z flags are valid.
0A49-0A4B
LD HL,4127H
Load register pair HL with the starting address of REG 2.

NOTE: 4127H-412EH holds REG 2 with 412EH being the exponent.
0A4C-0A4E
GOSUB to 09D3H to move the double precision value pointed to by register pair DE to REG 2.
0A4F-0A51
LD DE,412EH
Load register pair DE with the address of the exponent in REG 2.
0A52
LD A,(DE)
Load register A with the exponent for the double precision value in REG 2 at the location of the memory pointer in register pair DE.
0A53
OR A
Check to see if the double precision value in REG 2 is equal to zero.
0A54-0A56
JUMP if the double precision value in REG 2 is equal to zero.
0A57-0A59
LD HL,095EH
Load register pair HL with the return address.
0A5A
PUSH HL
Save the return address in register pair HL on the STACK.
0A5B-0A5D
GOSUB to 0955H to check to see if the double precision value in REG 1 is equal to zero.
0A5E
DEC DE
Decrement the value of the memory pointer in register pair DE to point to the sign.
0A5F
LD A,(DE)
Load register A with the MSB of the double precision value in REG 2 at the location of the memory pointer in register pair DE.
0A60
LD C,A
Load register C with the MSB of the double precision value in REG 2 in register A.
0A61
RET Z
Return if the double precision value in REG 1 is equal to zero.
0A62-0A64
LD HL,4123H
Load register pair HL with the address of the MSB of the double precision value in REG 1.
0A65
XOR (HL)
Check to see if the sign bit for the MSB of the double precision value in REG 1 at the location of the memory pointer in register pair HL is the same as the sign bit for the MSB of the double precision value in REG 2 in register A.
0A66
LD A,C
Load register A with the MSB of the double precision value in REG 2 in register C.
0A67
RET M
Return if the sign bits for the double precision values in REG 1 and REG 2 aren’t the same.
0A68
INC DE
Increment the value of the memory pointer in register pair DE to point back to the exponent of REG 2.
0A69
INC HL
Increment the value of the memory pointer in register pair HL to point back to the exponent of REG 1.
0A6AH-OA6B
LD B,08H
Load register B with 8 (i.e., the number of bytes to be compared).
0A6C
LD A,(DE)
Load register A with the value at the location of the memory pointer in register pair DE.
0A6D
SUB (HL)
Check to see if the value in register A is the same as the value at the location of the memory pointer in register pair HL.
0A6E-0A70
JUMP back to 0A23H if the value in register A isn’t the same as the value at the location of the memory pointer in register pair HL.
0A71
DEC DE
Decrement the value of the memory pointer in register pair DE.
0A72
DEC HL
Decrement the value of the memory pointer in register pair HL.
0A73
DEC B
Decrement the number of bytes remaining to be compared in register B.
0A74-0A75
Loop until all of the bytes have been compared.
0A76
POP BC
Get the value from the STACK and put it in register pair BC.
0A77
RET
Return.

0A78-0A7E – DOUBLE PRECISION COMPARE
“CPDP”

  • Double-precision compare. This compare is the opposite of the A4FH compare. It compares the AACC with the ACC. (Remember that a compare is actually a subtraction that is never executed therefore a compare can be done in two ways with the same values. (A-B and B-A)). The results are the same as the A4FH routine.
  • NOTE: To use a ROM call to compare two double precision number, store the first input in 411DH-4124H, and store the second input in 4127H-412EH and then CALL 0A78H. If the numbers are equal, the Z (zero) flag will be set. If they are not equal, the Z flag will be turned off. If the first input number is the smaller, the S (sign) and C (carry) flags will also be turned off. If the second input number is the smaller, the S and C flags will both be set.
0A78-0A7A
Go compare the double precision value in REG 2 to the double precision value in REG 1.
0A7B-0A7D
JUMP if the double precision value in REG 1 and the double precision value in REG 2 aren’t the same.
0A7E
RET
Return.

0A7F-0AB0 – LEVEL II BASIC CINT ROUTINE

  • CINT routine. Takes a value from ACC, converts it to an integer value and puts it back into the ACC. On completion, the HL register pair contains the LSB of the integer value, and the NTF contains 2 (Integer=2). If NTF=3 (string) a TM ERROR will be generated and control will be passed to BASIC.
0A7F
“CINT”
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0A80-0A82
LD HL,(4121H)
Load register pair HL with the integer value in REG 1
0A83
RET M
If that test showed we have an INTEGER, then return out of this subroutine.
0A84-0A86
If that test showed we have a STRING, Display a ?TM ERROR message.
0A87-0A89
If that test shows we have DOUBLE PRECISION, call 0AB9H to convert the number to single precision.
  • NOTE: To use a ROM call to call the CINT routine, store the single precision input variable in 4121H-4124H and then call to 0A8AH and bypass all the foregoing. After the call, the integer result would be in 4121H-4122H and in the HL register pair. Too big a number will generate a ?OV Error.
0A8A-0A8C
LD HL,07B2H
Load register pair HL with the return address.
0A8D
PUSH HL
Save the return address in register pair HL on the STACK.
0A8E-0A90
LD A,(4124H)
Load register A with the exponent for the single precision value in REG 1.
0A91-0A92
CP 90H
Check to see if the exponent for the single precision value in REG 1 in register A indicates more than 16 bits of precision.
0A93-0A94
JUMP to 0AA3H if the exponent for the single precision value in REG 1 in register A indicates more than 16 bits of precision.
0A95-0A97
Its not too large, so GOSUB to 0AFBH to convert the single precision value in REG 1 to an integer and return with the integer value in register pair DE.
0A98
EX DE,HL
Swap DE and HL.
0A99
POP DE
Get the error address from the STACK and put it in register pair DE.
0A9A-0A9C
“ISTOR”
LD (4121H),HL
Save the integer value in register pair HL as the current value in REG 1.

This is the routine that returns the value in the HL register pair to the BASIC program that called it. In effect it moves the content of HL into REG 1 (ACC = HL).
0A9D-0A9E
“FLAGIN”
LD A,02H
Load register A with an integer number type flag (which is a 2).
0A9F-0AA1
LD (40AFH),A
Save the integer number type flag in register A as the current value of the number type flag.

Note: 40AFH holds the current number’s type flag as follows:
  • 2: Integer
  • 3: String
  • 4: Single precision
  • 8: Double precision
0AA2
RET
Return.
0AA3-0AA5
LD BC,9080H
Load register pair BC with the exponent and the MSB of a single precision value (i.e., -32768).
0AA6-0AA8
LD DE,0000H
Load register pair DE with the NMSB and the LSB of a single precision value. Register pairs BC and DE now hold a single precision value equal to -32768.
0AA9-0AAB
Compare them by GOSUB to the SINGLE PRECISION COMPARISON routine at 0A0CH.

NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:
  • A=0 if REG 1 = BCDE
  • A=1 if REG 1>BCDE; and
  • A=FFH if REG 1<BCDE.
0AAC
RET NZ
Display an ?OV ERROR if the value in REG 1 isn’t equal to -32768.
0AAD
LD H,C
Put -32768 into HL by first loading register H with the MSB of the single precision value in register C.
0AAE
LD L,D
and then loading register L with the NMSB of the single precision value in register D.
0AAF-0AB0
JUMP to 0A99H to store it in REG 1 and set the variable type flag.

0AB1-0ACB – LEVEL II BASIC CSNG ROUTINE
“CSASP”

  • CSNG routine. Takes value from ACC and converts it to single-precision. The result is put in ACC and NTF contains 4.
0AB1
“CSNG”
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0AB2
RET PO
If that test shows we have SINGLE PRECISION, return out of this subroutine.
0AB3-0AB5
If that test shows we have an INTEGER, jump to 0ACCH.
0AB6-0AB8
If that test shows we have a STRING, display a ?TM ERROR .
0AB9-0ABB
At this point, we have a DOUBLE PRECISION number, so call 09BF which loads the SINGLE PRECISION value in REG 1 (which is currently the most significant four bytes of the double precision value in REG 1) into register pair BC/DE.
0ABC-0ABE
Go set the current number type flag to single precision.
0ABF
LD A,B
Load register A with the exponent of the double precision value in register B.
0AC0
OR A
Check to see if the double precision value in REG 1 is equal to zero.
0AC1
RET Z
Return if the double precision value in REG 1 is equal to zero.
0AC2-0AC4
GOSUB to 09DFH to unpack the number … turn on the most significant bit of the single precision value in REG 1.
0AC5-0AC7
LD HL,4120H
Load register pair HL with the address of the most significant byte chopped off the double precision value.
0AC8
LD B,(HL)
Loaded register B with the most significant byte chopped off the double precision value at the location of the memory pointer in register pair HL.
0AC9-0ACB
JUMP to 0796H to round the double number up.

0ACC-0ADA – LEVEL II BASIC MATH ROUTINE
“CHGIS”

  • Convert Integer to Single Precision. Alters: A,B,C,D,E,H,L.
  • Note: If you wanted to convert integer to single precision via a ROM call, you would store the integer input variable in 4121H-4122H and then call to 0ACCH. The result (as a single precision number) will be in 4121H-4124H.
0ACC-0ACE
LD HL,(4121H)
Load register pair HL with the integer value at the location of an integer storage in REG 1.
0ACF-0AD1
GOSUB to 0AEF to set the current number type flag to single precision.
0AD2
LD A,H
Now we need to prepare the registers for the routine at 0969H … Load register A with the MSB of the integer value in register H.
0AD3
LD D,L
Load register D with the LSB of the integer value in register L.
0AD4-0AD5
LD E,00H
Zero register E.
0AD6-0AD7
LD B,90H
Load register B with 90H (Decimal: 144) as the initial maximum exponent.
0AD8-0ADA
JUMP to 0969H.

0ADB-0AED – LEVEL II BASIC CDBL ROUTINE
“CSADP”

  • CDBL routine. Takes a value from ACC and converts it to double-precision. The result will be in ACC and NTF will be 8.
0ADB
“CDBL”
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0ADC
RET NC
If that test shows we have a DOUBLE PRECISION number, return out of the subroutine.
0ADD-0ADF
If that test shows we have a STRING, Display a TM ERROR message.
0AE0-0AE2
If that test shows we have an INTEGER, then GOSUB to 0ACCH to convert it to SINGLE PRECISION..
0AE3-0AE5
LD HL,0000H
So now we know we have a SINGLE PRECISION value. Load register pair HL with zero.
0AE6-0AE8
LD (411DH),HL
Clear the next 4 bytes … Save the value in register pair HL as the first and second bytes of REG 1.

NOTE: 411DH-4124H holds REG l.
0AE9-0AEB
LD (411FH),HL
and save the value in register pair HL as the third and fourth bytes of REG 1.
0AEC-0AED
“FLAGDP”
LD A,08H
Load register A with a double precision number type flag.

0AEE-0AF3 – LEVEL II BASIC MATH ROUTINE

0AEE
01
Z-80 Trick – See the note at 0134H for an explanation.
0AEF-0AF0
“FLAGSP”
LD A,04H
Load register A with a single precision number type flag (of 4).
0AF1-0AF3
JUMP away to 0A9FH to save the value in register A as the current number type flag.

0AF4-0AFA – LEVEL II BASIC MATH ROUTINE – Force REG1 to be a STRING

  • This routine calls 20H (RST 20H) and returns if NTF=3 (string) else if NTF is not 3 then it generates a TM ERROR. BC, DE, and HL are saved.
0AF4
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0AF5
RET Z
If that test shows we have a STRING, return out of the subroutine.
0AF6-0AF7
LD E,18H
Load register E with a TM ERROR code.

This is the entry point for the TM ERROR.
0AF8-0AFA
Display a TM ERROR message if the current value in REG 1 isn’t a string.

0AFB-0B1E – LEVEL II BASIC MATH ROUTINE

  • This routine will reset the BC and DE register pairs if the A register contains 0. (XOR A before calling this routine).
  • Greatest integer function. Leaves INT(REG1) in C,D,E (signed). Assumes REG1 < 2^23 = 8388608. Assumes the exponent of REG1 is in A. Alters A,B,C,D,E
0AFB
LD B,A
Load register B with the exponent of the single precision number in register A.
0AFC
LD C,A
Load register C with the exponent of the single precision number in register A.
0AFD
LD D,A
Load register D with the exponent of the single precision number in register A.
0AFE
LD E,A
Load register E with the exponent of the single precision number in register A.
0AFF
OR A
Check to see if the single precision number in REG 1 is equal to zero.
0B00
RET Z
Return if the single precision value in REG 1 is equal to zero.

The hard case is QINT is negative non-integers. To handle this if the number is negative, we regard the 3-byte mantissa as a 3 byte integer and subtract one. Then all the fractional bits are shifted out by shifting the mantissa right. Then, if the number was negative, we add one. So if we had a negative integer, all the bits to the right of the binary point were zero. So the net effect is we have the original number in C,D,E. If the number was a negative non-integer, there is at least one non-zero bit to the right of the binary point. So the net effect is that we get the absolute value of INT(REG1) in C,D,E. C,D,E is then negated if the original number was negative so the result will be signed.

0B01
PUSH HL
Save the value in register pair HL on the STACK.
0B02-0B04
GOSUB to 09BFH which loads the SINGLE PRECISION value in REG 1 into register pair BC/DE.
0B05-0B07
GOSUB to 09DFH to to turn on the sign bit of the single precision value in register pairs BC and DE.
0B08
XOR (HL)
Set the sign bit according to the sign of the value at the location of the memory pointer in register pair HL.
0B09
LD H,A
Load register H with the value of the sign in register A.
0B0A-0B0C
Go decrement the single precision value in register pairs BC and DE if the sign of the value is negative.
0B0D-0B0E
LD A,98H
Load register A with the maximum exponent of 98H (Decimal: 152).
0B0F
SUB B
Figure the number of bits to be shifted by subtracting the exponent in register B from the exponent in register A.
0B10-0B12
GOSUB to 07D7H to shift the single precision value in register pairs BC and DE (to get rid of the fractional bits).
0B13
LD A,H
Load register A with the value of the sign in register H.
0B14
RLA
Put the sign bit into the CARRY FLAG so it won’t be changed.
0B15-0B17
Go bump the value in register pairs BC and DE if the original number was negative.
0B18-0B19
LD B,00H
Load register B with zero to forget the bits which were shifted out.
0B1A-0B1C
Go make the integer negative if the original number was negative because we want a signed mantissa. Return with the integer value in register pair DE.
0B1D
POP HL
Get the old HL value from the STACK and put it in register pair HL.
0B1E
RET
Return.

0BlF-0B25 – LEVEL II BASIC MATH ROUTINE

0B1F
DEC DE
Decrement the NMSB and the LSB of the single precision value in register pair DE.
0B20
LD A,D
Load register A with the value of the NMSB for the single precision value in register D.
0B21
AND E
Combine the LSB of the single precision value in register E with the NMSB of the single precision value in register A.
0B22
INC A
Increment the combined value in register A.
0B23
RET NZ
Return if the NMSB and the LSB of the single precision value in register pair DE isn’t equal to FFFFH.
0B24
DEC BC
Decrement the value of the exponent and the MSB of the single precision value in register pair BC.
0B25
RET
Return.

0B26-0B58 – LEVEL II BASIC FIX ROUTINE
“FIX”

  • FIX routine. Takes a value from ACC and converts it to an integer value. The result will be in ACC. NTF will be 2 if value is smaller than 32767 else it will be 4. An error will be generated if NTF=3 (string).
    A call to 0B26H unconditionally truncates the fractional part of a floating point number in REG 1. The result is stored in WRAl and the type flag is set to integer.
  • Note: If you wanted to call the FIX routine via a ROM call, you would store the single-precision input variable in 4121H-4124H, then put a 4 into 40AFH to flag as single precision, and then call to 0B26H. If the result can be an integer, it will be in 4121H-4122H and in the HL register pair. If single precision, the result will be in 4121H-4124H. If double precision, in 411DH-4124H. In all cases 40AFH will have the data mode flag as 2, 4, or 8, accordingly.
  • The routine is FIX(X)=SGN(X)*INT(ABS(X))
0B26
“FIX”
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0B27
RET M
If that test shows we have an INTEGER, return out of the subroutine.
0B28-0B2A
GOSUB to 0955H to check the sign of the current value in REG 1.
0B2B-0B2D
If the current value in REG 1 is positive, jump to the RETURN INTEGER (INT[N]) routine at 0B37H (which 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 REG 1. The mode flag is updated.).
0B2E-0B30
GOSUB to 0982H to convert the current value in REG 1 to positive.
0B31-0B33
Now that REG 1 is positive, call the RETURN INTEGER (INT[N]) routine at 0B37H (which 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 REG 1. The mode flag is updated.).
0B34-0B36
JUMP back to 097BH (which is in the middle of the ABS(x) routine.

0B37 – LEVEL II BASIC INT( ROUTINE

A call to 0B37H 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 REG 1. The mode flag is updated.

0B37
“INT”
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0B38
RET M
If that test shows we have an INTEGER, return out of this subroutine.
0B39-0B3A
JUMP if the current value in REG 1 is double precision.
0B3B-0B3C
Display a ?TM ERROR if the current value in REG 1 isa string.

Note: If you wanted to call the INT routine via a ROM call, you would store the single precision input variable in 4121H-4124H, put a 4 into 40AFH (to flag as single precision), and then call 0B3DH and bypass all the foregoing. After the call, the integer result would be in 4121H-4122H and in the HL register pair IF the absolute value of the input did not exceed 32767. Otherwise it will be in 4121H-4124H in single precision format, and 40AF will be a 2 for integer or 4 for single precision..

0B3D-0B3F
Go convert the single precision value in REG 1 to an integer.
0B40-0B42
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1.
0B43
LD A,(HL)
Load register A with the value of the exponent in REG 1 at the location of the memory pointer in register pair HL.
0B44-0B45
CP 98H
Check to see if there is more than 24 bits of precision used by the current value in REG 1.
0B46-0B48
LD A,(4121H)
Load register A with the LSB of the single precision number in REG 1.
0B49
RET NC
Return if more than 24 bits of precision is used by the single precision value in REG 1.
0B4A
LD A,(HL)
Load register A with the exponent of the single precision number in REG 1.
0B4B-0B4D
GOSUB to 0AFBH to convert the single precision number in REG 1 to an integer.
0B4E-0B4F
LD (HL),98H
Save an exponent in REG 1.
0B50
LD A,E
Load register A with the LSB of the integer value in register E.
0B51
PUSH AF
Save the LSB of the integer value in register A on the STACK.
0B52
LD A,C
Load register A with the value in register C.
0B53
RLA
Move the sign bit in register A into the CARRY FLAG.
0B54-0B56
Go make the number in REG 1 single precision.
0B57
POP AF
Get the LSB of the single precision value from the STACK and put it in register A.
0B58
RET
Return.

0B59-0B9D – LEVEL II BASIC MATH ROUTINE

0B59-0B5B
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1.
0B5C
LD A,(HL)
Load register A with the value of the exponent for the double precision number in REG 1 at the location of the memory pointer in register pair HL.
0B5D-0B5E
CP 90H
Check to see if the double precision number in REG 1 uses more or less than 16 bits of precision by checking A against 90H. This has the effect of checking A-90H, so if A < 90H (16 Bits of Precision) then the CARRY will be set and if A >= 90H (16 Bits of Precision) then the NO CARRY will be set.
0B5F-0B61
If the double precision value in REG 1 uses less than 16 bits of precision, jump to the CONVERT TO INTEGER routine at 0A7F (where the contents of REG 1 are converted from single or double precision to integer and stored in HL).
0B62-0B63
JUMP forward to 0B78H if the double precision number in REG 1 uses more than 16 bits of precision.
0B64
LD C,A
Load register C with the exponent for the double precision number in register A.
0B65
DEC HL
Decrement the value of the memory pointer in register pair HL.
0B66
LD A,(HL)
Load register A with the MSB of the double precision value in REG 1 at the location of the memory pointer in register pair HL.
0B67-0B68
XOR 80H
Complement the value of the sign bit in register A (which is 1000 0000).
0B69-0B6A
LD B,06H
Load register B with the number of bytes to be checked.
0B6B
DEC HL
Decrement the value of the memory pointer in register pair HL.
0B6C
OR (HL)
Combine the value at the location of the memory pointer in register HL with the value in register A.
0B6D
DEC B
Decrement the byte counter in register B.
0B6E-0B6F
Loop until all of the bytes have been checked.
0B70
OR A
Check to see if the double precision value in REG 1 is equal to a -32768.
0B71-0B73
LD HL,8000H
Load register pair HL with a negative zero.
0B74-0B76
JUMP back to 0A9AH if the double precision value in REG 1 is a -32768.
0B77
LD A,C
Load register A with the exponent for the double precision value in register C.
0B78-0B79
CP B8H
Check to see if more than 56 bits of precision has been used for the double precision value in REG 1.
0B7A
RET NC
Return if more than 56 bits of precision have been used for the double precision value in REG 1.
0B7B
PUSH AF
Save the exponent in register A on the STACK.
0B7C-0B7E
GOSUB to 09BF which loads most significant four bytes of the double precision value in REG 1 into register pair BC/DE.
0B7F-0B81
GOSUB to 09DFH to turn on the sign bit and return with the value of the sign.
0B82
XOR (HL)
Set the sign bit by combining the value at the location of the memory pointer in register pair HL with the result of the sign test in register A.
0B83
DEC HL
Decrement the value of the memory pointer in register pair HL.
0B84-0B85
LD (HL),B8H
Save an exponent at the location of the memory pointer in register HL.
0B86
PUSH AF
Save the value of the sign test in register A on the STACK.
0B87-0B89
GOSUB to 0BA0H to adjust the number in REG 1 if it’s negative.
0B8A-0B8C
LD HL,4123H
Load register pair HL with the address of the MSB in REG 1.
0B8D-0B8E
LD A,B8H
Load register A with the maximum value of an exponent.
0B8F
SUB B
Subtract the value of the exponent at the location of the memory pointer in register pair HL from the value in register A.
0B90-0B92
Go adjust the value in REG 1.
0B93
POP AF
Get the value of the sign test from the STACK and put it in register A.
0B94-0B96
If REG 1 is negative, then COSUB to 0D20H to adjust the value.
0B97
XOR A
Zero register A.
0B98-0B9A
LD (411CH),A
Zero memory location 411CH.

NOTE: 411CH is used by floating point routines.
0B9B
POP AF
Get the value of the original exponent test from the STACK and put it in register pair AF.
0B9C
RET NC
Return if more than 56 bits are used by the double precision number.
0B9D-0B9F
JUMP to 0CD8H.

0BA0-0BA9 – LEVEL II BASIC MATH ROUTINE

0BA0-0BA2
LD HL,411DH
Load register pair HL with the starting address of REG 1.

NOTE: 411DH-4124H holds REG l.
0BA3
LD A,(HL)
Load register A with the value at the location of the memory pointer in register pair HL.
0BA4
DEC (HL)
Decrement the value at the location of the memory pointer in register pair HL.
0BA5
OR A
Check to see if the value in register A is equal to zero.
0BA6
INC HL
Increment the value of the memory pointer in register pair HL.
0BA7-0BA8
Loop until the value at the location of the memory pointer in register pair HL is equal to a nonzero value.
0BA9
RET
Return.

0BAA-0BC6 – LEVEL II BASIC MATH ROUTINE – Integer Multiply for Multiply Dimensioned Arrays. DF = BC * DE. Overflow will cause a BS ERROR. Alters A, B, C, D, and E

0BAA
PUSH HL
Save the value in register pair HL on the STACK.
0BAB-0BAD
LD HL,0000H
Load register pair HL with zero to zero the product registers.
0BAE-0BAF
LD A,B
OR C
Test for BC=0. The easiest way to test a 2 byte register for zero is to load the MSB into A and then OR it with the LSB. If the MSB was 0 and the LSB was 0, then A will be 0.
0BB0-0BB1
JUMP to 0BC4H if BC = 0 (which is really just for speed).
0BB2-0BB3
LD A,10H
Load register A with the counter value (which is 16).
0BB4
ADD HL,HL
HL = HL + HL. This will set the CARRY flag if it overflows.
0BB5-0BB7
Display a ?BS ERROR message if the result in register pair HL has overflowed.
0BB8
EX DE,HL
We need to do a DE = DE + DE, but that doesn’t exist, so we need to use HL. First, exchange the integer value in register pair DE with the result in register pair HL.
0BB9
ADD HL,HL
… then HL = HL + HL.
0BBA
EX DE,HL
… then exchange the result in register pair DE with the integer value in register pair HL.
0BBB-0BBC
JUMP to 0BC1H if the most significant bit in the integer value in register DE wasn’t set.
0BBD
ADD HL,BC
Add the integer value in register pair BC to the result in register pair HL.
0BBE-0BC0
Display a BS ERROR message if the result in register pair HL has overflowed.
0BC1
DEC A
Decrement the counter in register A.
0BC2-0BCJ
Loop until the multiplication has been completed.
0BC4
EX DE,HL
Load register pair DE with the result in register pair HL.
0BC5
POP HL
Get the value from the STACK and put it in register pair HL.
0BC6
RET
Return.

0BC7-0BD1 – INTEGER SUBTRACTION
“SUBINT”

  • Integer subtract. (REG 1=DE-HL) The result is returned in both REG 1 and the HL register pair.
    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 REG 1 and the mode flag is updated accordingly.
  • Note: If you wanted to subtract 2 integers via a ROM call, store one into DE and the subtrahend in HL (i.e., to do 26-17, DE gets 26), and then call 0BC7H. The integer result will be stored in 4121H-4122H approximately 210 microseconds later, and 40AFH will be set to 2 (to flag it as an integer). If there is an overflow, it will be converted to single precision (with 40AFH being a 4 in that case) and will be stored in 4121H-4124H.
  • (HL):=(DE)-(HL). Alters: A,B,C,D,E,H,L
0BC7
“ISUB”
LD A,H
Load register A with the MSB of the integer value in register H.
0BC8
RLA
Put the value of the sign bit into the CARRY FLAG.
0BC9
SBC A,A
Adjust register A according to the value of the sign bit.
0BCA
LD B,A
Load register B with the result of the sign test.
0BCB-0BCD
GOSUB to 0C51H to complement the value in register pair HL.
0BCE
LD A,C
Load register A with zero.
0BCF
SBC A,B
Adjust the value of the sign test.
0BD0-0BD1
JUMP to 0BD5H.

0BD2-0BF1 – INTEGER ADDITION
“ADDINT”

  • Integer addition (REG 1=DE+HL). After execution NTF=2, or 4 if overflow has occurred, in which case the result in REG 1 will be single-precision. The result is returned in both REG 1 and the HL register pair.
    Adds the integer value in DE to the integer in HL. The sum is left in HL and the orginal 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 Reg 1 and the mode flag would be updated.
  • Note: If you wanted to add 2 integers via a ROM call, store one input into DE and the other into HL, and then call 0BD2H. The result will be in 4121H-4122H and in HL, with a 2 in 40AFH, and will take about 130 microseconds. If there is an overflow, the result will be converted to Single Precision and put into 4121H-4124H (with a 4 in 40AFH).
  • (HL):=(DE)+(HL). Alters: A,B,C,D,E,H,L
0BD2
LD A,H
Load register A with the MSB of the integer value in register pair HL.
0BD3
RLA
Put the value of the sign bit into the CARRY FLAG.
0BD4
SBC A,A
Adjust register A according to the value of the sign bit.
0BD5
LD B,A
Load register B with the result of the sign test to save the sign.
0BD6
PUSH HL
Save the integer value in register pair HL on the STACK.
0BD7
LD A,D
Load register A with the MSB of the integer value in register pair DE.
0BD8
RLA
Put the value of the sign bit into the CARRY FLAG.
0BD9
SBC A,A
Adjust register A according to the value of the sign bit.
0BDA
ADD HL,DE
Add the integer value in register pair DE to the integer value in register pair HL.
0BDB
ADC A,B
Add the CARRY FLAG and the value from the sign test for the integer value in register pair HL in register B to the value of the sign test for the integer value in register pair DE in register A.
0BDC
RRCA
This instruction and the next basically test to see if the LSB of A is different from the MSB of H, in which cas an overflow will occur. So first, put the value of the CARRY FLAG in register A.
0BDD
XOR H
Then combine the value of the sign bit for the result in register H with the value in register A.
0BDE-0BE0
JUMP unless overflow has occurred.
0BE1
PUSH BC
Save the value of the sign test in register B on the STACK.
0BE2
EX DE,HL
Load register pair HL with the integer value in register pair DE.
0BE3-0BE5
Go convert the register value in register pair HL to single precision and return with the result in REG 1.
0BE6
POP AF
Get the value of the sign test from the STACK and put it in register A.
0BE7
POP HL
Get the integer value from the STACK and put it in register pair HL.
0BE8-0BEA
Call 09A4 which moves the SINGLE PRECISION value in REG 1 to the STACK (stored in LSB/MSB/Exponent order).
0BEB
EX DE,HL
Load register pair DE with the integer value in register pair HL.
0BEC-0BEE
Go convert the integer value in register pair DE to single precision and return with the result in REG 1.
0BEF-0BF1
Go perform single precision addition.

0BF2-0ClE – INTEGER MULTIPLICATION
“MLTINT”

  • Integer multiply. (REG 1=DE*HL). 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 REG 1.
  • Note: If you wanted to multiply two integers, store one input in DE, the other in HL CALL 0BF2H. The result is in 4121H-4122H and in HL, with a 2 in 40AFH (but in an overflow the result is converted to single precision format and stored in 4121H-4124H, with a 4 in 40AFH. Process takes approximately 900 microseconds.
  • Alters A,B,C,D,E,H,L
0BF2,0BF3
“IMUL”
LD A,H
OR L
We need to check if HL is zero, so first load register A with the MSB of the integer value in register H and then combine the LSB of the integer value in register L with the MSB of the integer value in register A.
0BF4-0BF6
JUMP if the integer value in register pair HL is equal to zero.
0BF7
PUSH HL
Save the integer value in register pair HL on the STACK.
0BF8
PUSH DE
Save the integer value in register pair DE on the STACK.
0BF9-0BFB
Go convert any negative integer values to positive and return with register B set according to the value of the sign bits.
0BFC
PUSH BC
Save the value of the sign bit test in register B on the STACK.
0BFD
LD B,H
Load register B with the MSB of the integer value in register H.
0BFE
LD C,L
Load register C with the LSB of the integer value in register L.
0BFF-0C01
LD HL,0000H
The product is going to go into HL so load register pair HL with zero.
0C02-0C03
LD A,10H
Load register A with the counter value (which is 16).
0C04
ADD HL,HL
Multiply the result in register pair HL by two.
0C05-0C06
JUMP to 0C26H if the result in register pair HL has overflowed.
0C07
EX DE,HL
We need to multiply the result in register pair DE by two, but there’s no command for that, so we need to have HL do it. First, exchange the integer value in register pair DE with the integer result in register pair HL.
0C08
ADD HL,HL
… then multiply the integer value in register pair HL by two.
0C09
EX DE,HL
… then exchange the integer result in register pair DE with the integer value in register pair HL.
0C0A-0C0B
JUMP to 0C10H if the most significant bit of the integer register pair DE wasn’t set.
0C0C
ADD HL,BC
Add the integer value in register pair BC to the integer result in register pair HL.
0C0D-0C0F
JUMP to 0C26H if the result in register pair HL has overflowed.
0C10
DEC A
Decrement the value of the counter in register A.
0C11-0C12
Loop until the multiplication has been completed.
0C13
POP BC
Get the value of the sign test from the STACK and put it in register B.
0C14
POP DE
Get the integer value from the STACK and put it in register pair DE.

This is an entry point from IDIV and is to test to see if the rsult is greater than 32767.

0C15
LD A,H
Load register A with the MSB of the result in register H.
0C16
OR A
Check to see if the sign bit in the MSB of the integer result in register A is set.
0C17-0C19
JUMP to 0C1FH if the integer result in register pair HL is negative. This jump is to check for a special case of -32768.
0C1A
POP DE
Get the integer value from the STACK and put it in register pair DE.
0C1B
LD A,B
Load register A with the value of the sign test in register B.
0C1C-0C1E
JUMP to 0C4DH to negate the result, if necessary.

0ClF-0C34 – LEVEL II BASIC MATH ROUTINE

0C1F-0C20
XOR 80H
Clear the sign bit for the MSB of the integer value in register A which is 1000 0000. This is a way to check to specifically check for 32768.
0C21
OR L
Combine the value of the LSB for the integer value in register L with the adjusted MSB of the integer value in register A.
0C22-0C23
JUMP to 0C37H if the result is equal to zero (meaning it was 32768).
0C24
EX DE,HL
At this point, it was greater than 32768, so its an overflow situation. Load register pair HL with the integer value in register pair DE.
0C25-0C28
LD BC,E1C1H
Z-80 Trick – See the note at 0134H for an explanation.
0C26
POP BC
Get the value of the sign test from the STACK and put it in register B.
0C27
POP HL
Get the integer value from the STACK and put it in register pair HL.
0C28-0C2A
GOSUB to 0ACFH to convert the integer value in register pair HL to single precision and return with the result in REG 1.
0C2B
POP HL
Get the integer value from the STACK and put it in register pair HL.
0C2C-0C2E
GOSUB to 09A4H to move the SINGLE PRECISION value in REG 1 to the STACK (stored in LSB/MSB/Exponent order).
0C2F-0C31
GOSUB to 0ACFH to convert the integer value in register pair HL to single precision and return with the result in REG 1.
0C32
POP BC
Get the exponent and the MSB of the single precision value from the STACK and put it in register pair BC.
0C33
POP DE
Get the NMSB and the LSB of the single precision value from the STACK and put it in register pair DE.
0C34-0C36
JUMP to the SINGLE PRECISION MULTIPLY routine at 0847H (which multiplies the current value in REG 1 by the value in (BC/DE). The product is left in REG 1.

0C37-0C44 – LEVEL II BASIC MATH ROUTINE

0C37
LD A,B
Load register A with the result of the sign test in register B.
0C38
OR A
Check to see if the result is supposed to be negative.
0C39
POP BC
Get the value from the STACK and put it in register pair BC.
0C3A-0CJC
JUMP if the result is supposed to be negative.
0C3D
PUSH DE
Save the integer value in register pair DE on the STACK.
0C3E-0C40
Go convert the integer result in register pair HL to single precision and return with the result in REG 1.
0C41
POP DE
Get the integer value from the STACK and put it in register pair DE.
0C42-0C44
JUMP to 0982H.

0C45-0C5A – LEVEL II BASIC MATH ROUTINE

0C45
LD A,H
Load register A with the MSB of the integer value in register H.
0c46
XOR D
Combine the MSB of the integer value in register D with the MSB of the integer value in register A.
0C47
LD B,A
Save the result of the combined signs in register A into register B.
0C48-0C4A
GOSUB to 0C4CH to convert a negative integer value in register pair HL to positive.
0C4B
EX DE,HL
Exchange the integer value in register pair DE with the integer value in register pair HL.
0C4C
LD A,H
Load register A with the MSB of the integer value in register H.
0C4D
OR A
Check the value of the sign for the MSB of the integer value in register A.
0C4E-0C50
JUMP if the integer value in register pair HL is positive.
0C51
XOR A
Zero register A.
Negate HL routine. This routine changes the sign of the HL register pair and stores it in the ACC. (HL=REG 1=-HL) The result is returned in both the HL register pair and the ACC.
0C52
LD C,A
Load register C with the value in register A.
0C53
SUB L
Subtract the LSB of the integer value in register L from the value in register A.
0C54
LD L,A
Save the adjusted value in register A in register L.
0C55
LD A,C
Load register A with the value in register C.
0C56
SBC A,H
Subtract the MSB of the integer value in register H from the value in register A.
0C57
LD H,A
Save the adjusted value in register A into register H.
0C58-0C5A
JUMP to 0A9AH.

0C5B-0C6F – LEVEL II BASIC MATH ROUTINE – Integer Negation. Alters A,B,C,D,E,H,L.

0C5B-0C5D
LD HL,(4121H)
Load register pair HL with the integer value in REG 1.
0C5E-0C60
GOSUB to 0C51H to convert the integer value in register pair HL to positive if it’s negative.
0C61
LD A,H
Load register A with the MSB of the integer value in register H.
0C62-0C63
XOR 80H
XOR A with 80H (Binary: 1000 0000). This will invert the value of the sign bit in register A. It checks for 32768.
0C64
OR L
Combine the LSB of the integer value in register L with the adjusted MSB of the integer value in register A.
0C65
RET NZ
Return if the integer value in REG 1 isn’t equal to -32768.
0C66
EX DE,HL
Load register pair DE with the integer value in register pair HL.
0C67-0C69
Go set the number type flag to single precision.
0C6A
XOR A
Zero register A.
0C6B-0C6C
LD B,98H
Load register B with an exponent.
0C6D-0C6F
JUMP to 0969H.

0C70-0C76 – DOUBLE PRECISION SUBTRACTION
“SUBDP”

  • Double-precision subtraction (REG 1=ACC-AACC).
    Subtracts the double precision value in REG 2 from the value in REG 1. The difference is left in REG 1.
  • Note: If you wanted to subtract two double precision numbers, store the minuend in 411DH-4124H and the subtrahend in 4127H-412EH, and CALL 0C70H. The result (in double precision format) is in 411DH-4124H in approximately 1.3 milliseconds.
0C70-0C72
“DSUB”
LD HL,412DH
Load register pair HL with the address of the MSB in REG 2.
0C73
LD A,(HL)
Load register A with the MSB of the double precision value in REG 2 at the location of the memory pointer in register pair HL.
0C74-0C75
XOR 80H
Invert the value of the sign bit for the MSB of the double precision value in register A which is 1000 0000.
0C76
LD (HL),A
Save the adjusted MSB of the double precision value in register A in REG 2 at the location of the memory pointer in register pair HL.

0C77-0CCEH -DOUBLE PRECISION ADDITION
“ADDDP”

  • Double-precision addition (REG 1=ACC+AACC).
    Adds the double precision value in REG 2 to the value in REG 1. Sum is left in REG 1.
  • Note: If you wanted to add 2 double precision numbers via a ROM call, store one input into 411DH-4124H and the other in 4127H-412EH. Then call 0C77H. The double precision result will be stored in 411DH-4124H approximately 1.3 milliseconds later.
0C77-0C79
“DADD”
LD HL,412EH
Load register pair HL with the address of the exponent in REG 2.
0C7A
LD A,(HL)
Load register A with the exponent of the double precision value in REG 2 at the location of the memory pointer in register pair HL.
0C7B
OR A
Check to see if the double precision value in REG 2 is equal to zero.
0C7C
RET Z
Return if the double precision value in REG 2 is equal to zero.
0C7D
LD B,A
Load register B with the value of the exponent for the double precision value in register A.
0C7E
DEC HL
Decrement the value of the memory pointer in register pair HL.
0C7F
LD C,(HL)
Load register C with the value of the MSB of the double precision value in REG 2 at the location of the memory pointer in register pair HL.
0C80-0C82
LD DE,4124H
Load register pair DE with the address of the exponent in REG 1.
0C83
LD A,(DE)
Load register A with the value of the exponent of the double precision value in REG 1 at the location of the memory pointer in register pair DE.
0C84
OR A
Check to see if the double precision value in REG 1 is equal to zero.
0C85-0C87
JUMP if the double precision value in REG 1 is equal to zero.
0C88
SUB B
Subtract the value of the exponent for the double precision value in REG 2 in register B from the value of the exponent for the double precision value in REG 1 in register A.
0C89-0C8A
JUMP if the double precision value in REG 1 is greater than or equal to the double precision value in REG 2.
0C8B
CPL
Complement the difference between the two exponents in register A.
0C8C
INC A
Increment the value of the difference for the exponents in register A so that register A will hold the positive difference.
0C8D
PUSH AF
Save the difference for the exponents in register A on the STACK.
0C8E-0C8F
LD C,08H
Load register C with the counter value which is 8.
0C90
INC HL
Increment the value of the memory pointer in register pair HL so that it will be pointing to the exponent of the double precision value in REG 2.
0C91
PUSH HL
Save the value of the memory pointer in register pair HL on the STACK.
0C92
LD A,(DE)
Load register A with the value at the location of the memory pointer in register pair DE.
0C93
LD B,(HL)
Load register B with the value at the location of the memory pointer in register pair HL.
0C94
LD (HL),A
Save the value in register A at the location of the memory pointer in register pair HL.
0C95
LD A,B
Load register A with the value in register B.
0C96
LD (DE),A
Save the value in register A at the location of the memory pointer in register pair DE.
0C97
DEC DE
Decrement the value of the memory pointer in register pair DE.
0C98
DEC HL
Decrement the value of the memory pointer in register pair HL.
0C99
DEC C
Decrement the value of the counter in register C.
0C9A-0C9B
Loop until the double precision values in REG 1 and REG 2 have been exchanged.
0C9C
POP HL
Get the value of the memory pointer from the STACK and put it in register pair HL.
0C9D
LD B,(HL)
Load register B with the value of the exponent for the double precision value in REG 2 at the location of the memory pointer in register pair HL.
0C9E
DEC HL
Decrement the value of the memory pointer in register pair HL.
0C9F
LD C,(HL)
Load register C with the value of the MSB for the double precision value in REG 2 at the location of the memory pointer in register pair HL.
0CA0
POP AF
Get the difference for the exponents from the STACK and put it in register A.
0CA1-0CA2
CP 39H
Check to see if the difference between the two exponents is greater than 56 bits. To do this we test A against 39H (A – 39H). If A<39H then the CARRY FLAG will be set and if A>=39H then the NO CARRY FLAG will be set.
0CA3
RET NC
Return if the difference between the two exponents is greater than 56 bits.
0CA4
PUSH AF
Save the difference for the exponents in register A on the STACK.
0CA5-0CA7
Go turn on the sign bits for the double precision numbers.
0CA8
INC HL
Increment the value of the memory pointer in register pair HL.
0CA9-0CAA
LD (HL),00H
Zero the location of the memory pointer in register pair HL.
0CAB
LD B,A
Save the result of the sign test in register A in register B.
0CAC
POP AF
Get the difference for the exponents from the STACK and put it in register A.
0CAD-0CAF
LD HL,412DH
Load register pair HL with the address of the MSB in REG 2.
0CB0-0CB2
Go shift the double precision value in REG 2 until it lines up with the double precision value in REG 1.
0CB3-0CB5
LD A,(4126H)
Get the bits shifted out of the double precision value in REG2 and put it in register A.
0CB6-0CB8
LD (411CH),A
Save the value in register A.

NOTE: 411CH is used by floating point routines.
0CB9
LD A,B
Load register A with the value of the sign test in register B.
0CBA
OR A
Check to see if the signs are equal.
0CBB-0CBD
Go subtract the values if the signs aren’t equal.
0CBE-0CC0
Go add the values.
0CC1-0CC3
JUMP if the CARRY FLAG isn’t set.
0CC4
EX DE,HL
Load register pair HL with the value of the memory pointer in register pair DE.
0CC5
INC (HL)
Increment the value of the exponent at the location of the memory pointer in register pair HL.
0CC6-0CC8
Display an ?OV ERROR if the exponent for the double precision result in REG 1 is too large.
0CC9-0CCB
GOSUB to 0D90H to adjust the double precision result in REG 1.
0CCC-0CCE
JUMP to 0D0EH.

0CCF-0DlF – DOUBLE PRECISION MATH ROUTINE

0CCF-0CD1
Go subtract the double precision values.
0CD2-0CD4
LD HL,4125H
Load register pair HL with the address of the sign for the result.

NOTE: 4125H-4126H is used by floating point routines.
0CD5-0CD7
Go complement the result in REG 1 if the CARRY FLAG is set.
0CD8
XOR A
Zero register A.
0CD9
LD B,A
Load register B with the value in register A.
0CDA-0CDC
LD A,(4123H)
Load register A with the value of the MSB of the double precision result in REG 1.
0CDD
OR A
Check to see if the MSB of the double precision result is equal to zero.
0CDE-0CDF
JUMP forward to 0CFEH if the MSB of the double precision value is nonzero.
0CE0-0CE2
LD HL,411CH
Load register pair HL with the starting address of REG 1 minus one.

NOTE: 411CH is used by floating point routines.
0CE3-0CE4
LD C,08H
Load register C with the number of bytes to be shifted.
0CE5
LD D,(HL)
Load register D with the value at the location of the memory pointer in register pair HL.
0CE6
LD (HL),A
Save the value in register A at the location of the memory pointer in register pair HL.
0CE7
LD A,D
Load register A with the value in register D.
0CE8
INC HL
Increment the value of the memory pointer in registerpair HL.
0CE9
DEC C
Decrement the number of bytes to be shifted in register C.
0CEA-0CEB
Loop until all of the bytes in the double precision value have been shifted.
0CEC
LD A,B
Load register A with the number of bits shifted in register B.
0CED-0CEE
SUB 08H
Subtract the number of bits just shifted from the shift counter in register A.
0CEF-0CF0
CP C0H
Check to see if the whole of the double precision value has been shifted.
0CF1-0CF2
JUMP to 0CD9H if the whole of the double precision value hasn’t been shifted.
0CF3-0CF5
JUMP to 0778H to make the double precision value equal to zero if the whole of the double precision value has been shifted.
0CF6
DEC B
Decrement the shift counter in register B.
0CF7-0CF9
LD HL,411CH
Load register pair HL with the starting address of REG 1 minus one.

NOTE: 411CH is used by floating point routines.
0CFA-0CFC
GOSUB to shift the double precision value in REG 1 once.
0CFD
OR A
Check to see if the sign bit of the MSB of the double precision value in register A is set.
0CFE-0D00
Loop until the sign bit is set.
0D01
LD A,B
Load register A with the value of the shift counter in register B.
0D02
OR A
Check to see if the shift counter in register A is equal to zero.
0D03-0D04
JUMP if the value in REG 1 wasn’t shifted at all.
0D05-0D07
LD HL,4124H
Load register pair HL with the address of the exponent in REG 1.
0D08
ADD A,(HL)
Add the value of the exponent for the double preci�sion value in REG 1 at the location of the memory pointer in register pair HL to the value of the shift counter in register A.
0D09
LD (HL),A
Save the adjusted exponent for the double precision value in register A at the location of the memory pointer in register pair HL.
0D0A-0D0C
JUMP if overflow didn’t occur.
0D0D
RET Z
Return if the double precision value is equal to zero.
0D0E-0D10
LD A,(411CH)
Load register A with the value of the rounding byte at the location of the starting address of REG 1 minus one.

NOTE: 411CH is used by floating point routines.
0D11
OR A
Check to see if there is a bit to be shifted into the double precision value in REG 1.
0D12-0D14
Go move the bit into the double precision value if necessary.
0D15-0D17
LD HL,4125H
Load register pair HL with the address of the sign for the result.

NOTE: 4125H-4126H is used by floating point routines.
0D18
LD A,(HL)
Load register A with the value of the sign for the result at the location of the memory pointer in register pair HL.
0D19-0D1A
AND 80H
Mask A against 80H (1000 0000), to turn off all bits other than Bit 7 (the sign).
0D1B
DEC HL
Decrement the value of the memory pointer in register pair HL so that it points to the exponent in REG 1.
0D1C
DEC HL
Decrement the value of the memory pointer in register pair HL so that it points to the MSB in REG 1
0D1D
XOR (HL)
Combine the value of the MSB of the double preci�sion value in REG 1 at the location of the memory pointer in register pair HL with the value of the sign for the result in register A.
0D1E
LD (HL),A
Save the adjusted MSB of the double precision value in register A at the location of the memory pointer in register pair HL.
0D1F
RET
Return.

0D20-0D32 – DOUBLE PRECISION MATH ROUTINE

0D20-0D22
LD HL,411DH
Load register pair HL with the starting address in REG 1.

NOTE: 411DH-4124H holds REG l.
0D23-0D24
LD B,07H
Load register B with the number of bytes to be bumped for the double precision value in REG 1.
0D25
INC (HL)
Increment the value at the location of the memory pointer in register pair HL.
0D26
RET NZ
Return if the value at the location of the memory pointer in register pair HL isn’t equal to zero.
0D27
INC HL
Increment the value of the memory pointer in register pair HL.
0D28
DEC B
Decrement the value of the byte counter in register B.
0D29-0D2A
Loop until all of the necessary bytes have been bumped.
0D2B
INC (HL)
Increment the value of the exponent at the location of the memory pointer in register pair HL.
0D2C-0D2E
Go to the Level II BASIC error routine and display an OV ERROR message if the exponent for the double precision value in REG 1 is too large.
0D2F
DEC HL
Decrement the value of the memory pointer in register pair HL.
0D30-0D31
LD (HL),80H
Save a new MSB at the location of the memory pointer in register pair HL.
0D32
RET
Return.

0D33-0D44 – DOUBLE PRECISION MATH ROUTINE

0D33-0D35
LD HL,4127H
Load register pair HL with the starting address of REG 2.

NOTE: 4127H-412EH holds REG 2 with 412EH being the exponent.
0D36-0D38
LD DE,411DH
Load register pair DE with the starting address of REG 1.

NOTE: 411DH-4124H holds REG l.
0D39-0D3A
LD C,07H
Load register C with the number of bytes to be added.
0D3B
XOR A
Clear the CARRY FLAG.
0D3C
LD A,(DE)
Load register A with the value in REG 1 at the location of the memory pointer in register pair DE.
0D3D
ADC A,(HL)
Add the value in REG 2 at the location of the memory value in register A.
0D3E
LD (DE),A
Save the result in register A in REGI at the location of the memory pointer in register pair DE.
0D3F
INC DE
Increment the value of the memory pointer in register pair DE.
0D40
INC HL
Increment the value of the memory pointer in register pair HL.
0D41
DEC C
Decrement the number of bytes to be added in register C.
0D42-0D43
Loop until all of the bytes for the double precision values have been added.
0D44
RET
Return.

0D45-0D56 – DOUBLE PRECISION MATH ROUTINE

0D45-0D47
LD HL,4127H
Load register pair HL with the starting address of REG 2.

NOTE: 4127H-412EH holds REG 2 with 412EH being the exponent.
0D48-0D4A
LD DE,411DH
Load register pair DE with the starting address of REG 1.

NOTE: 411DH-4124H holds REG l.
0D4B-0D4C
LD C,07H
Load register C with the number of bytes to be subtracted.
0D4D
XOR A
Clear the CARRY FLAG.
+-0D4E
LD A,(DE)
Load register A with the value in REG 1 at the location of the memory pointer in register pair DE.
| 0D4F
SBC A,(HL)
Subtract the value in REG 2 at the location of the memory pointer in register pair HL from the value in register A.
| 0D50
LD (DE),A
Save the result in register A in REG 1 at the location of the memory pointer in register pair DE.
| 0D51
INC DE
Increment the value of the memory pointer in register pair DE.
| 0D52
INC HL
Increment the value of the memory pointer in register pair HL.
| 0D53
DEC C
Decrement the number of bytes to be subtracted for the double precision values in register C.
+-0D54-0D55
Loop until all of the bytes for the double precision values have been subtracted.
0D56
RET
Return.

0D57-0D68 – DOUBLE PRECISION MATH ROUTINE

0D57
LD A,(HL)
Load register A with the value of the sign at the location of the memory pointer in register pair HL.
0D58
CPL
Complement the value of the sign in register A.
0D59
LD (HL),A
Save the value of the sign in register A at the location of the memory pointer in register pair HL.
0D5A-0D5C
LD HL,411CH
Load register pair HL with the starting address of REG 1 minus one.

NOTE: 411CH is used by floating point routines.
0D5D-0D5E
LD B,08H
Load register B with the number of bytes to be reversed.
0D5F
XOR A
Zero register A.
0D60
LD C,A
Load register C with the value in register A.
+-0D61
LD A,C
Load register A with the value in register C.
| 0D62
SBC A,(HL)
Subtract the value at the location of the memory pointer in register pair HL from the value in register A.
| 0D63
LD (HL),A
Save the reversed value in register A at the location of the memory pointer in register pair HL.
| 0D64
INC HL
Increment the value of the memory pointer in register pair HL.
| 0D65
DEC B
Decrement the number of bytes to be reversed in register B.
+-0D66-0D67
Loop until all of the bytes for the double precision number in REG 1 have been reversed.
0D68
RET
Return.

0D69-0D8F – DOUBLE PRECISION MATH ROUTINE

0D69
LD (HL),C
Save the MSB of the double precision value in register C at the location of the memory pointer in register pair HL.
0D6A
PUSH HL
Save the value of the memory pointer in register pair HL on the STACK.
0D6B-0D6C
SUB 08H
Subtract 8 from the number of bits to be shifted from the number of bits to be shifted in register A.
0D6D-0D6E
JUMP if there are less than 8 bits to be shifted.
0D6F
POP HL
Get the value of the memory pointer from the STACK and put it in register pair HL.
0D70
PUSH HL
Save the value of the memory pointer in register pair HL on the STACK.
0D71-0D73
LD DE,0800H
Load register pair DE with the number of bytes to be shifted (which is 2048) and the value to be shifted into the double precision value.
0D74
LD C,(HL)
Load register C with the value at the location of the memory pointer in register pair HL.
0D75
LD (HL),E
Save the value in register E at the location of the memory pointer in register pair HL.
0D76
LD E,C
Load register E with the value in register C.
0D77
DEC HL
Decrement the value of the memory pointer in register pair HL.
0D78
DEC D
Decrement the number of bytes shifted in register D.
0D79-0D7A
Loop until all of the bytes have been shifted.
0D7B-0D7C
Loop until there are less than 8 bits to be shifted.
0D7D-0D7E
ADD 09H
Adjust the number of bits to be shifted in register A so that it holds the correct value (adjustment against 0000 1001).
0D7F
LD D,A
Load register D with the number of bits to be shifted in register A.
0D80
XOR A
Zero register A.
0D81
POP HL
Get the value of the memory pointer from the STACK and put it in register pair HL.
0D82
DEC D
Decrement the number of bits to be shifted in register D.
0D83
RET Z
Return if all of the bits have been shifted.
0D84
PUSH HL
Save the value of the memory pointer in register pair HL on the STACK.
0D85-0D86
LD E,08H
Load register E with the number of bytes to be shifted.
0D87
LD A,(HL)
Load register A with the value at the location of the memory pointer in register pair HL.
0D88
RRA
Rotate the bits in register A right, copying Bit 0 to the CARRY FLAG, and the CARRY FLAG to bit 7.
0D89
LD (HL),A
Save the adjusted value in register A at the location of the memory pointer in register pair HL.
0D8A
DEC HL
Decrement the value of the memory pointer in register pair HL.
0D8B
DEC E
Decrement the number of bytes to be shifted in register E.
0D8C-0D8D
Loop until all of the bytes have been shifted.
0D8E-0D8F
Loop until all of the bits have been shifted.

0D90-0D96 – DOUBLE PRECISION MATH ROUTINE

0D90-0D92
LD HL,4123H
Load register pair HL with the address of the MSB of the double precision value in REG 1.
0D93-0D94
LD D,01H
Load register D with the number of bits to be shifted.
0D95-0D96
JUMP to 0D84H.

0D97-0DA0 – DOUBLE PRECISION MATH ROUTINE

0D97-0D98
LD C,08H
Load register C with the number of bytes to be shifted.
+-0D99
LD A,(HL)
Load register A with the value at the location of the memory pointer in register pair HL.
| 0D9A
RLA
Shift the value in register A.
| 0D9B
LD (HL),A
Save the shifted value in register A at the location of the memory pointer in register pair HL.
| 0D9C
INC HL
Increment the value of the memory pointer in register pair HL.
| 0D9D
DEC C
Decrement the byte counter in register C.
+-0D9E-0D9F
Loop until all of the bytes have been shifted.
0DA0
RET
Return.

0DAl-0DD3 – DOUBLE PRECISION MULTIPLICATION
“MLTDP”

  • Double-precision multiplication (REG 1=ACC*AACC).
    Multiplies the double precision value in REG 1 by the value in REG 2. The product is left in REG 1.
  • Note: If you wanted to multiply two double precision numbers store one operand in 411DH-4124H, and store the other in 4127H-412EH and then CALL 0DA1H. The result (in double precision format) is in 411DH-4124H in approximately 22 milliseconds.
0DA1-0DA3
“DMUL”
Go check to see if the value in REG 1 is equal to zero.
0DA4
RET Z
Return if the double precision value in REG 1 is equal to zero.
0DA5-0DA7
Go figure the new exponent.
0DA8-0DAA
Go move the double precision value in REG 1 to a temporary work area.
0DAB
LD (HL),C
Zero the location at the current value of the memory pointer in register pair HL.
0DAC
INC DE
Increment register pair DE so that it points to the LSB of the double precision value in the temporary work area.
0DAD-0DAE
LD B,07H
Load register B with the number of bytes to be figured.
0DAF
LD A,(DE)
Load register A with the value at the location of the memory pointer in register pair DE.
0DB0
INC DE
Increment the value of the memory pointer in register pair DE.
0DB1
OR A
Check to see if the value in register A is equal to zero.

0DB2 – INTEGER ADD routine – “IADD”

Adds the integer value in DE to the integer in HL. The sum is left in HL and the orginal 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 REG 1 and the mode flag would be updated.

0DB2
PUSH DE
Save the value of the memory pointer in register pair DE on the STACK.
0DB3-0DB4
JUMP if the value in register A is equal to zero.
0DB5-0DB6
LD C,08H
Load register C with the numberofbits to be shifted.
0DB7
PUSH BC
Save the value in register pair BC on the STACK.
0DB8
RRA
Shift the value in register A one place to the right.
0DB9
LD B,A
Load register B with the value in register A.
0DBA-0DBC
Go add the value in REG 2 to the total in REG 1 if bit zero of register A was set.
0DBD-0DBF
Go shift the value of the total in REG 1.
0DC0
LD A,B
Load register A with the adjusted value in register B.
0DC1
POP BC
Get the value from the STACK and put it in register pair BC.
0DC2
DEC C
Decrement the number of bits to be shifted in regis�ter C.
0DC3-0DC4
Loop back to 0DB7H until all of the bits have been shifted.
0DC5
POP DE
Get the value from the STACK and put it in register pair DE.
0DC6
DEC B
Decrement the number of bytes to be figured in register B.
0DC7-0DC8
Loop back to 0DAFH until all of the bytes have been figured.
0DC9-0DCB
JUMP to 0CD8H.
0DCC-0DCE
LD HL,4123H
Load register pair HL with the address of the MSB in REG 1
0DCF-0DD1
Go shift the double precision total in REG 1.
0DD2-0DD3
JUMP to 0DC5H.

0DD4-0DDB – DOUBLE PRECISION CONSTANT STORAGE AREA

0DD4-0DDB
00 00 00 00 00 00 20 84
A double precision constant equal to 10.0 is stored here.

0DDC-0DE4 – DOUBLE PRECISION MATH ROUTINE – – Divide a double precision number by 10.

0DDC-0DDE
LD DE,0DD4H
Load register pair DE with the starting address of the double precision constant stored above.
0DDF-0DE1
LD HL,4127H
Load register pair HL with the starting address of REG 2.

NOTE: 4127H-412EH holds REG 2 with 412EH being the exponent.
0DE2-0DE4
Go move the double precision constant into REG 2.

0DE5-0E38 – DOUBLE PRECISION DIVISION
“DIVDP”

  • Double-precision division (REG 1=ACC / AACC).
    Divides the double precision value in WRAl by the value in REG 2. The quotient is left in REG 1.
  • To use a ROM call to divide two double precision numbers, store the dividend in 411DH-4124H, and the divisor in 4127H-412EH and then CALL 0DE5H. The result (in double precision format) is in 411DH-4124H and then pproximately 42 milliseconds. Overflow or /0 will error out and return to Level II.
0DE5-0DE7
“DDIV”
LD A,(412EH)
Load register A with the value of the exponent for the double precision value in REG 2.
0DE8
OR A
Check to see if the double precision value in REG 2 is equal to zero.
0DE9-0DEB
Display a /0 ERROR message if the double precision value in REG 2 is equal to zero.
0DEC-0DEE
Go figure the value of the new exponent.
0DEF
INC (HL)
Increment the value of the exponent in REG 1.
0DF0
INC (HL)
Increment the value of the exponent in REG 1.
0DF1-0DF3
Go move the double precision value from REG 1 into the temporary work area.
0DF4-0DF6
LD HL,4151H
Load register pair HL with the address of the exponent in the temporary work area.
0DF7
LD (HL),C
Zero the value of the exponent in the temporary work area at the location of the memory pointer in register pair HL.
0DF8
LD B,C
Zero register B.
0DF9-0DFB
LD DE,414AH
Load register pair DE with the starting address of the double precision value in the temporary work area.

NOTE: 414AH-4151H is used by floating pointer routines.
0DFC-0DFE
LD HL,4127H
Load register pair HL with the starting address of the double precision value in REG 2.

NOTE: 4127H-412EH holds REG 2 with 412EH being the exponent.
0DFF-0E01
Go subtract the double precision value in REG 2 from the double precision value in the temporary work area.
0E02
LD A,(DE)
Load register A with the value at the location of the memory pointer in register pair DE.
0E03
SBC A,C
Subtract the value in register C from the value in register A.
0E04
CCF
Complement the value of the CARRY FLAG.
0E05-0E06
JUMP if the double precision value in REG 2 is greater than the double precision value in the temporary work area.
0E07-0E09
LD DE,414AH
Load register pair DE with the starting address of the double precision value in the temporary work area.

NOTE: 414AH-4151H is used by floating pointer routines.
0E0A-0E0C
LD HL,4127H
Load register pair HL with the starting address of tht double precision value in REG 2.

NOTE: 4127H-412EH holds REG 2 with 412EH being the exponent.
0E0D-0E0F
Go add the double precision value in REG 2 to the double precision value in the temporary work area.
0E10
XOR A
Zero register A.
0E11-0E13
If the CARRY FLAG is set, JUMP to 0412H.
0E14-0E16
LD A,(4123H)
Load register A with the value of the MSB of the total in REG 1.
0E17
INC A
Increment the value of the MSB for the double precision result in register A.
0E18
DEC A
Decrement the value of the MSB for the double precision result in register A.
0E19
RRA
Rotate A right one bit, putting the old BIT 0 into the CARRY FLAG, and putting the old CARRY FLAG into BIT 7, which is the SIGN bit.
0E1A-0E1C
If the NEGATIVE FLAG is set by the prior rotation, then JUMP to 0D11H.
0E1D
RLA
Put the sign bit in register A back into the CARRY FLAG.
0E1E-0E20
LD HL,411DH
Load register pair HL with the starting address of the double precision result in REG 1.

NOTE: 411DH-4124H holds REG l.
0E21-0E22
LD C,07H
Load register C with the number of bytes to be shifted.
0E23-0E25
Go shift the double precision result in REG 1.
0E26-0E28
LD HL,414AH
Load register pair HL with the starting address of the double precision value in the temporary work area.

NOTE: 414AH-4151H is used by floating pointer routines.
0E29R-0E2B
Go shift the double precision value in the temporary work area.
0E2C
LD A,B
Load register A with the value of the counter in register B.
0E2D
OR A
Check to see if the value of the counter in register A is equal to zero.
0E2E-0E2F
Loop until done if the value of the counter in register A isn’t equal to zero.
0E30-0E32
LD HL,4124H
Load register pair HL with the address of the exponent for the double precision result in REG 1 (which is 16676).
0E33
DEC (HL)
Decrement the value of the exponent for the double precision result in REG 1 at the location of the mem�ory pointer in register pair HL.
0E34-0E35
Loop until done if overflow didn’t occur.
0E36-0E38
Display an ?OV ERROR if the exponent for the result in REG 1 is too small.

0E39-0E4C – DOUBLE PRECISION MATH ROUTINE – Move the double precision value in REG 1 to a temporary work area.

0E39
LD A,C
Load register A with the MSB of the double precision value in REG 2 in register C.
0E3A-0E3C
LD (412DH),A
Save the MSB of the double precision value in REG 2 in register A.
0E3D
DEC HL
Decrement the value of the memory pointer in register pair HL.
0E3E-0E40
LD DE,4150H
Load register pair DE with the starting address of the temporary work area.
0E41-0E43
LD BC,0700H
Load register B with the number of bytes to be moved (which is 1792) and zero register C.
0E44
LD A,(HL)
Load register A with the value at the location of the memory pointer in register pair HL.
0E45
LD (DE),A
Save the value in register A at the location of the memory pointer in register pair DE.
0E46
LD (HL),C
Zero the location of the memory pointer in register pair HL.
0E47
DEC DE
Decrement the value of the memory pointer in register pair DE.
0E48
DEC HL
Decrement the value of the memory pointer in register pair HL.
0E49
DEC B
Decrement the value of the byte counter in register B.
0E4A-0E4B
Loop until the double precision value has been moved to the temporary work area.
0E4C
RET
Return.

0E4D-0E64 – LEVEL II BASIC MATH ROUTINE – Multiply the current double precision value by 10

  • This routine multiplies the current DP value by 2 by adding it to itself. First the current value is moved to a saved location, and then DP add routine adds the current value to that saved value.
0E4D-0E4F
Go move the value in REG 1 to REG 2.
0E50
EX DE,HL
Load register pair HL with the value of the memory pointer in register pair DE.
0E51
DEC HL
Decrement the value of the memory pointer in register pair HL.
0E52
LD A,(HL)
Load register A with the value of the exponent in REG 1 at the location of the memory pointer in register pair HL.
0E53
OR A
Check to see if the value in REG 1 is equal to zero.
0E54
RET Z
Return if the value in REG 1 is equal to zero.
0E55-0E56
ADD 02H
Adjust the exponent for the following addition.
0E57-0E59
Display an ?OV ERROR if the adjusted exponent in register A is too large.
0E5A
LD (HL),A
Save the adjusted exponent in register A in REG 1 at the location of the memory pointer in register pair HL.
0E5B
PUSH HL
Save the value of the memory pointer in register pair HL on the STACK.
0E5C-0E5E
Call the DOUBLE PRECISION ADD function (which adds the double precision value in REG 2 to the value in REG 1. Result is left in REG 1).
0E5F
POP HL
Get the value of the memory pointer from the STACK and put it in register pair HL.
0E60
INC (HL)
Increment the value of the exponent for the double preci�sion value in REG 1 at the location of the memory pointer in register pair HL.
0E61
RET NZ
Return if overflow didn’t occur.
0E62-0E64
Display an ?OV ERROR if the exponent in REG 1 at the location of the memory pointer in register pair HL is too large.

0E65-0F88 – ASCII TO DOUBLE PRECISION

  • This routine converts an ASCII string (pointed to by HL) to a double-precision value and stores it in the ACC. The NTF is fixed accordingly. The string must be terminated with a , or zero byte. Note that the AACC is destroyed in the process and that HL will point to the delimiter at the end of the string. The string formats must follow the same rules as in BASIC.
0E65-0E67
Go zero the exponent in REG 1.
0E68-0E6A
Go set the current number type flag to double precision.

0E6C – ASCII to Binary Converter

  • A call to 0E6CH 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 REG 1 and the mode flag will be to the proper value.
  • Note: If you wanted to do this conversion via a ROM call, first have the characters assembled in consecutive memory locations, with either a comma or a 00H at the end. Load HL with the address of the first character. Call 0E6CH. If the output can be an integer, it will be in 4121H-4122H (with 40AFH being a 2). If the output has to be single precision, it will be in 4121H-4124H (with 40AFH being a 4). If the output has to be double precision, it will be in 411DH-4124H (with 40AFH being an 8).
0E6C
“ASTOR”
OR AFH
Zero register A (by issuing an OR against 1010 1111).
This routine is the same as E65H above, except that it fixes REG 1 and NTF to the smallest possible number type.
0E6D
EX DE,HL
Load register pair DE with the current input buffer pointer in register pair HL.
0E6E-0E70
LD BC,00FFH
Load register pair BC with a zero and a negative one.
0E71
LD H,B
Load register H with zero.
0E72
LD L,B
Load register L with zero.
0E73-0E75
Go set the current number type flag to integer if the routine was entered from OE6CH.
0E76
EX DE,HL
Load register pair HL with the input buffer pointer in register pair DE.
0E77
LD A,(HL)
Load register A with the character at the location of the current input buffer pointer in register pair HL.
0E78-0E79
CP 2DH
Check to see if the character at the location of the current input buffer pointer in register A is a minus sign(-).
0E7A
PUSH AF
Save the value in register pair AF on the STACK.
0E7B-0E7D
JUMP if the character at the location of the current input buffer pointer in register A is a minus sign (-).
0E7E-0E7F
CP 2BH
Check to see if the character at the location of the current input buffer pointer in register A is a plus sign(+).
0E80-0E81
JUMP if the character at the location of the current input buffer pointer in register A is a plus sign ( +).
0E82
DEC HL
Decrement the value of the current input buffer pointer in register pair HL.

0E83H – Process a + or at the location of the current input buffer.

0E83
RST 10H
Since we need to bump the current input buffer pointer in register pair HL until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H (which 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 OB are ignored causing the following character to be loaded and tested. The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one. The string must be terminated by a byte of zeros).
0E84-0E86
JUMP if the character at the location of the current input buffer pointer in register A is numeric.
0E87-0E88
CP 2EH
Check to see if the character at the location of the current input buffer pointer in register A is a decimal point (.).
0E89-0E8B
JUMP if the character at the location of the current input buffer pointer in register A is a decimal point (.).
0ESC-0E8D
CP 45H
Check to see if the character at the location of the current input buffer pointer in register A is an E.
0E8E-0E8F
JUMP if the character at the location of the current input buffer pointer in register A is an E.
0E90-0E91
CP 25H
Check to see if the character at the location of the current input buffer pointer in register A is a %.
0E92-0E94
JUMP if the character at the location of the current input buffer pointer in register A is a %.
0E95-0E96
CP 23H
Check to see if the character at the location of the current input buffer pointer in register A is a #.
0E97-0E99
JUMP if the character at the location of the current input buffer pointer in register A is a #.
0E9A-0E9B
CP 21H
Check to see if the character at the location of the current input buffer pointer in register A is an ! .
0E9C-0E9E
JUMP if the character at the location of the current input buffer pointer in register A is an ! .
0E9F-0EA0
CP 44H
Check to see if the character at the location of the current input buffer pointer in register A is a D.
0EA1-0EA2
JUMP if the character at the location of the current input buffer pointer in register A isn’t a D.
0EA3
OR A
Set the flags according to the value of the character at the location of the current input buffer pointer in register A.

0EA4H – Inside the ASCII TO BINARY CONVERTER routine. Process a E at the location of the current input buffer.

0EA4-0EA6
GOSUB to 0EFBH to convert the current value in REG 1 to either single precision (if Z is set) or double precision (if NZ is set).
0EA7
PUSH HL
Save the current input buffer pointer in register pair HL on the STACK.
0EA8-0EAA
LD HL,0EBDH
Load register pair HL with the return address (which is 3773).
0EAB
EX (SP),HL
Exchange the return address in register pair HL with the value of the current input buffer pointer in register pair HL.
0EAC
RST 10H
Since we need to bump the current input buffer pointer in register pair HL until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.
NOTE:
  • The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
  • Blanks and control codes 09H and 0BH are ignored causing the following character to be loaded and tested.
  • The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one.
  • The string must be terminated by a byte of zeros.
0EAD
DEC D
Decrement the value in register D.
0EAE-0EAF
CP CEH
Check to see if the character at the location of the current input buffer pointer in register A is a minus sign token ( CEH).
0EB0
RET Z
Return if the character at the location of the current input buffer pointer in register A is a minus sign token (CEH).
0EB1-0EB2
CP 2DH
Check to see if the character at the location of the current input buffer pointer in register A is a minus sign(-).
0EB3
RET Z
Return if the character at the location of the current input buffer pointer in register A is a minus sign (-).
0EB4
INC D
Increment the value in register D.
0EB5-0EB6
CP CDH
Check to see if the character at the location of the current input buffer pointer in register A is a plus sign token (CDH.)
0EB7
RET Z
Return if the character at the location of the current input buffer pointer in register A is a plus sign token (CDH).
0EB8-0EB9
CP 2BH
Check to see if the character at the location of the current input buffer pointer in register A is a plus sign ( +).
0EBB
RET Z
Return if the character at the location of the current input buffer pointer in register A is a plus sign ( +).
0EBA
DEC HL
Decrement the value of the input buffer pointer in register pair HL.
0EBC
POP AF
Get the value from the STACK and put it in register pair AF.
0EBD
RST 10H
Since we need to bump the current input buffer pointer in register pair HL until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.
NOTE:
  • The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
  • Blanks and control codes 09H and 0BH are ignored causing the following character to be loaded and tested.
  • The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one.
  • The string must be terminated by a byte of zeros.
0EBE-0EC0
JUMP if the character at the location of the input buffer pointer in register A is numeric.
0EC1
INC D
Increment the value in register D.
0EC2-0EC3
JUMP if the exponent is positive.
0EC4
XOR A
Zero register A.
0EC5
SUB E
Subtract the value of the exponent in register E from register A.
0EC6
LD E,A
Load register E with the value of the exponent in register A.
0EC7
PUSH HL
Save the current input buffer pointer in register pair HL on the STACK.
0EC8
LD A,E
Load register A with the value of the exponent in register E.
0EC9
SUB B
Subtract the value in register B from the exponent in register A.
0ECA-0ECC
Go multiply the current value by ten if necessary.
0ECD-0ECF
Go divide the current value by ten if necessary.
0ED0-0ED1
Loop until the value is adjusted correctly.
0ED2
POP HL
Get the value of the current input buffer pointer from the STACK and put it in register pair HL.
0ED3
POP AF
Get the value from the STACK and put it in register pair AF.
0ED4
PUSH HL
Save the value of the current input buffer pointer in register pair HL on the STACK.
0ED5-0ED7
GOSUB to 097BH to convert the negative value in REG 1 to its positive equivalent.
0ED8
POP HL
Get the value of the current input buffer pointer from the STACK and put it in register pair HL.
0ED9
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0EDA
RET PE
If that test shows we have anything other than a SINGLE PRECISION number, return out of the subroutine.
0EDB
PUSH HL
Save the current value of the input buffer pointer in register pair HL on the STACK.
0EDC-0EDE
LD HL,0890H
Load register pair HL with the return address of 2192.
0EDF
PUSH HL
Save the value of the return address in register pair HL on the STACK.
0EE0-0EE2
Go convert the current value in REG 1 to an integer if possible.
0EE3
RET
Return.

0EE4H – Inside the ASCII TO BINARY CONVERTER routine. Process a . at the location of the current input buffer. JUMPed to from 0E89H.

0EE4
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0EE5
INC C
Increment the value in register C.
0EE6-0EE7
If that test shows we have a number, jump to 0EC7H since there is no need to convert the current value.
0EE8-0EEA
If that test shows we have anything other than DOUBLE PRECISION, GOSUB to 0EFBH to convert the current value in REG 1 to either single precision (if Z is set) or double precision (if NZ is set).
0EEB-0EED
JUMP to 0E83H.

0EEEH – Inside the ASCII TO BINARY CONVERTER routine. Process a % at the location of the current input buffer. JUMPed to from 0E92H.

0EEE
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0EEF-0EF1
If that test shows anything butn an INTEGER, jump to the Level II BASIC error routine and display a SN ERROR message.
0EF2
INC HL
Increment the value of the current input buffer pointer in register pair HL.
0EF3-0EF4
JUMP to 0EC7H.
0EF5
OR A
Set the flags according to the character at the location of the current input buffer pointer in register pair HL.
0EF6-0EF8
GOSUB to 0EFBH to convert the current value in REG 1 to either single precision (if Z is set) or double precision (if NZ is set).
0EF9-0EFA
JUMP to 0EF2H.

0EFBH – Inside the ASCII TO BINARY CONVERTER routine. Convert the current value in REG 1 to either single precision or double precision based on the Z FLAG.

0EFB
PUSH HL
Save the value in register pair HL on the STACK.
0EFC
PUSH DE
Save the value in register pair DE on the STACK.
0EFD
PUSH BC
Save the value in register pair BC on the STACK.
0EFE
PUSH AF
Save the value in register pair AF on the STACK.
0EFF-0F01
Call the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of REG 1 from integer or double precision into single precision).
0F02
POP AF
Get the value from the STACK and put it in register pair AF.
0F03-0F05
Call the CONVERT TO DOUBLE PRECISION routine at 0ADBH (where the contents of REG 1 are converted from integer or single precision to double precision).
0F06
POP BC
Get the value from the STACK and put it in register pair BC.
0F07
POP DE
Get the value from the STACK and put it in register pair DE.
0F08
POP HL
Get the value from the STACK and put it in register pair HL.
0F09
RET
Return.

0F0AH – Multiply the current value by 10 Part 1 – Jumps to Part 2 based on number type.

0F0A
RET Z
Return if the current value is an integer.
0F0B
PUSH AF
Save the value in register pair AF on the STACK.
0F0C
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0F0D
PUSH AF
Save the value in register pair AF on the STACK.
0F0E-0F10
If that test shows SINGLE PRECISION, go to 093EH to multiply the current value in REG 1 by ten.
0F11
POP AF
Get the value from the STACK and put it in register pair AF.
0F12-0F14
If that test shows DOUBLE PRECISION, go to 0E4DH to multiply the current value in REG 1 by ten.
0F15
POP AF
Get the value from the STACK and put it in register pair AF.
0F16
DEC A
Decrement the value in register A.
0F17
RET
Return.

0F18H – Divide the current value by 10 Part 1 – Jumps to Part 2 based on number type.

0F18
PUSH DE
Save the value in register pair DE on the STACK.
0F19
PUSH HL
Save the value in register pair HL on the STACK.
0F1A
PUSH AF
Save the value in register pair AF on the STACK.
0F1B
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0F1C
PUSH AF
Save the value in register pair AF on the STACK.
0F1D-0F1F
If that test shows SINGLE PRECISION, go to 0897H to divide the current value in REG 1 by ten.
0F20
POP AF
Get the value from the STACK and put it in register pair AF.
0F21-0F23
If that test shows DOUBLE PRECISION, go to 0DDCH to divide the current value in REG 1 by ten.
0F24
POP AF
Get the value from the STACK and put it in register pair AF.
0F25
POP HL
Get the value from the STACK and put it in register pair HL.
0F26
POP DE
Get the value from the STACK and put it in register pair DE.
0F27
INC A
Increment the value in register A.
0F28
RET
Return.

0F29H – Inside the ASCII TO BINARY CONVERTER routine. Process a number at the location of the current input buffer. JUMPed to from 0E84H.

0F29
PUSH DE
Save the value in register pair DE on the STACK.
0F2A
LD A,B
Load register A with the value in register B.
0F2B
ADC A,C
Add the value in register C to the value in register A.
0F2C
LD B,A
Load register B with the adjusted value in register A.
0F2D
PUSH BC
Save the value in register pair BC on the STACK.
0F2E
PUSH HL
Save the value in register pair HL on the STACK.
0F2F
LD A,(HL)
Load register A with the character at the location of the current input buffer pointer in register pair HL.
0F30-0F31
SUB 30H
Convert the adjusted value in register A to it�s binary equivalent (which is subtracting 0011 0000)
0F32
PUSH AF
Save the adjusted value in register A on the STACK.
0F33
RST 20H
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in REG 1 and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH).

The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
0F34-0F36
If that test shows we have anything but an INTEGER, jump to 0F5DH.
0F37-0F39
LD HL,(4121H)
Now that we know we have an integer, load register pair HL with the integer value in REG 1.
0F3A-0F3C
LD DE,0CCDH
Load register pair DE with 0CCDH.
0F3D
RST 18H
Now we need to check to see if the integer value in HL is greater than or equal to 0CCDH (in DE), so we call the COMPARE DE:HL routine, which 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=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal).
0F3E-0F3F
JUMP to 0F59 if the integer value in register pair HL is greater than or equal to 0CCDH.
0F40
LD D,H
Load register D with the MSB of the integer value in register H.
0F41
LD E,L
Load register E with the LSB of the integer value in register L.
0F42
ADD HL,HL
Multiply the integer value in register pair HL by two.
0F43
ADD HL,HL
Multiply the integer value in register pair HL by two. Register pair HL now holds the original integer value times four.
0F44
ADD HL,DE
Add the original integer value in register pair DE to the integer value in register pair HL. Register pair HL now holds the original integer value times five.
0F45
ADD HL,HL
Multiply the integer value in register pair HL by two. Register pair HL now holds the origmal integer value times ten.
0F46
POP AF
Get the binary value for the next character from the STACK and put it in register A.
0F47
LD C,A
Load register C with the value of the character in register A.
0F48
ADD HL,BC
Add the value of the character in register pair BC to the integer value in register pair HL.
0F49,0F4A
LD A,H
OR A
The easiest way to check flags for a 2-byte register is to OR the bytes together.
0F4B-0F4D
JUMP if the sign bit is set in the integer value in register pair HL.
0F4E-0F50
LD (4121H),HL
Save the integer value in register pair HL as the current integer value in REG 1.
0F51
POP HL
Get the value from the STACK and put it in register pair HL.
0F52
POP BC
Get the value from the STACK and put it in register pair BC.
0F53
POP DE
Get the value from the STACK and put it in register pair DE.
0F54-0F56
JUMP to 0E83H.

0F57H – Inside the ASCII TO BINARY CONVERTER routine. At this point, the integer value in HL has the sign bit HIGH.

0F57
LD A,C
Load register A with the binary value of the character in register C.
0F58
PUSH AF
Save the value in register A on the STACK.
0F59-0F5B
GOSUB to 0ACCH to convert the current value in REG 1 to single precision.
0F5C
SCF
Set the CARRY FLAG.
0F5D-0F5E
JUMP if the current value in REG 1 is double precision.
0F5F-0F61
LD BC,9474H
Load register pair BC with the exponent and the MSB of a single precision constant.
0F62-0F64
LD DE,2400H
Load register pair DE with the NMSB and the LSB of a single precision constant. Register pairs BC and DE now hold a single precision constant equal to 1E6.
0F65-0F67
GOSUB to the SINGLE PRECISION COMPARISON routine at 0A0CH.

NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:
  • A=0 if REG 1 = BCDE
  • A=1 if REG 1>BCDE; and
  • A=FFH if REG 1<BCDE.
0F68-0F6A
JUMP to 0F74H if the single precision value in REG 1 is greater than or equal to 1E6.
0F6B-0F6D
Go multiply the single precision value in REG 1 by 10.
0F6E
POP AF
Get the binary value of the character from the STACK and put it in register A.
0F6F-0F71
Go add the value in register A to the single precision value in REG 1.
0F72-0F33
JUMP to 0F51H.
0F74-0F76
Go convert the single precision value in REG 1 to double precision.

0F77H – Inside the ASCII TO BINARY CONVERTER routine. At this point, the number in REG 1 is double precision.

0F77-0F79
Go multiply the double precision value in REG 1 by ten.
0F7A-0F7C
Go move the double precision value in REG 1 to REG 2.
0F7D
POP AF
Get the binary value for the character from the STACK and put it in register A.
0F7E-0F80
Go convert the binary value in register A to single precision.
0F81-0F83
Go convert the single precision value in REG 1 to double precision.
0F84-0F86
Call the DOUBLE PRECISION ADD function (which adds the double precision value in REG 2 to the value in REG 1. Result is left in REG 1).
0F87-0F88
JUMP to 0F51H.

0F89-0F93 – SINGLE PRECISION MATH ROUTINE – Subroutine to add the value in register A to the single precision value in REG 1

0F89-0F8B
Call 09A4 which moves the SINGLE PRECISION value in REG 1 to the STACK (stored in LSB/MSB/Exponent order).
0F8C-0F8E
Go convert the value in register Ato single precision and return with the result in REG 1.
0F8F
POP BC
Get the exponent and the MSB for the single preci�sion value from the STACK and put it in register pair BC.
0F90
POP DE
Get the NMSB and the LSB of the single precision value from the STACK and put it in register pair DE.
0F91-0F93
JUMP to the SINGLE PRECISION ADD routine at 0716H (which adds the single precision value in (BC/DE) to the single precision value in REG 1. The sum is left in REG 1).

0F94-0FA6 – LEVEL II BASIC MATH ROUTINE – Part of the ASCII TO BINARY CONVERSION routine. JUMPs here if the character at the location of the input buffer pointer in register A is numeric

0F94
LD A,E
Load register A with the value of the exponent in register E.
0F95-0F96
CP 0AH
We need to check to see if the value of the exponent in register A is greater than or equal to 10, by testing A – 0AH. If A=0AH it sets the ZERO FLAG. If A<0AH then the CARRY FLAG will be set and if A>=0AH then the NO CARRY FLAG will be set.
0F97-0F98
JUMP if the value of the exponent in register A is greater than or equal to 10.
0F99
RLCA
Multiply the value in register A by two.
0F9A
RLCA
Multiply the value in register A by two. Register A now holds the original value of the exponent times four.
0F9B
ADD A,E
Add the original value of the exponent in register E to the adjusted value of the exponent in register A.
0F9C
RLCA
Multiply the value in register A by two. Register A now holds the original value of the exponent times ten.
0F9D
ADD A,(HL)
Add the value of the current character at the memory location of the input buffer pointer in register pair HL to the adjusted value in register A.
0F9E-0F9F
SUB 30H
Convert the adjusted value in register A to its binary equivalent (which is subtracting 0011 0000).
0FA0
LD E,A
Load register E with the adjusted value in register A.
0FA2-0FA3
Load register E with the maximum exponent.
0FA4-0FA6
JUMP to 0EBDH.

0FA7-0FAE – DISPLAY MESSAGE ROUTINE

0FA7
PUSH HL
Save the value in register pair HL on the STACK.
0FA8-0FAA
LD HL,1924H
Load register pair HL with the starting address of the IN message (which is 1924H).
0FAB-0FAD
Call the WRITE MESSAGE routine at 28A7H..
NOTE:
  • The routine at 28A7 displays the 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 41D0H (JP 5B99H).
0FAE
POP HL
Get the value from the STACK and put it in register pair HL.

0FAF-0FBC – CONVERT BINARY TO ASCII AND DISPLAY RESULT. This is also the continuation of the DISPLAY MESSAGE routine above because it is showing an error “IN xxxx” where xxxx would be the ASCII of xxxx (the line number).

This routine converts the value in the HL register pair (which is assumed to be an integer) to ASCII and display it at the current cursor position on the video screen.

0FAF-0FB1
Go save the value in register pair HL as the current value in REG 1.
0FB2
XOR A
Zero register A.
0FB3-0FB5
Go initialize the input buffer for the ASCII conversion.
0FB6
OR (HL)
Set the flags.
0FB7-0FB9
Go convert the integer value in REG 1 to an ASCII string. Return with register pair HL pointing to the result.
0FBA-0FBC
Go display the message pointed to by register pair HL.

0FBDH – BINARY TO ASCII CONVERSION ROUTINE
“CSAASC”

  • Conversion routine. Converts the value from REG 1 to an ASCII string delimited with a zero byte. The number type can be any of Integer, single or double-precision. After execution HL will be pointing to the start of the string. REG 1 and AACC are destroyed by the process.
  • To use a ROM call to convert a number to a string of digits, and to display the latter on the video screen starting at the current cursor position, store the number in 4121H-4122H (if it’s an integer), or in 4121H-4124H (if it’s single precision), or in 411DH-4124H (if it’s double precision). Then store the variable type (2, 4, or 8, respectively) in 40AFH. Call 0FBDH and then call the WRITE MESSAGE routine at 28A7H.
    • NOTE 1: The routine at 0FBDH is the conversion routine described in Section 3.3 (a). The subroutine at 28A7H is a general program for displaying a string of characters and updating the cursor position. The string to be displayed must be terminated by a zero byte, and the HL register pair must contain the address of the first character of the string before 28A7H is called. (The routine at 0FBDH effects this setup automatically.)
    • NOTE 2: Many of the ROM routines described in this book require a numeric input (or inputs). For most of these, the instructions given for calling them have not included the storage of the variable type flag in 40AFH. The reason is that, wherever possible, the variable type flag storage has been finessed by the choice of the subroutine entry point. In the routine of this section, that has not been possible, nor was it possible for the INT, the FIX, the Number to Numeric String, the SGN, or the ABS routines. Storing a 2, 4, or 8 in 40AFH takes only 5 bytes of machine code, but there are subroutines in the Level II ROM that can reduce the required code to 3 bytes. CALL 0A9DH will store a 2 in 40AFH. CALL 0AEFH will store a 4 in 40AFH. And, finally, CALL 0AECH will store an 8 in 40AFH; this last subroutine, however, destroys the contents of the BC register pair. DISK SYSTEM CAUTION: The subroutine at 28A7H has two exits to DISK BASIC, with RAM transfer points at 41C1H and 41D0H. To use this routine safely, either be certain that DISK BASIC is in place or have your assembly language program fill locations 41C1H and 41D0H with RET’s (C9H), before calling the routine.
0FBD
“NEDIT”
XOR A
Zero register A.

0FBE-0FC0 – FLOATING to ASCII Conversion Routine

  • This routine converts a single or double precision number in REG 1 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 as follows:
    • A=0 means do not edit; this is a binary to ASCII conversion
    • A=X means edit as follows: Bit 7=1 means edit the value, Bit 6=Print commas every third digit, Bit 5=Include leading asterisks, Bit 4=Print a leading $, Bit 3=Sign Follows Value, and Bit 1=Exponential Notation
    • B = The number of digits to the left of the decimal point.
    • C = The number of digits after the decimal point.
  • Note: If you wanted to convert any integer/single/double into its character string, store the variable in 4121H-4122H for integer, 4121H-4124H for single, or in 411DH-4124H for double. Then load 40AFH with a 2, 4, or 8 depending on whether that variable was integer, single, or double. Then call 0FBDH. Upon return, the character string is stored in 4130H and on, ending with a 00H.
0FBE-0FC0
Initialize the input buffer for the ASCII conversion by calling 1034H (which puts the EDIT flag into A, loads HL with the starting address of the input buffer, and inserts a space).
0FC1-0FC2
AND 08H
Mask A against 08H (Binary: 0000 1000) to help check the value of the edit flag in register A to see if the sign is to be included.
0FC3-0FC4
Skip the next instruction (i.e., JUMP to 0FC7H) if the sign isn’t to be included in the ASCII string.
0FC5-0FC6
LD (HL),2BH
Save a + at the location of the input buffer pointer in register pair HL.
0FC7
EX DE,HL
Load register pair DE with the value of the input buffer pointer in register pair HL.
0FC8-0FCA
Go determine the value of the sign for the current value in REG 1.
0FCB
EX DE,HL
Load register pair HL with the input buffer pointer in register pair DE.
0FCC-0FCE
JUMP down to 0FD9H if the current value in REG 1 is positive.
0FCF-0FD0
LD (HL),2DH
Save a at the location of the input buffer pointer in register pair HL.
0FD1
PUSH BC
Save the value in register pair BC on the STACK.
0FD2
PUSH HL
Save the value in register pair HL on the STACK.
0FD3-0FD5
GOSUB to 097BH to convert the negative value in REG 1 to its positive equivalent.
0FD6
POP HL
Get the value from the STACK and put it in register pair HL.
0FD7
POP BC
Get the value from the STACK and put it in register pair HL.
0FD8
OR H
Set the flags.

0FD9H is a routine which will convert the integer value in REG 1 (i.e., 4124H) to an ASCII string. Returns with register pair HL pointing to the result.

0FD9
INC HL
Increment the input buffer pointer in register pair HL.
0FDA-0FDB
LD (HL),30H
Save a 0 at the location of the input buffer pointer in register pair HL.
0FDC-0FDE
LD A,(40D8H)
Load register A with the value of the edit flag (stored at 40D8H).

NOTE: 40D8H-40D9H holds the temporary storage location.
0FDF
LD D,A
Load register D with the value of the edit flag in register A.
0FE0
RLA
Move the edit on/off bit in register A into the CARRY FLAG.
0FE1-0FE3
LD A,(40AFH)
Load register A with the value of the current number type flag.

Note: 40AFH holds the current number’s type flag as follows:
  • 2: Integer
  • 3: String
  • 4: Single precision
  • 8: Double precision
0FE4-0FE6
JUMP to 109AH if value is to be edited.
0FE7-0FE9
JUMP to 1092H if no edit.
0FEA-0FEB
CP 04H
Check to see if the current value in REG 1 is single or double precision by testing A – 04H. If A=04H it sets the ZERO FLAG. If A<04H then the CARRY FLAG will be set and if A>=04H then the NO CARRY FLAG will be set.
0FEC-0FEE
JUMP if the current value in REG 1 is single or double precision.
0FEF-0FF1
LD BC,0000H
Load register pair BC with zero.
0FF2-0FF4
Call the INTEGER TO ASCII routine at 1232F (which converts the integer in REG 1 to ASCII and stores the ASCII string in the buffer pointed to in HL).
0FF5-0FF7
LD HL,4130H
Load register pair HL with the starting address of the input buffer, which is at 16688.

NOTE: 4130H-4149H holds Internal print buffer.
0FF8
LD B,(HL)
Load register B with the character at the location of the input buffer pointer in register pair HL.
0FF9-0FFA
LD C,20H
Load register C with a space character.
0FFB-0FFD
LD A,(40D8H)
Load register A with the value of the edit flag (which is stored in 40D8H).

NOTE: 40D8H-40D9H holds the temporary storage location.
0FFE
LD E,A
Load register E with the value of the edit flag in register A.
0FFF-1000
AND 20H
Check the value of the edit flag in register A (by AND againt 0010 0000) to see if leading * are to be printed.