Page Customization:

Display OPCodes

Display Labels

These 3 pages are a breakdown of the Model I ROM, with comments to help you understand what is going on 0000H-0FFFFH / 1001H-2002H / 2003H-2FFFH. 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 2FFFH 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.

ROM Constants

The ROM was written by Bill Gates, Paul Allen, and M Davidoff on a PDP-10. Since the source code was cross-compiled, the authors put in some variables and constants

0000H-0004H – POWER UP ROUTINE – “START”

0000-0002 Disables the interrupts, clears the A register, then jumps to initialisation routine at 674H

↳ START

↳ SYNTAX

(RST 008H)

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 in 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)

0008 (RST 8H) 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

000BH-000CH – DISK ROUTINE – “WHERE”

↳ WHERE

000DH-000FH – DISK BOOTSTRAP – “$BOOT”

0010 (RST 10H) jumps to 1D78H 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

0010H-0012H – RST 10 – GET A CHARACTER FROM THE BUFFER

(RST 010H)

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 (C=1) if HL is pointing to a number and the Z flag will be SET if the character pointed to happens to be zero (ASCII 30H) or 3AH (“:”). The carry flag will be RESET (0) if the character is non-numeric. (BC and DE registers are unaffected) This routine can be used by CALLing 1D78H or RST l0H

0013H-0017H – INPUT ROUTINE – $GET

This routine Inputs a byte from an input device. When calling, DE = starting address of DCB of device. On exit, A = byte received from device, Z set if device ready. Uses AF.

↳ $GET

0018 (RST 18H) 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

↳ RST18

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)

001BH-001EH – DRIVER ENTRY ROUTINE – Part 1 – “PUT”

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.

↳ PUT

0020 (RST 20H) 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. (The NTF will be discussed in the arithmetic section.)

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 the ACCumulator (i.e., 4121H-4122H). It should be used with caution, however since the mode flag and ACCumulator can get out of phase particularly if some of the CALLS described here are used to load ACCumulator

0023H-0027H – DISK ROUTINE – “$CTL”

↳ $CTL

0028 (RST 28H) 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

(RST 028H)

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)

002BH-002FH – KEYBOARD ROUTINE – “$KBD”

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 A Register 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 SYS0 where the request code will be inspected and ignored, because system request codes must have bit 8 on. After inspection of the code, control is returned to the caller of 002B. Characters detected at 002B are not displayed. Uses DE, status, and A register

Of the 3 keyboard scanning routines, this is the most fundamental one. If no key is pressed when the CALL is executed, the code falls through with A = 00H. If you want to wait for a key to be pressed, you would use CALL 0049 or you would write a routine that jumps back to the call if A is 0.

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).

Scan Keyboard: Performs an instantaneous scan of the keyboard. If no key is depressed control is returned to the caller with in Register A 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 SYS0 where the request code will be inspected and ignored, because system request codes must have bit 8 on. After inspection of the code, control is returned to the caller of 002B. Characters detected at 002B are not displayed. Uses DE, status, and A register

↳ $KBD

Note: 4015H holds Keyboard DCB – Device type

0030 (RST 30H) 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

0033H-0037H – VIDEO ROUTINE – “$DSP”

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.

↳ $DSP

Note: 401DH holds Video DCB – Device type

0038 (RST 38H) This location will pass control to 4012H. This location is only used by a Disk system

(RST 038H)

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 SYSO 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

003BH-003FH – PRINTER ROUTINE – “$PRT”

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 A-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.

Character LPRINT routine. Same as 33H but outputs to line printer. (Contents of A Register will be printed.)

↳ $PRT

Note: 4025H holds Printer DCB – Device type

0040H-0042H – INPUT ROUTINE – “$KEYIN”

↳ $KEYIN

0046H-0048H – DRIVER ENTRY ROUTINE – Part 2 – “CIOJ”

0049H-004FH – KEYBOARD ROUTINE – “$KEY”

A call to 0049H returns as soon as any key on keyboard is pressed, exactly how the INKEY$ function works in BASIC. ASCII value for character entered is returned in A register. If you don’t want the program to hold while waiting for a key, you would use CALL 002BH instead.

Character input routine. This routine is the same as 2BH except that it will not return until a key is pressed, which often makes it often more useful than 2BH. Character is returned in the A Register (AF and DE used)

Wait For Keyboard Input: Returns as soon as any key on keyboard is pressed. ASCII value for character entered is returned in A- register. Uses A, status and DE registers

↳ $KEY

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.

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

0050H-005FH – KEYBOARD LOOKUP TABLE – “KEYTAB”

This is a table of control characters used by BASIC.

↳ KEYTAB

0060H-0065H – DELAY ROUTINE – “$PAUSE”

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.66. Register A is used.

↳ PAUSE

OR C78 B1

0066 is the location to which program control jumps when the RESET button is pressed (Non Maskable Interrupt address).5

↳ NMI

This is the location to which program control jumps when the RESET button is pressed (Non Maskable Interrupt address)

0069H-0074H – NMI INTERRUPT ROUTINE (RESET) – “$INITIO”

This part of the initialization routine checks to see if a disk drive is connected. If so, it will jump to 00H. (This is why the reset button will reinitialize DOS.)

0075H-0104H – INITIALIZATION ROUTINE – “INIT2”

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

>Note: 4080H-408DH is a division support routine.

Note: 4080H-408DH is a division support routine

This loads 40A7H with the I/O buffer location address 41E8H. (40A7H is the I/O buffer pointer and can be changed to relocate the buffer.)

Note: 40A7H-40A8H holds the input Buffer pointer

0091H-0104H – The rest of the initialization routine. First, it fills the RAM locations pointing to all 28 DOS BASIC commands, set them to pointo ?L3 ERROR, ask 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

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 lAl9H which is the entry point for the BASIC command mode

Note: 4152H-41A3H holds Disk Basic links

↳ LOPRTS

00A8H – VIDEO AND PRINTER ROUTINE

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).

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.

↳ MEMSIZ

↳ LOOPMM

OR L7C

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

↳ USEDEF

↳ STRSZD

Note: 40A0H-40A1H holds the start of string space pointer

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).

The “MEMORY SIZE” message is located here

↳ MEMMSG

012DH-0131H – ?L3 ERROR ROUTINE – “NAVERR”

↳ NAVERR

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

0132, 0135, 0138 These are the entry points for the POINT, SET and the RESET commands in that order, see Part 2 for more data on the graphics routines

↳ GRPHCS

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.

0135H-0137H – LEVEL II BASIC SET COMMAND – “SET”

↳ SET

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

↳ RESET

Common code for SET/RESET/POINT – A will be 0 if POINT, 80H if SET and 1 for RESET.

This is a suitable entry point for the graphics routines. (see Part 2)

↳ LOPMD3

↳ SHFTW

↳ PWR2

↳ FND4

↳ FINSTB

↳ FINPTB

↳ SBIT

↳ TBIT

019DH-01C8H – LEVEL II BASIC INKEY$ ROUTINE – “INKEY”

↳ INKEY

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.

↳ BUFCIN

Note: 4099H holds the last key pressed

↳ NULRT

Note: 40AFH holds current variable’s type flag

01C9H-01D2H – LEVEL II BASIC CLS ROUTINE – “CLS”

A CALL 1C9H 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.

↳ CLS

01D3H-01D8H – 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.

↳ RANDOM

01D9H-01F7H – CASSETTE ROUTINE

Output a pulse to the cassette recorder

↳ CTPULS

Delay loop between pulses

01F8H-01FDH – CASSETTE ROUTINE (TURN OFF CASSETTE) – “CTOFF”

↳ CTOFF

01FEH-0211H- CASSETTE ROUTINE (EVALUATE DRIVE NUMBER) – “CTON”

↳ CTON

0212H-021DH – CASSETTE ROUTINE (TURN ON CASSETTE)

“DEFDRV”

CALL 212H will select the cassette unit specified in A-Register and start the motor. Units are numbered from one. Put 00H in A Register to turn on cassette 1, or O1H to turn on cassette 2. All registers are used.

To use a ROM call to turn on the cassette, execute the following instructions: LD A,0 and then CALL 0212H

↳ DEFDRV

↳ CTCHG2

021EH-022BH – CASSETTE ROUTINE – “CTSTAT”

↳ CTSTAT

↳ CTCHG

Note: 403DH-4040H is used by DOS

Note: 403DH-4040H is used by DOS

022CH-0234H – CASSETTE ROUTINE (BLINK **) – “BCASIN”

Alternately displays and clears an asterisk in the upper right hand comer. Uses all registers.

↳ BCASIN

`SPACE`, else if the character in Register A is a

`SPACE`make it a *

0235H-0240H – CASSETTE ROUTINE (READ A BYTE) – “CASIN”

Read One Byte: Reads one byte from the currently selected unit. The byte read is returned in the A-register. All other registers are preserved

This routine will read a byte from tape. A CALL 235H will return with the byte read from tape in the A Register BC, DE and HL are unchanged

To use a ROM call to read a character from cassette (after the cassette has been turned on and leader and sync have been found), CALL 0235H. The input character will be in the A register. Again, the routine at 0235H must be called frequently enough to sustain the 500 baud rate if more than one character is to be read.

CASIN

CTB0

0241H-0260H – CASSETTE ROUTINE (READ A BIT) – “CTBIT”

Routine waits for timing pulse, and then performs a timing loop. When the time is up it tests the tape for a bit, which will be “1” if present and “0” if not. A CALL 241H is used by 235H eight times to input one byte.

0264 Writes the byte in the A Register to tape. BC, DE and HL are unchanged by a CALL 264H

↳ CTBIT

CB0

CB1

0261H-0263H – CASSETTE ROUTINE – “TWOCSO”

↳ TWOCSO

0264H-027DH – CASSETTE ROUTINE (WRITE A BYTE) – “CASOUT”

Writes the byte in the A Register to tape. BC, DE and HL are unchanged by a CALL 264H.

To use a ROM call to write a character onto cassette tape (after the cassette has been turned on and leader and sync have been recorded), load the character into the A Register And CALL 0264H. If more than one character is to be written, the CALL 0264H must be executed with sufficient frequency to sustain the 500 baud recording rate. The routine provides automatic timing.

↳ CASOUT

BYT1

027EH-0283H – CASSETTE ROUTINE

↳ BYT2

0284H-0292H – CASSETTE ROUTINE (TURN ON CASSETTE AND WRITE LEADER) – “CWRTON”

A call to 0284H writes a Level II leader on currently selected unit. The leader consists of 256 (decimal) binary zeros followed by a A5H. Uses the B and A registers.

↳ CWONWL

Load Register B with the number of bytes to be written

CSAV1

0293H-029EH – CASSETTE ROUTINE (TURN ON CASSETTE AND READ LEADER) – “CSRDON”

↳ CSRDON

Read Leader: Reads the currently selected cassette unit until an end of leader (A5) is found. An asterisk is displayed in the upper right hand corner of the video display when the end is found. Uses the A-register

Reads from tape until the leader is found, then keeps going until it is bypassed and the sync byte (ASH) is found, when it returns. DE, BC and HL are unchanged by this

↳ CSRDON+3

Save the current BASIC program pointer in Register Pair HL on the STACK

CLOD1

029FH-02A8H – CASSETTE ROUTINE

Places the double asterisk in the right top corner to show that the sync byte has been found

Load Register A with a * character. (“*” is 2AH)

02A9H-0329H – LEVEL II SYSTEM ROUTINE-ENTRY POINT – “ENBLK”

↳ ENBLK

Note: 40DFH-40E0H is also used by DOS

↳ SYSTEM

In NEWDOS 2.1, this is called during a SYSTEM operation

This location passes control to the routine used by the BASIC command SYSTEM

`BREAK`key was hit (because the Carry flag is now on), go to the Level II BASIC READY routine

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.

LOPHD

GETDT

↳ GETDT2

↳ LDATIN

0314H – Read 2 bytes from the tape into Register Pair HL – “CADRIN”

This routine is commonly 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

↳ CADRIN

031DH – Execute the Cassette Program which was Loaded – “GODO”

↳ GODO

Note: 40DFH-40E0H is also used by DOS

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.

032AH-0347H – OUTPUT ROUTINE – “OUTCH1” and “OUTDO”

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 and 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.

↳ OUTDO

In NEWDOS 2.1, this writes to the system output device

Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer

At this point, A is either +1, -1, or 0. The ROM handles this by testing for a positive number (1 = Cassette), and then a non-zero number (-1 = Printer), and then flows down (0 = Display) if neither of those apply

033AH-0347H – OUTPUT ROUTINE – “OUT2D”

A Print routine which 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

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.

- Backspace and erase previous character – 08H
- Carriage return and linefeed – 0DH
- Turn on cursor – 0EH
- Turn off cursor – 0FH
- Convert to 32 characters per line mode – 17H
- Backspace cursor – 18H
- Advance cursor one position – 19H
- Downward line feed – 1AH
- Upward line feed – 1BH
- Home (cursor to upper left corner) – 1CH
- Move cursor to beginning of current line – 1DH
- Erase from cursor position to end of line – 1EH
- Erase from cursor position to end of screen – 1FH

↳ OUT2D

Save the value in Register Pair DE on the STACK

Note: 40A6H holds the current cursor line position

0348H-0357H – VIDEO ROUTINE – “DSPPOS”

↳ DSPPOS

Note: 403DH-4040H is used by DOS

Note: 4020H-4021H holds Video DCB – Cursor location

0358H-0360H – KEYBOARD ROUTINE – “ISCHAR”

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

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

0361H-0383H – INPUT ROUTINE – “INLIN”

This is one of the general purpose input routines (see 5D9 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.

↳ INLIN

Note: 4099H holds the Last key pressed

Note: 40A6H holds the current cursor line position

In NEWDOS 2.1, this is the satrt of keyboard input

Note: 40A7H-40A8H holds the input Buffer pointer

Note: 40A7H-40A8H holds the input Buffer pointer

`BREAK`key was not pressed), zero all the status flags

0384H-038AH – KEYBOARD ROUTINE – “INCHR”

Waits for keypress

038BH-039BH – PRINTER ROUTINE – “FINLPT”

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 409BH – 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.

↳ FINLPT

Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer

Note: 409BH holds the printer carriage position

`ENTER`3E 0D

039CH-03C1H – PRINTER ROUTINE – “OUTLPT”

This is the LPRINT routine. All registers are saved. The byte to be printed should be in the A register.

↳ OUTLPT

↳ OUTDO

`LINE FEED`FE 0A

`CARRIAGE RETURN`3E 0D

↳ LZRNOT

Note: 409BH holds the printer carriage position

↳ LZRPOS

Note: 409BH holds the printer carriage position

03C2H-03E2H – DRIVER ENTRY ROUTINE – “CIO”

This routine is called from a RST 14 (with a device code of 01H in Register B), RST 1C (with a device code of 02H in Register B), and RST 24 (with a device code of 04H in Register B).

On entry, BC shoud contain the Device Control Block and A may contain (if needed) the output control/data

According to the original ROM notes, this is the Character I/O Linkage to Device Driver routine. On entry Register Pair DE to point at the Device Control Block and Register A will hold the output or control data, if any. On exit, the codes depend on whether a byte or a control code was passed. If this was an I/O operation, Register A will hold that input/output data byte. If this was a I/O control operation, Register A will hold the device status and the Z FLAG will be set if the device is ready.

↳ CIO

↳ CIORTN

03E3H-0457H – KEYBOARD DRIVER – “KEY”

This is the keyboard driver. It scans the keyboard and converts the bit pattern obtained to ASCII and stores it in the A register.

According to the original ROM notes, this is the Keyboard Driver. On exit, Register A to hold the data byte received (or 0 if none). On entry, [IX] should point to the DCB, which is laid out as follows:

- DCB + 0 = DCB Type
- DCB + 1 = Driver Address (LSB)
- DCB + 2 = Driver Addres (MSB)
- DCB + 3 = 0
- DCB + 4 = 0
- DCB + 5 = 0
- DCB + 6 = “K”
- DCB + 7 = “I”

↳ KEY

Note: 4036H-403CH is the keyboard work area

03FAH-040AH – Accept a Keyboard Downstroke and Convert it to ASCII – “KEYDWN”

↳ KEYDWN

↳ KEYDLP

040BH-0428H – Part of the Keyboard routine – “KEYFND”

We now have identified the key. Next we need to see if it is shifted

↳ KEYFND

0429H-043CH – Part of the Keyboard routine – “KEYNAL”

If we are here, the character was not alphanumeric, so need to check for special and/or shift

↳ KEYNAL

043DH-044AH – Part of the Keyboard routine – “KEYSPL”

This routine does a special key conversion via a table

↳ KEYSPL

↳ KEYNSF

044BH-044BH – Part of the Keyboard routine – “KEYRTN”

This routine will debounce the keyboard downstroke and return

↳ KEYRTN

0458H-058CH – DISPLAY DRIVER – “DSP”

This is the video driver. On entry, the character to be displayed should be in the C register. On exit, A would contain the character at the cursor (if called for an INPUT). This routine handles scrolling etc.

Register IX points to the DCB, so IX+0 = the DCB type, IX+1 = LSB of the Driver Address, IX+2 = MSB of the Driver Address, IX+3 = LSB of the Cursor Position, IX+4 = MSB of the Cursor Position, IX+5 = Cursor Character, IX+6 = “D”, and IX+7=”O”

According to the original ROM notes, this is the Display Driver. On exit, Register A to hold the character read from the new cursor position (if the routine was called to look for that). On entry, [IX] should point to the DCB, which is laid out as follows:

- DCB + 0 = DCB Type
- DCB + 1 = Driver Address (LSB)
- DCB + 2 = Driver Addres (MSB)
- DCB + 3 = Cursor Position Address (LSB)
- DCB + 4 = Cursor Position Address (MSB)
- DCB + 5 = Cursor Character
- DCB + 6 = “D”
- DCB + 7 = “O”

↳ DSP

↳ DSPGRP

↳ DSPRTN

049AH – Read the character at the current position of the display – “DSPRD”

↳ DSPRD

04A1H – Go to the beginning of the line – “DSPBOL”

↳ DSPBOL

04A6H – Handle graphic characters – “DSPHRC”

↳ DSPGRC

04AFH – Handle Space Compression characters – “DSPSPC”

04B8H – Turn the cursor on – “DSPCON”

↳ DSPCON

04BDH – Turn the cursor off – “DSPCOF”

↳ DSPCOF

04C0H – Home the cursor – “DSPHOM”

↳ DSPHOM

Note: 403DH-4040H is used by DOS

↳ DSPBSP

Note: 403DH-4040H is used by DOS

04DAH – Cursor Left – “DSPLFT”

↳ DSPLFT

Note: 403DH-4040H is used by DOS

04E7H – Cursor Down – “DSPDWN”

This is a space saver because if the cursor isn’t on the same line it needs to move down, so jumping here is also jumping to a CURSOR DOWN routine that was simply a fall-through from a wrap around

↳ DSPDWN

04ECH – Cursor Right – “DSPRHT”

↳ DSPRHT

Same trick as dealing with CURSOR DOWN if there was an overflow, this does a CURSOR UP if you back up too far

↳ DSPUP

04F6H – Set up 32-Character mode – “DSPETB”

↳ DSPETB

Note: 403DH-4040H is used by DOS

Note: 403DH-4040H is used by DOS

0506H – Process control characters – “DSPCTL”

↳ DSPCTL

0541H – Part of the Display routine – “DSPOUT”

Output the character held in Register A and move the cursor, scrolling the screen if necessary

↳ DSPOUT

Note: 403DH-4040H is used by DOS

↳ DSPOT2

0554H – Part of the Display routine – “DSPROL”

Scroll the screen upward by one line

↳ DSPROL

0564H – Part of the Display routine – “DSPCR”

Display a carriage return / line feed

↳ DSPCR

0573H – Part of the Display routine – “DSPEOL”

Erase to the end of the line

DSPEOL

057CH – Part of the Display routine – “DSPEOF”

Erase to the end of the frame

To use a ROM call to clear the video screen from (including) position N – where N is an integer between 0 and 1023 (decimal), inclusive, to the end of the display, Load the HL Register with the value 3C00H + N and then CALL 057CH

↳ DSPEOF

Clear to end of frame routine. To use this routine load the HL Register Pair with the screen address from which you want the erasing to start. The DE and A registers are used

↳ DSPERF

↳ DSPERA

058DH-0D8H – PRINTER DRIVER – “PRT”

According to the original ROM notes, this is the Printer Driver. On entry, Register C to hold the character to be sent to the printer, and [IX] should point to the DCB, which is laid out as follows:

- DCB + 0 = DCB Type
- DCB + 1 = Driver Address (LSB)
- DCB + 2 = Driver Addres (MSB)
- DCB + 3 = Lines Per Page (or 0 if top-of-page)
- DCB + 4 = Line Counter
- DCB + 5 = 0
- DCB + 6 = “P”
- DCB + 7 = “R”

↳ PRT

↳ PRTVT

↳ PRTFF

↳ PRTIT

↳ PRTIT2

↳ PRTOP

05D1H – Part of the Printer Routine – “PRTSTA”

Get printer status routine

A call to 05D1 will return the status of the line printer in the status Register As 0 if the printer is ready/selected, and non-zero if not ready, as follows:

- Bit 7 = Printer Busy. 1=Busy
- Bit 6 = Paper Status. 1= Out of paper.
- Bit 5 = Printer Ready. 1 = Ready.
- All other bits are not used.

05D9H-0673H – Part of the Keyboard Routine – “KEYIN”

Keyboard Line Handler Routine

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.

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

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

According to the original ROM comments, on entry, HL to point to the input line address in RAM and Register B to hold the maximum number of input characters to fetch. On exit, Register A should hold the number of characters entered

↳ KEYIN

↳ KLNNXT

`SPACE`

`SPACE`)

`BREAK`key

↳ KLNCHR

0619H – Part of the Display routine – “KLNCLR”

Clear the screen

↳ KLNCLR

0622H – Part of the Display routine – “KLNCNL”

Cancel the accumulated line

↳ KLNCNL

↳ KLNCAN

0630H – Part of the Display routine – “KLNBSP”

Backspace one character. On entry Register B to hold the number of characters received, and Register C to hold the size of the buffer

↳ KLNBSP

0641H – Part of the Display routine – “KLNETB”

Turn on 32 Character Mode

↳ KLNETB

0646H – Part of the Display routine – “KLNHT”

Process a horizontal tab

↳ KLNHT

↳ KLNHTL

0661H – Part of the Display routine – “KLNBRK”

Process a Carriage Return and Automatic Line Feed

↳ KLNBRK

↳ KLNCR

0674H-06D1H – INITIALIZATION ROUTINE – “INIT”

↳ INIT

↳ CLRAM

068BH – INITIALIZATION ROUTINE – “CHKMAN”

Check for a manual override

↳ CHKMAN

This is the beginning of the routine which boots a diskette

069FH – Bootstrap from Diskette – “BOOT”

↳ BOOT

↳ BOOTDL

This routine loads Drive 0, Track 0, Sector 0 into 4200H-4455H, and then jumps to 4200H

↳ BOOTLP

06CCH-06CEH – Alternative re-entry point into BASIC – “RESETR”

This is an alternative re-entry point into BASIC. A JP 6CCH is often better than a jump to 1A19H as the latter sometimes does strange things to any resident BASIC program

↳ RESETR

06D2H-0707H – ROM STORAGE LOCATION FOR DATA TO BE MOVED TO RAM BY THE INITIALIZATION PROCESS – “INITR”

↳ INITR

This is the keyboard DCB

This is the display DCB

This is the printer DCB

070BH – MATH!

The math routines in the Level II ROM are fairly complex because they have to be. The following is a brief-ish description of the overall intentions of the authors:

RAM Locations / Purpose

DFACLO 4 Four lowest orders for double precision FACLO 3 Low order of Mantissa, Middle Order of Mantissa, High Order of Mantissa FAC 2 Exponent, Temporary Complement of the Sign in the MSB ARGLO 7 Temporary location of second argument for double precision ARG 1 FBUFFR Buffer for FOUT Floating Point Formula

- The sign is the first bit of the mantissa
- The mantissa is 24 bits long
- THe binary point is to the left of the MSB
- The manitssa is positive, with a one assumed to be where the sign bit is
- The sign of the exponent is the first bit of the exponent
- The exponent is stored in excess of 80H (i.e., it is a signed 8 bit number with 80H added to it)
- An exponent of zero means the number is zero, and all other bytes are ignored
In memory a number looks like this:

- Bits 17-24 of the mantissa
- Bits 9-16 of the mantissa
- The sign is in Bit 7
- Bits 2-8 of the mantassa are in bits 6-0
- The exponent is stored as a signed number + 80H
- Bit 1 of the mantissa is always a 1
Calling Math Routines

To call a ONE argument routine, the argument should be in the FAC

To call a TWO argument routine, the first argument should be in BCDE and the second argument should be in the FAC

Regardless of which is desired, the result will be in the FAC

ROM routines with a “S” point to two argument operations which have (HL) pointing to the first argument instead of it being in BCDE. “MOVERM” is called to get the argument into the registers.

ROM routines with a “T” assume that the first argument is on the stack. “POPR” is used to get the arguments into the registers. Note: Never CALL a “T” routine, the return address will be confused with a number.

Stack Usage

The to LO’s are pushed first, and then the HO and finally the sign. The lower byte of each part is in the lower memory address, so when the number ios POPed into the registers, the higher order byte will be in the higher order register of the register pair (i.e., B, D, and H).

According to Vernon Hester, there are a whole lot of errors in ROM code for processing math. I have no hope of finding the code so I will put them here:

When a number is just under specific decimal magnitudes, the ROM prints a colon instead of 10

Example: 9999999999999999 / 1D12 + 3D-13 returns :000

070BH-070FH – SINGLE PRECISION ADDITION, ACCumulator = (HL) + ACCumulator – “FADDH”

Single-precision addition (ACCumulator=(HL)+ACC) involving a buffer pointed to by the HL Register Pair and ACCumulator (i.e., 4121H-4122H). This part of the program loads the BCDE registers with the value from the buffer, then passes control to 716H.

↳ FADDH21 80 13

↳ FADDS

0710H-0712H – SINGLE PRECISION SUBTRACTION, ACCumulator = (HL) – ACCumulator

“FSUBS”

Single-precision subtraction (ACC=(HL)-ACC). This loads the BCDE registers with the value from (HL), then passes control to 713H.

↳ FSUBS

0713H-0715H – SINGLE PRECISION SUBTRACTION, ACCumulator = BCDE – ACCumulator – “FSUB”

Single-precision subtraction (ACCumulator=BCDE-ACCumulator). The routine actually inverts ACCumulator (i.e., 4121H-4122H) and adds it to the contents of the BCDE registers which, in effect, is a subtraction. The result will be stored in the ACCumulator (i.e., 4121H-4122H).

Single Precision Subtract: Subtracts the single precision value in (BC/DE) from the single precision value in the ACCumulator. The difference is left in the ACCumulator

Single-precision subtraction (ACC=BCDE-ACC). The routine actually inverts the ACC 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 (ACC)

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.

↳ FSUB

0716H-0752H – SINGLE PRECISION ADDITION, ACCumulator = BCDE + ACCumulator – “FADD”

Single-precision addition (ACCumulator=BCDE+ACC). This routine adds two single-precision values and stores the result in the ACCumulator 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.

Single Precision Add: Add the single precision value in (BC/DE) to the single precision value in the ACCumulator. The sum is left in the ACCumulator

Single-precision addition (ACC=BCDE+ACC). This routine adds two singleprecision values and stores the result in the ACC area

Formula: FAC:=ARG+FAC

Routine ALTERS A,B,C,D,E,H,L

If INTFSF=1 the format of floating point numbers will be:

- Reg B – SIGN AND BITS 1-7 OF EXPONENT
- Reg C – Bit 8 of exponent ;and bits 2-8 of mantissa
- Reg D – Bits 9-16 of mantissa
- Reg E – Bits 17-24 of mantissa, and likewise for the ACCumulator format
- Note: The exponent for intel will be 7FH

↳ FADD

At this point we know that we are going to actually do the math, so the next step is to get the smaller number into the registers (BCDE) so we can just shift it rith and align the binary points of both numbers. If we do this, then we just add or subtract them bytewise.

At this point, the smaller number is in ABCD, so we proceed with the math.

↳ FADD1

If the numbers have the same sign, then we add them. if the signs are different, then we have to subtract them. we have to do this because the mantissas are positive. judging by the exponents, the larger number is in the ACCumulator, so if we subtract, the sign of the result should be the sign of the ACCumulator; however, if the exponents are the same, the number in the registers could be bigger, so after we subtract them, we have to check if the result was negative. if it was, we negate the number in the registers and complement the sign of the ACCumulator. (here the ACCumulator is unpacked) if we have to add the numbers, the sign of the result is the sign of the ACCumulator. so, in either case, when we are all done, the sign of the result will be the sign of the ACCumulator.

0754H-077CH – SINGLE PRECISION MATH ROUTINE – “FADD3”

This routine will subtract CDEB from ((HL)+0,1,2),0.

↳ FADD3

With that out the way, we need to make sure we have a positive mantissa (or else we will need to negate the number).

↳ FADFLT

This next routine normalizes CDEB. In doing so, ABCDE and HL are all modified. This routine shifts the mantissa left until the MSB is a 1.

↳ NORMAL

This routine will ZERO out the ACCumulator, changing only Register A in the process. A will exit as 0.

↳ ZERO

↳ ZERO0

077DH-07A7H – SINGLE PRECISION MATH SUPPORT ROUTINE – “NORM2”

↳ NORM2

If we are here, then we have a fully normalized result, so let us continue.

The “ROUND” routine rounds the result in CDEB and puts the result into the ACCumulator. All registers are affected. CDE is rounded up or down based on the MSB of Register B.

Vernong Hester has flagged an error in the rounding of math routines. In base 10, rounding to k-digits examines digit k+1. If digit k+1 is 5 through 9, then digit k is adjusted up by one and carries to the most significant digit, if necessary. If digit k+1 is less than 5, then digit k is not adjusted. This should not get muddled with the conversion of base 2 to base 10. Nevertheless, four divided by nine should be: .444444 and not .444445

↳ ROUND

↳ ROUNDB

07A8H-07B6H – SINGLE PRECISION MATH SUPPORT ROUTINE – “ROUNDA”

This is a subroutine within the ROUND round. This will add one to C/D/E.

↳ ROUNDA

07B2H – ?OV ERROR entry point – “OVERR”

↳ OVERR

07B7H-07C2H SINGLE PRECISION MATH ROUTINE – “FADDA”

This routine adds (HL+2),)(HL+1),(HL+0) to C,D,E. This is called by FADD and FOUT.

↳ FADDA

07C3H-07D6H – SINGLE PRECISION MATH ROUTINE – NEGR

This routine negates the number in C/D/E/B. CALLd by FADD and QUINT. Alters everything except Register H.

↳ NEGR

07D7H-07F7H – SINGLE PRECISION MATH ROUTINE – “SHIFTR”

This routine will shift the number in C/D/E right the number of times held in Register A. The general idea is to shift right 8 places as many times as is possible within the number of times in A, and then jump out to shift single bits once you can’t shift 8 at a time anymore. Alters everything except Register H.

↳ SHIFTR

↳ SHFTR1

If we are here, then we are good to shift 8 bytes at once. So B to E, E to D, D to C, and then Zero out C …

07E4 – SINGLE PRECISION MATH ROUTINE – “SHFTR2”

This routine will shift the number in C/D/E right the number of times held in Register A, but one byte at a time.

↳ SHFTR2

↳ SHFTR3

07F8H-07FBH – SINGLE PRECISION CONSTANT STORAGE LOCATION

– “FONE”

↳ FONE

07FCH-0808H – SINGLE PRECISION CONSTANTS STORAGE LOCATION 2 – “LOGCN2”

↳ LOGCN2

0809H-0846H – LEVEL II BASIC LOG ROUTINE – “LOG”

The LOG(n) routine, (ACCumulator=LOG (ACCumulator)). This routine finds the natural log (base E) of the single precision value in the ACCumulator area.

The result is returned as a single precision value in the ACCumulator

To use a ROM call to find LOG(n), where X is a positive single precision variable, store the value of n 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.

Vernon Hester has identified a bug in the LOG() routine. Regardless of the base, if the argument is 1 then the logarithm is zero, if the argument is > 1 then the logarithm is positive, and if the argument is > 0 and < 1 then the logarithm is negative. However, if the argument is just under 1, the ROMâ€™s LOG function produces a positive value. e.g., 10 PRINT LOG(.99999994)

↳ LOG

The next two instructions are commented in the original ROM source code as: Get SQR(.5)

The next two instructions save SQR(.5) to the STACK

The next two instructions restore SQR(.5) from the STACK

The next two instructions get SQR(2)

The next two instructions are commented in the original ROM source code as: Get -1/2

The instructions are commented in the original ROM source code as: Get LN(2)

↳ MULLN2

The original ROM source code had a jump to the muptlication routine; but to save bytes, the ROM was restructured to just fall into the MULTiplocation routine instead.

0847H-0891H – SINGLE PRECISION MULTIPLICATION, – “FMULT”

Single-precision multiplication (ACCumulator=BCDE*ACC or ACC = ARG * FAC)).

Multiplies the current value in the ACCumulator by the value in (BC/DE). the product is left in the ACCumulator.

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.

Single Precision Multiply Multiplies the current value in the ACCumulator by the value in (BC/DE). the product is left in the ACCumulator

This routine alters every Register.

↳ FMULT

↳ FMULT2

The original source code explains what is being done next. The product will be formed in C/D/E/B. This will be in C/H/L/B part of the time in order to use the “DAD” instruction. At FMULT2, we get the next byte of the mantissa in the ACCumulator to multiply by, which is tracked by HL and unchanged by FMULT2. If the byte is zero, we just shift the product 8 bits to the right. This byte is then shifted right and saved in Register D. The CARRY FLAG determines if we should add in the second factor, and, if we do, we add it to C/H/L. Register B is only used to determine which way we round. We then shift C/H/L/B right one to get ready for the next time through the loop. Note: The CARRY is shifted into the MSB of Register C. Register E has the count to determine when we have looked at all the bits of Register D.

↳ FMULT4

↳ FMULT5

↳ POPHRT

0892H-0896H – SINGLE PRECISION MATH ROUTINE – “FMULT3”

This is accomplished by a circular shift of BC/DE one byte – B is lost, C is replaced by A

This is a multiply by zero, where we just shift everything 8 bits to the right.

↳ FMULT3

0897H-08A1H – SINGLE PRECISION MATH ROUTINE

– “DIV10”

This routine divides the ACCumulator by 10. Every Register is used.

↳ DIV10

↳ FDIVT

With the numbers in their places, we now just fall into the floating division routine.

08A2H-0903H – SINGLE PRECISION DIVISION – “FDIV”

Single-precision division (ACCumulator=BCDE/ACCumulator or ACC = ARG / ACC). If ACCumulator=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 the ACCumulator. The result is returned in the ACCumulator. Every register is used.

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.

↳ FDIV

08AE

INC (HL)34

At this point, the memory locations are set up, and it’s time to get to work. According to the original ROM source:

The numerator will be kept in Registers B/H/L. The quotient will be formed in Registers C/D/E. To get a bit of the quotient, we first save Registers B/H/L on the stack, and then subtract the denominator that we saved in memory. The CARRY FLAG will indicate whether or not Registers B/H/L was bigger than the denominator. If Registers B/H/L are bigger, the next bit of the quotient is a one. To get the old Registers B/H/L off the stack, they are POPped into the PSW. If the denominator was bigger, the next bit of the quotient is zero, and we get the old Registers B/H/L back by POPping them off the stack. We have to keep an extra bit of the quotient in FDIVG+1 in case the denominator was bigger, in which case Registers B/H/L will get shifted left. If the MSB of Register B is one, it has to be stored somewhere, so we store it in FDIVG+1. Then the next time through the loop Registers B/H/L will look bigger because it has an extra High Order bit in FDIVG+1. We are done dividing when the MSB of Register C is a one, which occurs when we have calculated 24 bits of the quotient. When we jump to ROUND, the 25th bit of the quotient (whcih is in the MSB of Register A) determines whether we round or not. If initially the denominator is bigger than the numerator, the first bit of the quotient will be zero. This means we will go through the divide loop 26 times, since it stops on the 25th bit after the first non-zero bit of the exponent. So, this quotient will look shifted left one from the quotient of two numbers in which the numerator is bigger. This can only occur on the first time through the loop, so Registers C/D/E are all zero. So, if we finish the loop and Registers C/D/E are all zero, then we must decrement the exponent to correct for this.

↳ FDIV1

↳ FDIV2

08DD

DEC A3C

0907H-0913H – DOUBLE PRECISION MATH ROUTINE – “MULDVS”

This routine is to check for special cases and to add exponents for the FMULT and FDIV routines. Registers A, B, H and L are modified.

↳ MULDVS

↳ MULDVA

0914H-0930H – SINGLE PRECISION MATH ROUTINE – “MULDIV”

↳ MULDIV

↳ DCXHRT

0931H-093DH – SINGLE PRECISION MATH ROUTINE – “MLDVEX”

This routine is called from EXP. If jumped here will checks if ACC=0. If so, the Z flag will be set

↳ MLDVEX

↳ MULDV1

093EH-0954H – SINGLE PRECISION MATH ROUTINE – “MUL10”

This routine multiplies the ACCumulator by 10. Every register is modified.

↳ MUL10

0955H-0963H – SINGLE PRECISION MATH ROUTINE – “SIGN”

Puts the SIGN of the ACCumulator into Register A. Only Register A is modified by this routine; the ACCumulator is left untouched.

To take advantage of the RST instructions to save bytes, FSIGN is defined to be an RST. “FSIGN” is equivalent to “call sign” the first few instructions of SIGN (the ones before SIGNC) are done in the 8 bytes at the RST location.

↳ SIGN

↳ FCOMPS

↳ ICOMPS

“SIGNS”

0964H-0976H – SINGLE PRECISION MATH ROUTINE – “FLOAT”

This routine will take a signed integer held in Register A and turn it into a floating point number. All registers are modified.

↳ FLOAT

This routine will float the singed number in B/A/D/E. All registers are modified.

0977H-0989H – LEVEL II BASIC ABS() ROUTINE – “ABS”

ABS routine (ACCumulator=ABS(ACCumulator)) 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 (the ACCumulator) to its positive equivalent. The result is left in the ACCumulator. 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. All registers are modified.

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.

ABS routine (ACC=ABS(ACC)) input and output can be integer, single-precision or double-precision, depending on what is placed in the NTF (NTF=2, 4 or 8). (For a definition of NTF, see Part 2.)

Absolute Value: Converts the value in Working Register Area 1 (ACCumulator) to its positive equivalent. The result is left in the ACCumulator. If a negative integer greater than 2**15 is encountered, it is converted to a single precision value. The data type or mode flag (40AF) will be updated to reflect any change in mode

↳ ABS

This routine will negate any value in the ACCumulator. Every Register is affected.

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

This routine will negate the single or double precision number in the ACCumulator. Registers A, H, and L are affected.To use this routine, the number must already be PACKed.

↳ NEG

098AH-0993H – LEVEL II BASIC SGN() ROUTINE – “SGN”

SGN function (ACCumulator=SGN(ACCumulator)). After execution, NTF=2 and ACCumulator=-l, 0 or 1 depending on sign and value of ACC before execution. Registers A, H, and L are affected.

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, s-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.

SGN function (ACC=SGN(ACC)). After execution, NTF=2 and ACC=-l, 0 or 1 depending on sign and value of ACC be fore execution. 0994 This routine checks the sign of the ACC. NTF must be set. After execution A register=00 if ACC=0, A=01 if ACC > 0 or A=FFH if A < 1. The Flags are also valid

This routine will convert a signed number (held in Register A) into an integer.

↳ CONIA

0994H-09A3H – LEVEL II BASIC MATH ROUTINE – “VSIGN”

This routine checks the sign of the ACCumulator. NTF must be set. After execution A register=00 if ACCumulator=0, A=01 if ACC > 0 or A=FFH if A < 1. The Flags are also valid.

↳ VSIGN

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

This routine finds the sign of the value held at (HL). Only Register A is altered.

↳ ISIGN

09A4H-09B0H – SINGLE PRECISION MATH ROUTINE – “PUSHF”

Move ACCumulator To STACK: Moves the single precision value in the ACCumulator to the STACK. It is stored in LSB/MSB/Exponent order. Registers D and E are affected. Note, the mode flag is not tested by the move routine, it is simply assumed that ACCumulator contains a single precision value

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.

↳ PUSHF

09B1H-09BEH – SINGLE PRECISION MATH ROUTINE – “MOVFM”

This routine moves a number from memory (pointed to by HL) into the ACCumulator — (ACCumulator=(HL)). All registers except Register A are affected, with HL = HL + 4 on exit.

↳ MOVFM

This routine loads the ACC with the contents of the BC and DE Register Pairs. (ACC=BCDE). Only Registers D and E are modified.

Move SP Value In BC/DC Into ACCumulator: Moves the single precision value in BC/DE into ACCumulator. HL is destroyed BC/DE is left intact. Note – the mode flag is not updated!

↳ MOVFR

09BFH-09CAH – SINGLE PRECISION MATH ROUTINE – “MOVRF”

This routine is the opposite of the 09B4H routine. It loads four bytes from ACCumulator (single-precision) into the BC/DE Register Pairs. Only Register A is unchanged.

Loads A SP Value From ACCumulator Into BC/DE: Loads a single precision value from ACCumulator into BC/DE. Note, the mode flag is not tested by the move routine. It is up to the caller to insure that ACCumulator actually contains a single precision value

This routine is the opposite of the 9B4H routine. It loads four bytes from the ACC (single-precision) into the BC and DE Register Pairs. (BCDE=ACC). A is unchanged

Load A SP Value Into BC/DE: Loads a single precision value pointed to by HL into BC/DE. Uses all registers

On Exit, HL = HL + 4

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

↳ MOVRM

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

↳ GETBCD

↳ INXHRT

09CBH-09D1H – SINGLE PRECISION MATH ROUTINE – “MOVMF”

This routine is the opposite of the 09B1H routine. It loads the number from the ACCumulator to the memory location pointed to by HL. ((HL)=ACC). Modifies all Registers except for Register C

↳ MOVMF

Data move routine. This moves four bytes from the location pointed to by DE into the location pointed to by HL. ((HL)=(DE)). Modifies all Registers except for Register C

↳ MOVE

09D2H-09DEH – MOVE VALUE POINTED TO BY HL TO THE LOCATION POINTED TO BY DE – “MOVVFM”

This is the VARIABLE MOVE routine which moves the number of bytes specified in the variable type flag (40AFH) from the address in DE to the address in HL. Uses A, B, DE and HL.

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))

↳ MOVVFM

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

↳ VMOVE

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))Moves contents of B-register bytes from the address in DE to the address given in HL. Uses all registers except C

↳ MOVE1

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)

09DFH-09F3H – SINGLE PRECISION MATH ROUTINE – “UNPACK”

This routine “UNPACKS” the ACCumulator and the Registers. Registers A, C, H, and L are altered.

When the number in the ACCumulator is unpacked, the assumed one in the mantissa is restored, and the complement of the sign is placed in ACCumulator+1.

↳ UNPACK

INC HL23

09F4H-09FBH – LEVEL II BASIC MATH ROUTINE – “VMOVFA”

This routine moves a number of bytes (the number depending on the value stored in the VALTYPE) from (HL) to the ACCumulator. All Registers except C are affected.

↳ VMOVFA

09FCH-0A0BH – LEVEL II BASIC MATH ROUTINE – “VMOVAF”

This is the opposite of 9F4H. This routine moves a number of bytes (the number depending on the value stored in the VALTYPE) from the ACCumulator to (HL). All Registers except C are affected.

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

0A0CH-0A25H – SINGLE PRECISION COMPARE – “FCOMP”

According to the original ROM source code, this routine will compare two single precision numbers. On Exit, A=1 if ARG < ACCumulator, A=0 if ARG=Accmulator, and A=-1 if ARG > ACCumulator. This routine exits with the CARRY FLAG on. Alters Registers A, H, and L.

Single-precision compare. Compares ACCumulator with the contents of BCDE registers. After execution of this routine, the A Register will contain: A=0 if ACCumulator=BCDE, A=1 if ACC>BCDE or A=FFH if ACC<BCDE.

Single Precision Comparison: Algebraically compares the single precision value in (BC/DE) to the single precision value ACCumulator. The result of the comparison is returned in the A and status as: IF (BC/DE) > ACCumulator A = -1, IF (BC/DE) < ACCumulator A = +1, IF (BC/DE) = ACCumulator A = 0

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.

↳ FCOMP

↳ FCOMPD

0A26H-0A38H – Part of the SINGLE PRECISION COMPARISON ROUTINE – “FCOMP2”

0A39H-0A48H – INTEGER COMPARISON ROUTINE

– “ICOMP”

According to the original ROM source code, this routine will compare two integers. On Exit, A=1 if (DE) < (HL), A=0 if (DE)=(HL), and A=-1 if (DE) > (HL). Alters only Register A.

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.

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

Algebraically compares two integer values in DE and HL. The contents of DE and HL are left intact. The result of the comparison is left in the A Register and status register: If DE > HL A = -1, IF DE < HL A = +1, IF DE = HL A = 0

↳ ICOMP

0A49H-0A77H – DOUBLE PRECISION COMPARISON ROUTINE – “DCOMPD”

According to the original ROM source code, this routine will compare two double precision numbers. On Exit, A=1 if ARG < ACCumulator, A=0 if ARG=Accmulator, and A=-1 if ARG > ACCumulator. Every register is affected.

Double-precision compare. Compares ACCumulator with the ARG (a/k/a REG 2). After execution the A Register will contain: A=0 if ACCumulator=ARG (a/k/a REG 2), A=1 if ACC > ARG (a/k/a REG 2) or A=FFH if ACC < ARG (a/k/a REG 2). S and Z flags are valid.

↳ DCOMPD

Note: 4127H-412EH holds ARG (a/k/a REG 2)

↳ DCOMP1

0A78H-0A7EH – DOUBLE PRECISION COMPARE – “DCOMP”

According to the original ROM source code, this routine will compare two double precision numbers, but is the opposite of the ICOMP, FCOMP, and XDCOMP routines. This one swaps ARC and ACC, so on Exit, A=1 if ARG > ACCumulator, A=0 if ARG=Accmulator, and A=-1 if ARG < ACCumulator. Every register is affected.

Double-precision compare. This compare is the opposite of the A4FH compare. It compares the ARG (a/k/a REG 2) 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.

Double Precision Compare: Compares the double precision value in the ACCumulator to the value in ARG (a/k/a REG 2). Both Register areas are left intact. The result of the comparison is left in the A and status registers as: IF ACCumulator > ARG (a/k/a REG 2) A = -1, IF ACCumulator < ARG (a/k/a REG 2) A = +1, IF ACCumulator = ARG (a/k/a REG 2) A = 0

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.

↳ DCOMP

0A7FH-0AB0H – LEVEL II BASIC CINT ROUTINE – “FRCINT”

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. Every register is affected. No rounding is performed

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.

↳ FRCINT

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

0A8EH – LEVEL II BASIC CONVERSION ROUTINE – “CONIS”

This routine will convert a single precision number to an integer. Every register is affected.

↳ CONIS

↳ CONIS1

0A9AH – LEVEL II BASIC CONVERSION ROUTINE – “MAKINT”

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 the ACCumulator so it is ACCumulator = (HL) with VALTYPE set accordingly

↳ VALINT

↳ CONISD

Note: 40AFH holds Current number type flag. This is the entry point from the CONDS routine

0AA3H – LEVEL II BASIC CONVERSION ROUTINE – “CONIS2”

↳ CONIS2

NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value ACCumulator.

The results are stored in A as follows:

- A=0 if ACCumulator = BCDE
- A=1 if ACCumulator>BCDE; and
- A=FFH if ACCumulator<BCDE.

0AB1H-0ACBH – LEVEL II BASIC CSNG ROUTINE – “FRCSNG”

Force the number in the ACCumulator to be a single-precision number. Every register is affected.

CSNG routine. Takes value from ACC and converts it to single-precision. The result is put in ACC and NTF contains 4.

CSNG routine. Takes value from ACC and converts it to single-precision. The result is put in ACC and NTF contains 4

Integer To Single: The contents of ACCumulator are converted from integer or double precision to single precision. All registers are used

↳ FRCSNG

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

0AB9 – LEVEL II BASIC NUMBER CONVERSION ROUTINE – “CONSD”

Convert a double-prevision number to single-precision. Every register is affected.

↳ CONSD

0ACCH-0ADAH -LEVEL II BASIC NUMBER CONVERSION ROUTINE – “CONSI”

Convert Integer to Single Precision. Every register is affected.

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.

↳ CONSI

↳ CONSIH

0ADBH-0AEDH – LEVEL II BASIC CDBL ROUTINE – “FRCDBL”

CDBL routine. Takes a value from ACCumulator (regardless of integer or single precision) and convert it to double-precision. The result will be in ACC and NTF will be 8.

↳ FRCDBL

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

0AE3H – LEVEL II BASIC CDBL ROUTINE – “CONDS”

Convert a single precision number to double precisions. Modifies Registers A, H, and L.

↳ CONDS

Note: 411DH-4124H holds ACCumulator

↳ VALDBL

0AEEH-0AF3H – LEVEL II BASIC MATH ROUTINE – “VALSNG”

↳ VALSNG

3E 04

0AF4H-0AFAH – LEVEL II BASIC MATH ROUTINE – “CHKSTR”

This routine will force the ACCUmlator to be a STRING. Only Register A is modified.

↳ CHKSTR

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

0AF6 – ?TM Error Routine – “TMERR”

↳ TMERR

This is the entry point for the TM ERROR

0AFBH-0B1EH – LEVEL II BASIC MATH ROUTINE – “QINT”

This routine is a quick “Greatest Integer” function. Registers A-E are affected.

The result of INT(ACCumulator) is left in C/D/E as a signed number

This routine assumes that the number in the ACCumulator is less than 8,388,608 (i.e., 2^23) and that the exponent of the ACCumulator is held in Register A on entry.

This routine can also be used to reset the BC and DE Register Pairs if the A Register contains 0. (XOR A before calling this routine).

↳ QINT

The original ROM source code has this to say about the next set of instructions:

The hard case in 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 and 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 and the net effect is that we get the absolute value of int(fac) in C/D/E. C/D/E is then negated if the original number was negative so the result will be signed.

0BlFH-0B25H – LEVEL II BASIC MATH ROUTINE – “QINTA”

↳ QINTA

↳ DCXBRT

0B26H-0B58H – LEVEL II BASIC FIX ROUTINE

– “FIX”

This is the FIX(n) routine. It returns SGN(n)*INT(ABS(n))

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 the ACCumulator. The result is stored in the ACCumulator 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.

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)

Floating To Integer: Unconditionally truncates the fractional part of a floating point number in the ACCumulator. The result is stored in the ACCumulator and the type flag is set to integer

↳ FIX

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

0B37H – LEVEL II BASIC INT( ROUTINE – “VINT”

Return Integer: Returns the integer portion of a floating point number. Every flag is affected. 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 the ACCumulator

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

According to Vernon Hester, there is are a number of bugs in this routine.

First, INT(value) should produce a result equal to or less than value. However, if the value is double-precision (by definition), the ROM rounds value to single-precision first, then performs the INT function. e.g., PRINT INT(2.9999999) produces 3 instead of 2.

Next, INT(value) should never overflow. However, if the value is double-precision 32767.9999#, the ROM overflows.

Next, INT(value) should produce a result equal to or less than value. However, if the value is double-precision equal to ?2″n+2″(n-7) where n is an integer >14, the ROM produces an incorrect value. e.g., PRINT INT(?44800#) produces ?45056

↳ VINT

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

↳ INT

0B59H-0B9DH – LEVEL II BASIC MATH ROUTINE – “DINT”

Greated Integer function for double-precision numbers. All registers are affected.

↳ DINT

↳ DINT1

↳ DINT2

↳ DINTFO

↳ “DINTFO”

0BA0H-0BA9H – LEVEL II BASIC MATH ROUTINE – “DINTA”

↳ DINTA

↳ DINTA1

0BAAH-0BC6H – LEVEL II BASIC MATH ROUTINE – “UMULT”

This is the integer multiply routine for multiplying dimensioned array. It will calculate DE = BC * DE. If there is an overflow, a ?BS ERROR will get thrown. Every register except HL is affected.

↳ UMULT

0BAF

OR C78 B1

↳ UMULT1

↳ UMULT2

↳ MULRET

The next bunch of routines are the integer arithmetic routines. According to the original ROM source code, the conventions are.

- Integer variables are 2 byte signed numbers, with the LSB coming first
- For one argument functions, the argument is in (HL) and the results are put into (HL)
- For two argument operations, the first argument is in (DE), the second in (HL), and the restuls are left in the ACCumulator and, if there was no overflow, (HL). If there was an overflow, then the arguments are converted to single precision.
- When integers are stored in the ACCumulator, they are stored at FACLO+0 and FACLO+1, with VALTYPE=2

0BC7H-0BD1H – INTEGER SUBTRACTION – “ISUB”

Integer subtract. (ACCumulator=DE-HL) The result is returned in both ACCumulator and, if there was no overflow, 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 the ACCumulator 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.

Every register is affected.

Integer Subtraction: Subtracts the value in DE from the value in HL. The difference is left in the HL Register Pair. DE is preserved. In the event of underflow, both values are converted to single precision and the subtraction is repeated. The result is left in the ACCumulator and the mode flag is updated accordingly

↳ ISUB

0BD2H-0BF1H – INTEGER ADDITION – “IADD”

Integer addition (ACCumulator=DE+HL), where ACCumulator = 4121H-4122H. After execution NTF=2, or 4 if overflow has occurred, in which case the result in the ACCumulator will be single-precision. The result is returned in both ACCumulator 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 the ACCumulator and the mode flag would be updated.

Every register is affected.

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).

↳ IADD

↳ IADDS

0BF2H-0C1EH – INTEGER MULTIPLICATION – “IMULT”

Integer multiply. (ACCumulator (and HL) =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 the ACCumulator.

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.

↳ IMULT

0BFE

LD C,L44

↳ IMULT1

The next 6 instruction are to roate the first argument left one to see if we need to add BC to it or not. If the NC FLAG is set, then we don’t add in BC. Otherwise we do.

↳ IMULT2

This is the entry from IDIV. The next instructions test to see if the result is => 32768 or is -32768.

↳ IMLDIV

0C1FH-0C34H – LEVEL II BASIC MATH ROUTINE – “IMULT3”

↳ IMULT3

↳ IMULT5

↳ FMULTT

0C37H-0C44H – LEVEL II BASIC MATH ROUTINE – “IMULT4”

↳ IMULT4

0C45H-0C5AH – LEVEL II BASIC MATH ROUTINE – “IMULDV”

This is the integer division routine HL = DE / HL. The remainder will be left in DE and the quotient will be left in HL. Every register is affected.

↳ IMULDV

↳ INEGH

↳ INEGA

Negate HL routine. This routine changes the sign of the HL Register Pair and stores it in the ACC. (HL=ACCumulator=-HL) The result is returned in both the HL Register Pair and the ACC.

↳ INEGHL

0C5BH-0C6FH – LEVEL II BASIC MATH ROUTINE – “INEG”

Integer Negation Routine. All registers are altered.

↳ INEG

↳ INEGAD

DOUBLE PRECISION ROUTINES

The next bunch of routines are the double precision arithmetic routines. According to the original ROM source code, the conventions are.

- Double prevision numbers are 8 bytes long: The first 4 bytes are 32 low order bits of precision and the last 4 bytes are are in the same format as single precision numbers. The lowest order byte comes first in RAM.
- For one argument gunctions: The argument is in the ACCumulator, and the results is put there too.
- For two argument operations, the first argument is in the ACCumulator and the second argument is in ARG-7,-6,-5,-4,-3,-2,-1,-0. ARGLO=ARG-7. The result is left in the ACCumulator.
- Note that the order of the numbers is reversed from integers and single precisions values

0C70H-0C76H – DOUBLE PRECISION SUBTRACTION – “DSUB”

Double-precision subtraction (ACCumulator = ACCumulator – ARG).

Subtracts the double precision value in ARG (a/k/a REG 2) from the value in the ACCumulator. The difference is left in the ACCumulator.

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.

Vernon Hester has flagged a bug. Double-precision subtraction should produce an difference accurate to 16 digits. However, the difference resulting from doubleprecision subtraction is erroneous when the smaller operandâ€™s value is significantly less than the larger operandâ€™s value

Example: In the code Y# = .20# : X# = 1D16 : J# = X# – Y# : PRINT J# – X# J# is incorrect and J#-X# shows a positive result when it is negative.

↳ DSUB

0C77H-0CCEH -DOUBLE PRECISION ADDITION – “DADD”

Double-precision addition (ACCumulator=ACCumulator+ARG (a/k/a REG 2)).

Adds the double precision value in ARG (a/k/a REG 2) to the value in the ACCumulator. Sum is left in the ACCumulator. All registers are affected.

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.

↳ DADD

Next we are going to switch ARG and the ACCumulator.

↳ DADD1

↳ DADD2

0CCFH-0D1FH – DOUBLE PRECISION MATH ROUTINE – “DADD3”

0CD8H – DOUBLE PRECISION MATH ROUTINE – “DNORML” and “DNORM1”

↳ DNORML

↳ DNORM2

0CF6H – Part of the “DNORML” and “DNORM1” Routine

↳ DNORM3

↳ DNORM5

0D0EH – DOUBLE PRECISION MATH ROUTINE – “DROUND” and “DROUNB”

This routine will round the ACCumulator. Registers A, B, H, and L are affected.

↳ DROUND

↳ DROUNB

0D1C

DEC HL2B

0D20H-0D32H – DOUBLE PRECISION MATH support routine – “DROUNA”

↳ DROUNA

Note: 411DH-4124H holds ACCumulator

↳ DRON1

0D33H-0D44H – DOUBLE PRECISION MATH ROUTINE – “DADDAA” and “DADDA”

↳ DADDAA

Note: 4127H-412EH holds ARG (a/k/a REG 2)

↳ DADDFO

Note: 411DH-4124H holds ACCumulator

↳ DADDS

↳ DADDLS

0D45H-0D56H – DOUBLE PRECISION MATH ROUTINE – “DADDAS”

This routine subtracts numbers in the pure version. This needs to be done in two subroutines since the ROM cannot be modified.

↳ DADDAS

Note: 4127H-412EH holds ARG (a/k/a REG 2)

↳ DADDFS

Note: 411DH-4124H holds ACCumulator

↳ DADDSS

↳ DADDLS

0D57H-0D68H – DOUBLE PRECISION MATH ROUTINE – “DNEGR”

This routine will negate the signed number held in the ACCumulator. Registers A, B, C, H, and L are affected. This routine is called by DADD and DINT.

↳ DNEGR

↳ DNEGR1

0D69H-0D8FH – DOUBLE PRECISION MATH ROUTINE – “DSHFTR”

This routine wwill shift the double precision value held in the ACCumulator to the right once.

↳ DSHFTR

↳ DSHFR1

↳ DSHFRM

↳ DSHFR2

0D69H-0D8FH – DOUBLE PRECISION MATH ROUTINE – “DSHFR3”

↳ DSHFR3

↳ DSHFR4

↳ DSHFRA

↳ DSHFR5

0D90H-0D96H – DOUBLE PRECISION MATH ROUTINE – “DSHFRB”

This is the entry from DADD and DMULT.

↳ DSHFRB

0D97H-0DA0H – DOUBLE PRECISION MATH ROUTINE – “DSHFLC”

This routine will rotate the ACCumulator left one. Register A, C, H, and L are affected.

↳ DSHFLC

↳ DSHFTL

0DA1H-0DD3H – DOUBLE PRECISION MULTIPLICATION – “DMULT”

Double-precision multiplication (ACCumulator=ACC*ARG (a/k/a REG 2)).

Multiplies the double precision value in the ACCumulator by the value in ARG (a/k/a REG 2). The product is left in the ACCumulator.

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.

↳ DMULT

↳ DMULT2

↳ DMULT3

↳ DMULT4

0DCCH – DOUBLE PRECISION MULTIPLICATION Support Routine – “DMULT5”

This routine handles multiplying by zero.

↳ DMULT5

0DD4H-0DDBH – DOUBLE PRECISION CONSTANT STORAGE AREA – “DTEN” and “FTEN”

↳ DTEN

↳ FTEN

0DDCH-0DE4H – DOUBLE PRECISION MATH ROUTINE – “DDIV10”

Double precision divide routine. Divides the ACCumulator by 10. All registers are affected.

↳ DDIV10

Note: 4127H-412EH holds ARG (a/k/a REG 2)

0DE5H-0E38H – DOUBLE PRECISION DIVISION – “DDIV”

Double-precision division (ACCumulator=ACC / ARG).

Divides the double precision value in the ACCumulator by the value in ARG (a/k/a REG 2). The quotient is left in the ACCumulator. All registers are affected

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.

According to Vernon Hester, there is a bug this routine. Double-precision division should return a zero quotient when the dividend is zero. However, when the dividend is zero and the divisor is less than .25#, the ROMâ€™s double-precision division produces an non-zero quotient. e.g., PRINT 0 / .24# produces a quotient of 1.171859195766034D-38. If the divisor is 2.938735877055719D-39 then the quotient is .5

Another bug is that double-precision division should perform correctly for absolute values that are from 2.938735877055719D-39 to 1.701411834604692D+38. If the divisor is the minimum magnitude or the minimum magnitude times 2, then double-precision division errors.

10 Z# = 1 / (2^125 + 2^125) * .25 ‘This values Z# with 2.938735877055719D-39

20 PRINT 1 / Z# â€˜displays 2.938735877055719D-39 instead of overflow

↳ DDIV

0DF0

INC (HL)34

↳ DDIV1

↳ DDIV2

0E18

DEC A3C

Note: 411DH-4124H holds ACCumulator

0E39H-0E4CH – DOUBLE PRECISION MATH ROUTINE – “DMULDV”

This routine will transfer the double prevision number held in the ACCumulator to FBUFFR for the DMULT and DDIV routines. All registers are affected.

↳ DMULDV

↳ DMLDV1

0E4DH-0E64H – LEVEL II BASIC MATH ROUTINE – “DMUL10”

This routine multiplies the current double-precision value by 10 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. All registers are affected

↳ DMUL10

0E65H-0F88H – ASCII to Double Precision Converter – “FINDBL”

This routine converts an ASCII string (pointed to by HL) to a double-precision value and stores it in the ACCumulator. The NTF is fixed accordingly. The string must be terminated with a , or zero byte. Note that the ARG (a/k/a REG 2) 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. All registers are affected

On entry (HL) must point to the first character in the string buffer, with the first character being in A. On exit, the the double precision number is left in the ACCumulator.

In processing, the digits are packed into the ACCumulator as an integer, with tracking for the decimal point. C=80H if we have not seen a decimal point, and 00H if we have. Register B holds the number of digits after the decimal point.

At the end, Register B and the exponent (held in Register E) are used to determine how many times we multiply or divide the number by 10 to get the correct number.

F6 AFF6 AF

0E6CH – ASCII to Binary Converter – “FIN”

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 the ACCumulator and the mode flag will be to the proper value.

Evaluate a numeric string that begins at the address pointed to by the HL Register Pair, store it in ACCUM and set the NTF. This routine stops as soon as it encounters a character that is not part of the number (it will return a value of zero if no valid numeric characters are found). It will accept signed values in Integer, Real or Scientific Notation. Number returned will be in integer format if possible, else single precision unless the string has over seven digits (not including exponent), in which case number will be returned as double precision.

This routine will convert the ASCII string pointed to by register pair HL to binary. The result will be returned in the ACCumulator, and the number type flag will be updated accordingly. The routine will convert the ASCII string to the least amount of precision required.

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).

↳ FIN

↳ FINCHR

↳ FINC

↳ FINEX1

↳ FINEX

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.

↳ FINE

This “FINE2” routine will multiply or divide by 10 the correct number of times. If A=0 the number is an integer.

↳ FINE2

Next we need to put the correct sign on the number.

Next we want -32768 to be an integer (it would be single precision at this point)

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 |

Double Precision | NZ/NC/P/E and A is 5. |

This routine checks to see if we have seen TWO decimal points and to set the decimal point flag. We jumped here when we found a single decimal point.

↳ FINDP

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

0EEE – Math Routine – “FININT”

↳ FININT

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

↳ INFINE

↳ FINDBF

↳ FINSNF

0EFB – Math Routine – “FINFRC”

This routine will force the ACCumulator to be either single precision or double precision based on the Z FLAG. Z FLAG = Force to single precision; NZ FLAG = Force to double precision.

↳ FINFRC

0EE4 – Math Routine – “FINMUL” and “FINMLT”

This subroutine multiplies a number by 10 once. The original ROM source notes that the reason this is a subroutine is that it can also double as a check to see if A is ZERO, thus saving bytes. All registers are affected.

↳ FINMUL

↳ FINMLT

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

↳ DCRART

0F18 – Math Routine – “FINDIV”

This subroutine divides a number by 10 once. FIN and FOUT use this routine. Registers A, B, and C are affected.

↳ FINDIV

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

0F29 – Math Routine – “FINDIG”

This routine will pack the next digit of the number into the ACCumulator. To do this, the ACCumulator is multipled by ten to shift everything over and make room for the digit, and then the digit is added in.

↳ FINDIG

Variable Type | Flags | Register A |

Integer | NZ/C/M/E | -1 |

String | Z/C/P/E | 0 |

Single Precision | NZ/C/P/O | 1 |

Double Precision | NZ/NC/P/E | 5 |

If we are here, then we re packing the next digit of an integer.

0F41

LD E,L54

At this point, the number has shifted over to make room for the new digit in the ones place.

0F57 – Math Routine – “FINDG1”

This routine handles 32768 and 32769

↳ FINDG1

0F59 – Math Routine – “FINDG2”

Convert integer digits into single precision digits

↳ FINDG2

0F5D – Math Routine – “FINDGV”

Determine if we have a single precision or a double prevision number

↳ FINDGV

These next 2 instruction set up BCDE to hold “1000000”

- A=0 if ACCumulator = BCDE
- A=1 if ACCumulator>BCDE; and
- A=FFH if ACCumulator<BCDE.

0F74 – Math Routine – “FINDG3” and “FINDGD”

The routine will convert a 7 digit single precision number into a double precision number

↳ FINDG3

This routine will pack in a digit into a double precision number

↳ FINDGD

0F89H-0F93H – SINGLE PRECISION MATH ROUTINE – “FINLOG”

This is a subroutine for FIN and for LOG

↳ FINLOG

0F94H-0FA6H – LEVEL II BASIC MATH ROUTINE – “FINEDG”

Pack in a digit of the exponent. This is done by multiplying the old exponent by 10 and then adding in the desired digit. Note: This routine does NOT check for overflow.

↳ FINEDG

↳ FINEDO

0FA7H-0FAEH – DISPLAY MESSAGE ROUTINE – “INPRT”

This routine is to output a floating point number.

↳ INPRT

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).

0FAFH-0FBCH – CONVERT BINARY TO ASCII AND DISPLAY RESULT – “LINPRT”

This routine converts the two byte number in the HL Register Pair (which is assumed to be an integer) to ASCII and displays it at the current cursor position on the video screen. The space for the sign at the beginning of a line is removed. All registers are affected.

↳ LINPRT

0FBDH-1363H – BINARY TO ASCII CONVERSION ROUTINE – “FOUT”

According to the original ROM source code:

This routine will output the value held in the ACCumulator according to the format specifications held in Registers A, B, and C. The ACCumulator contents are lost and all registers are affected.

The format codes are as follows:

- Register A:

- Bit 7:

- 0 means free format output, i.e. the other bits of a must be zero, trailing zeros are suppressed, a number is printed in fixed or floating point notation according to its magnitude, the number is left justified in its field, and Registers B and C are ignored.
- 1 means fixed format output, i.e. the other bits of a are checked for formatting information, the number is right justified in its field, trailing zeros are not suppressed. this is used for print using.
- Bit 6:

- 0 means means don’t print the number with commas.
- 1 means group the digits in the integer part of the number into groups of three and separate the groups by commas.
- Bit 5: 1 means fill the leading spaces in the field with asterisks (“*”)
- Bit 4: 1 means output the number with a floating dollar sign (“$”)
- Bit 3: 1 means print the sign of a positive number as a plus sign (“+”) instead of a space
- Bit 2: 1 means print the sign of the number after the number
- Bit 1: Unused
- Bit 0:

- 1 means print the number in floating point notation i.e. “e notation”. If this bit is on, the comma specification (bit 6) is ignored.
- 0 means print the number in fixed point notation. Numbers > 1e16 cannot be printed in fixed point notation.
- Register B: The number of places in the field to the left of the decimal point (B does not include the decimal point)
- Register C: The number of places in the field to the right of the decimal point (C includes the decimal point)
- Note 1: B and C do not include the 4 positions for the exponent. If bit 0 is on FOUT assumes b+c <= 24 (decimal)
- Note 2: If the number is too big to fit in the field, a percent sign (“%”) is printed and the field is extended to hold the number.
According to other sources:

Conversion routine. Converts the value from ACCumulator 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. ACCumulator and ARG (a/k/a REG 2) 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 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: 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.

↳ FOUT

0FBEH-0FC0H – FLOATING to ASCII Conversion Routine – “PUFOUT”

This routine converts a single or double precision number in the ACCumulator 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: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.

- 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.

↳ PUFOUT

This routine will zero suppress the digits in FBUFFR and asterisk fill and zero suppress if necessary.

↳ FOUTZS

`SPACE`