PageCustomization:

Display OPCODEs

Display Labels

Display Gen 1

Display Gen 2 and Student Network

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

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

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

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

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

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

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

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

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

0018 (RST 18H) Jumps to 1C90H through 4006H. This routine can be called by using RST 18H or CALL 1C90H. It compares two 16 bit values in HL and DE and sets the S and Z flags accordingly (they are set in the same way as for a normal 8 bit CP). All registers are unchanged except for A

This is the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)

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.

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

(RST 020H)

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

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

Note: 4015H holds Keyboard DCB – Device type

(RST 030H)

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.

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

Note: 4025H holds Printer DCB – Device type

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

*0043H-0045H – Model 4 Gen 1 Routine – Unused Code

*0043H-0045H – Model 4 Gen 2 Routine – Called from new routine at 3790H

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

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.

*0060H – Model 4 Gen 1 – 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.

*0060H – Model 4 Gen 2 – 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.

0066H – 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.)

*006C-0074H – Model 4 Gen 1 – Unused Code

*006C-0074H – Model 4 Gen 2

*006D-0070H – Model 4 Gen 2 – New Code for Gen 2 – Called from 02C3H when the BREAK key is hit

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

NOTE: C3H is the first byte of a 3 byte JUMP xxxxH command.

NOTE: C9H is a RET instruction.

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.

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

↳ STRSZD

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

*00FFH – Model 4 Gen 1 Code

*00FFH – Model 4 Gen 2 Code

0105H-0110H – MESSAGE STORAGE

The “MEMORY SIZE” message is located here

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

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

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”

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

013AH-019CH GRAPHICS ROUTINE

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)

↳ SETRES

019DH-01C8H – LEVEL II BASIC INKEY$ ROUTINE – “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.

Note: 4099H holds the last key pressed

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.

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

*01D9-01F7H – Model 4 Gen 1 Routine – Print Screen Routine – “$PRSCN”

This routine copies all 1024 characters from the screen to the printer. If the printer is unavailable, this routine waits until the printer becomes available. If `BREAK` is pressed, this routine returns to the caller.

“PRSCN”

Difference between M1 and M3: The routine to print the contents of the screen on the line printer is located from 01D9H to 01F4H on the Model III. On the Model I, 01D9H – 01F7H contains the routine to output one bit to the cassette.

Difference between M1 and M3: 01F0H contains CALL 0221H instruction on Model I, and CALL 0214H instruction on Model III.

Difference between M1 and M3: Contains LD B,5CH instruction on Model I, JR 01DCH instruction on Model III.

*01D9 – Model 4 Gen 2 Routine

*01DC-01E5H – Model 4 Gen 2 Routine to wait for either PRINTER READY or a `BREAK` key

`BREAK`key was pressed, then RETurn to caller

*01E6-01F7H – Model 4 Gen 2 Routine – Called from 0102H after displaying the CASS, MEMORY SIZE, and RADIO SHACK messages

**NOTE:**4177H is the TIME$ vector.

01F8 – Turn Off The Cassette Motor – “$CSOFF”

After writing data to the cassette, this routine should be called to turn off the cassette drive. There are no entry conditions and no registers are modified.

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

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

- This is a delay loop. The BC register pair is used as the loop counter. The duration of the delay, in microseconds, is the value of BC times 14.65. Register A is used.

OR C

202 – Message Storage Location

*0210 – Model 4 Gen 1 – These instructions are never called or used.

*0210 – Model 4 Gen 2 – These instructions are never called or used.

0212H – This continues a subroutine and was JUMPed to from 022CH. It zeroes A and all flags everything and RETURNs.

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

0216-021A – Display a Carriage Return

021B-0227 – “$VDLINE” – Display a Line Until 03H or 0DH Reached.

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

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

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

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

022EH – Final cleanup before entering BASIC … Enable Interrupts and JUMP to READY prompt

*0232 – Model 1 Gen 1 – These instructions are never called or used.

*0232 – Model 1 Gen 2 – These instructions are never called or used.

0235-0240 – CASSETTE ROUTINE – Read a Byte from Cassette – “CSIN”

After the completion of a $CSHIN call, this $CSIN routine begins inputting data, one byte at a time. This routine MUST be called often enough to keep up with the baud rate. There are no entry conditions. A is modified to hold the data byte.

Difference between M1 and M3: In the Model I, 0235H – 0240H contains the routine to read one byte from the cassette, and 0241H – 0260H contains the routine to get one bit from the cassette. In the Model III, 0235H – 023CH contain the start of the Model III routine to read one byte from cassette, 023DH – 0242H is part of the routine that begins at 0287H (writes cassette leader and sync byte), 0243H – 024CH is the actual start of the routine to search for the cassette leader and aync byte, 024DH – 0252H is the actual start of the routine to write a byte to tape, and 0253H – 025EH is a subroutine used by the system to select 500 or 1500 baud tape speed.

**NOTE:**When a routine is CALLed, the RETurn address is put at the top of the stack; so RET jumps to the value at the top of the STACK.

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

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

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

**NOTE:**When a routine is CALLed, the RETurn address is put at the top of the stack; so RET jumps to the value at the top of the STACK.

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

0264 – “$CSOUT” – Output a byte to cassette.

After writing the header with $CSHWR, use this $CSOUT to write the data, one byte at a time. You MUST call $CSOUT often enough to keep up with the baud rate. Register A needs to hold the data byte on entry.

Difference between M1 and M3: In the Model I, 0264H – 0283H contains the routine to output one byte to the cassette. In the Model III, 0264H – 0266H contains a jump to 024DH (the start of the Model III routine to output one byte to cassette), followed by time data (60 seconds, 60 minutes, 24 hours) at 0266H – 0268H, followed by twelve bytes which contain the length of each of the twelve months (0264H – 0274H). This is followed by two NOPs, then starting at 0277H is a 1DH byte, a 1EH byte, the message “Diskette?”, and finally a 03H byte (at 0282H).

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

0284 – This subroutine is called by 2076H to turn the tape on, no header – it jumps out to 023DH.

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

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

0287 – Write Leader and Sync Byte – “$CSHWR”

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

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

`BREAK`Key. First, load A with the memory contents of 3840H (which is the keyboard scan of 14400, the 7th keyboard line), to check for a BREAK. 14400 is ENTER (01) CLEAR (02)

`BREAK`(04) RIGHT ARROW (08) LINE FEED (16) LEFT ARROW (32) SPACE (64)

`BREAK`key.

0293 – CASSETTE ROUTINE – Read the Header and Sync Bytes

0296 – CASSETTE ROUTINE – “CSHIN” – Search for Cassette Header and Sync Byte

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

0298 – Enable the Clock Display – “CLKON”

No entry conditions. A is altered by this routine.

“CLKON”

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

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

02A1 – Disable the Clock Display – “CLKOFF”

No entry conditions. A is altered by this routine.

“CLKOFF”

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

*02A8 – Model 4 Gen 1 – These instructions are never called or used.

*02A8 – Model 4 Gen 2 – These instructions are never called or used.

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

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

In NEWDOS 2.1, this is called during a SYSTEM operation

*02B5-02B7 – Model 4 Gen 1 – Set the STACK Pointer.

*02B5-02B7 – Model 4 Gen 2 – Set the STACK Pointer.

*02C3-02C5 – Model 4 Gen 1 – Deal with the BREAK Key.

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

*02C3-02C5 – Model 4 Gen 2 – Deal with the BREAK Key.

`BREAK`key was hit (because the Carry flag is now on), go to new routine at 006DH

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.

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

031DH – Execute the Cassette Program which was Loaded – “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.

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

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

Save the value in Register Pair DE on the STACK

Note: 40A6H holds the current cursor line position

0348H-0357H – VIDEO ROUTINE – “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

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.

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”

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.

↳ OUTDO

`LINE FEED`FE 0A

`CARRIAGE RETURN`3E 0D

Note: 409BH holds the printer carriage position

Note: 409BH holds the printer carriage position

03C2H-0451H – Model 4 Gen 1 PRINTER ROUTINE

In the Model III, 03C2H – 0451H is the line printer driver routine, 0452H – 0468H is the actual location of the routine to initialize all I/O drivers, 046BH – 0472H is a routine used by the RUN/EDIT/NEW commands to unprotect the video display and to load HL with the start of BASIC program pointer at 40A4H-40A5H, and 0473H-05D0H is the video driver routine and the keyboard driver begins at 3024H in the Model III).

- If A=20H it sets the ZERO FLAG
- If A<20H then the CARRY FLAG will be set
- if A>=20H then the NO CARRY FLAG will be set.

**NOTE:**03F5H prints a character while maintaining page height and width.

**NOTE:**IX+4 is the number of lines printed.

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

**NOTE:**IX+5 is the number of characters printed.

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

03F5-0424 – Model 4 Gen 1 Inside the PRINTER ROUTINE – Print A Character Honoring Page Height and Width

**NOTE:**IX+5 is the number of characters printed.

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

**NOTE:**IX+5 is the number of characters printed.

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

**NOTE:**IX+5 is the number of characters printed.

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

**NOTE:**IX+5 is the number of characters printed.

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

**NOTE:**IX+5 is the number of characters printed.

**NOTE:**IX+4 is the number of lines printed.

**NOTE:**IX+3 is the maximum number of lines per page.

**NOTE:**IX+4 is the number of lines printed.

0440-044A – Model 4 Gen 1 – Inside the PRINTER ROUTINE – Subroutine to wait for PRINTER READY, but Honor a `BREAK` Key

`BREAK`key being pressed.

03C2H-044AH – Model 4 Gen 2 PRINTER ROUTINE

- If A=20H it sets the ZERO FLAG
- If A<20H then the CARRY FLAG will be set
- if A>=20H then the NO CARRY FLAG will be set.

**NOTE:**0414H will process a carriage return.

**NOTE:**IX+4 is the number of lines printed.

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

**NOTE:**IX+5 is the number of characters printed.

**NOTE:**IX+4 is the number of number of lines printed.

03C2H-044AH – Model 4 Gen 2 PRINTER ROUTINE – Jumped here from 03C5 if the character in A was >= a SPACE

03F6 – Model 4 Gen 2 PRINTER ROUTINE – Jumped here from 03EDH if the character stored at 41FBH is a ZERO

040A – Model 4 Gen 2 PRINTER ROUTINE – Jumped here from 03FAH if the character stored at 41FCH is NOT a ZERO

0414 – Model 4 Gen 2 PRINTER ROUTINE – Jumped here from 03C9 if the character held in REGISTER C (the current character) is a CARRIAGE RETURN

041F – Model 4 Gen 2 PRINTER ROUTINE – Checks to see if we are at the end of a ilne, advances if needed, and sends the character to the printer

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

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

**NOTE:**IX+5 is the number of characters printed.

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

**NOTE:**F8H is the printer port. If Bit 7 is set, the printer is not busy. If Bit 6 is set the printer is not out of paper. If bit 5 is set, the device is selected. If Bit 4 is set, no printer fault.

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

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

*0469-046A – Model 4 Gen 1 – These instructions are never called or used.

*0469-046A – Model 4 Gen 2 – These instructions are never called or used.

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

**NOTE:**4214H is the number of protected video lines.

**NOTE:**40A4 is the DATA POINTER.

0473H-04B1H – Video Display DCB.

LD H,(IX+04H)

**NOTE:**IX+05H holds the character at the cursor position.

- If A=20H it sets the ZERO FLAG.
- If A<20H then the CARRY FLAG will be set
- If A>=20H then the NO CARRY FLAG will be set.

- If A=C0H it sets the ZERO FLAG.
- If A<C0H then the CARRY FLAG will be set
- If A>=C0H then the NO CARRY FLAG will be set.

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

**NOTE:**IX+05H holds the character at the cursor position.

**NOTE:**IX+05H holds the character at the cursor position.

**NOTE:**IX+6 holds the cursor character.

**NOTE:**B0H is a two pixel wide graphic character located below the letter line.

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

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

04CC – Cursor Management – CURSOR ON.

**NOTE:**IX+05H holds the character at the cursor position.

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

04D4 – Cursor Management – HOME CURSOR

**NOTE:**3C00H is the start of the video display RAM.

**NOTE:**4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls. In this case, we are looking for the bit which holds whether we are in LARGE characters or SMALL characters.

**NOTE:**4214H is the number of protected video lines.

04EB – Cursor Management – BACKSPACE

**NOTE:**4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls. In this case, we are looking for the bit which holds whether we are in LARGE characters or SMALL characters.

04F7 – Cursor Management – CURSOR BACK

**NOTE:**4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls. In this case, we are looking for the bit which holds whether we are in LARGE characters or SMALL characters.

0504 – Cursor Management – CURSOR DOWN

0509 – Cursor Management – CURSOR FORWARD.

050E – Cursor Management – CURSOR UP

**NOTE:**FFC0H is -64, or 1 line length.

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

**NOTE:**4210H holds the bit mask for port ECH. Port ECH stores miscellaneous controls. In this case, we are looking for the bit which holds whether we are in LARGE characters or SMALL characters.

0521-055F – Cursor Management – Process Special Characters

**NOTE:**08H is a BACKSPACE.

**NOTE:**0AH is a LINE FEED.

**NOTE:**0DH is a CARRIAGE RETURN.

**NOTE:**0EH is a CURSOR ON.

**NOTE:**0FH is a CURSOR OFF.

0560 – Cursor Management – Control Characters.

056B – Cursor Management – Special and Alternative Characters

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

**NOTE:**Bit 3 of ECH is the SPECIAL CHARACTER SELECT. It will be 0 for KANA and 1 for MISC.

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

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

**NOTE:**HL should be the current screen location and A should be the character.

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

0588 – Cursor Management – Scroll the Screen

**NOTE:**4214H is the number of protected video lines.

05AF – Cursor Management – CARRIAGE RETURN or LINE FEED

05BC – Cursor Management – CLEAR TO END OF LINE

05C5 – Cursor Management – CLEAR TO END OF SCREEN

*05D1-05D8 – Model 4 Gen 1 Message Storage Area

*05D1-05D8 – Model 4 Gen 2 Message Storage Area

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

`SPACE`

`SPACE`)

`BREAK`key

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

Clear the screen

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

Cancel the accumulated line

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

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

Turn on 32 Character Mode

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

Process a horizontal tab

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

Process a Carriage Return and Automatic Line Feed

0674 – KEYBOARD DRIVER ENTRY ROUTINE

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

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

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

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

INC D

INC D

INC D

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

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

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.

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.

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

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

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.

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.

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

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.

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

077DH-07A7H – SINGLE PRECISION MATH SUPPORT ROUTINE – “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.

Vernon 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

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

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

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

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.

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.

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.

07F8-07FB – SINGLE PRECISION CONSTANT STORAGE LOCATION

07FC-0808 – SINGLE PRECISION CONSTANTS STORAGE LOCATION2

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)

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)

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.

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.

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.

0897H-08A1H – SINGLE PRECISION MATH ROUTINE

– “DIV10”

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

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.

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.

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.

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

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

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

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

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.

↳ SIGNC

↳ INRART

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.

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.

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.

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.

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.

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.

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.

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!

09BF-09CA – SINGLE PRECISION MATH ROUTINE

“LDRASA”

- This routine is the opposite of the 09B4H routine. It loads four bytes from REG 1 (single-precision) into the BC and DE register pairs. (BCDE=ACC). A is unchanged.
- Move FAC to registers (B,C,D,E). Alters B,C,D,E,H,L

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

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

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

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

This routine is the same as 9D6H except that the number of bytes shifted is determined by the value in the B Register ((HL)=(DE))Moves contents of B-register bytes from the address in DE to the address given in HL. Uses all registers except C

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.

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.

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.

↳ VMOVMF

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.

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

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

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.

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.

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

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

0AA3H – LEVEL II BASIC CONVERSION ROUTINE – “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

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.

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.

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.

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.

Note: 411DH-4124H holds ACCumulator

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

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

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

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”

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

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.

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

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

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 |

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

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

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

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.

0BAF

OR C78 B1

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

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

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.

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”

0C37H-0C44H – LEVEL II BASIC MATH ROUTINE – “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.

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.

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

Integer Negation Routine. All registers are altered.

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.

Next we are going to switch ARG and the ACCumulator.

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

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

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

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

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

0D1C

DEC HL2B

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

Note: 411DH-4124H holds ACCumulator

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

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

Note: 411DH-4124H holds ACCumulator

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.

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

Note: 411DH-4124H holds ACCumulator

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.

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

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

0D7D-0D7EH – DOUBLE PRECISION MATH ROUTINE – “DSHFR3”

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

This is the entry from DADD and DMULT.

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

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

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.

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

This routine handles multiplying by zero.

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

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

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

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

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.

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

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

“ASTOR”

This routine is the same as E65H above, except that it fixes REG 1 and NTF to the smallest possible number type.

↳ FINCHR

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

↳ FINEX1

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

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.

NOTE:

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

↳ FINEC

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.

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

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

0EE4 – Math Routine – “FINDP”

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.

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”

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 |

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.

0F0A – 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.

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 |

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.

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.

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

0F59 – Math Routine – “FINDG2”

Convert integer digits into single precision digits

0F5D – Math Routine – “FINDGV”

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

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

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

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

This is a subroutine for FIN and for LOG

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.

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

This routine is to output a floating point number.

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.

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.

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.

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

`SPACE`

1034 – LEVEL II BASIC MATH ROUTINE– “FOUINI”

Initially set up the format specs and put in a SPACEfor the sign of a positive number. This routine gets called by the FLOATING to ASCII Conversion Routine (at 0FBEH) and by the BINARY to ASCII Conversion Routine (at 0FAFH)

Note: 40D8H-40D9H holds the temporary storage location

103D – LEVEL II BASIC MATH ROUTINE– “FOUFRV”

This routine gets called by the FLOATING to ASCII Conversion Routine (0FBEH-0FC0H) if the value being converted is either Single Precision or Double Precision. This will print a single or double precision number in free format

OK, this is fun. The next instructions are supposed to set Register D to be the counter for the number of digits to display. There is no agreement on what the next two instructions do:

“Microsoft BASIC Decoded & Other Mysteries” says it turns 04 (SP) and 08 (SP) into 08 (SP) and 10 (DP) into 09 (SP) and 0B (DP)

“Model III ROM Commented” says it turns D into 07 (SP) and 17 (DP)

The original ROM Source Code comment says it turns D into 04 to 06 (SP) and 10 to 20 (DP)

The FOFRS2 routine will suppress trailing zeroes.

At this point, all trailing zeroes are now gone and HL points to the last non-zero character.

1074 – LEVEL II BASIC MATH ROUTINE– “FOFLDN”

This routine will put the exponent and a Dor Einto the buffer. On entry, Register A holds the exponent and it is assumed that all FLAGs are set correctly.

1085 – LEVEL II BASIC MATH ROUTINE– “FOUCE1” and “FOUCE2”

This routine will calculate the two digit exponent.

1093 – LEVEL II BASIC MATH ROUTINE– “FOUTDN”

This routine will print a free format zero.

Note: 4130H-4149H holds an internal print buffer

109A- LEVEL II BASIC MATH ROUTINE– “FOUTFX”

This routine will print a number in fixed format.

If we are here then we are going to print an integer in fixed format/fixed point notation.

10BF – LEVEL II BASIC MATH ROUTINE– “FOUTTS”

This routine will finish up the printing of a fixed format number.

Now we need to check to see if the fixed format/fixed point number overflowed its field length. The location if the decimal point needs to be in TEMP2.

10DF – LEVEL II BASIC MATH ROUTINE– “FOUBE2”

In this routine, we check to see if we can ignore the leading zero before a decimal point. We can do this if if we see the following: (in order)

+,- a sign (either “-” or “+”) [optional] $ a dollar sign [optional] 0 a zero [mandatory] . a decimal point [mandatory] 0-9 another digit [mandatory]

If we see a leading zero, it must be the one before a decimal point or else FOUTZS would have akready suppressed it. In that case, we just INC HLover the character following the zero, and not have to check for the decimal point explicitly.

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.

10F9 – LEVEL II BASIC MATH ROUTINE– “FOUBE3”

If we can get rid of the zero, we put the characters on the STACK back into the buffer one position in front of where they originally were.

Note that the maximum number of STACK levels this uses is three — one for the last entry flag, one for a possible sign, and one for a possible dollar sign.

We don’t have to worry about the first character being in the buffer twice because the pointer when FOUT exits will be pointing to the second occurance.

1102 – LEVEL II BASIC MATH ROUTINE– “FOUBE4”

If the number is too big for the field, we wind up here to deal with that.

1109 – LEVEL II BASIC MATH ROUTINE– “FOUFXV”

This is where the PRINT USING routine will print a single or double precision number in a fixed format

If we are here, then we are printing a DOUBLE PRECISION number in fixed format/fixed point notation

111B – LEVEL II BASIC MATH ROUTINE– “FFXSDO”

This routine will print a number which is greaster than 10^16 in free format with a percent sign

1124 – LEVEL II BASIC MATH ROUTINE– “FFXSFX”

This routine will print a SINGLE PRECISION number in fixed format/fixed point notation

The results are stored in A as follows:

If ACCumulator = BCDE | A=00 |

If ACCumulator > BCDE | A=01 |

If ACCumulator < BCDE | A=FF |

1124 – LEVEL II BASIC MATH ROUTINE– “FFXSDC”

This routine will print a SINGLE PRECISION or DOUBLE PRECISION number in fixed format/fixed point notation

This routine will print a number that has no fractional digits

If the field length is higher than the number of characters we actually have, we are going to need to put in that number of leading zeroes.

1157 – LEVEL II BASIC MATH ROUTINE– “FFXXVS”

This routine will print a SINGLE PRECISION or DOUBLE PREVISION number that has fractional digits

This routine will print numbers with integer digits, and will print some leading zeroes if the field is bigger than the number of digits we need to print.

117F – LEVEL II BASIC MATH ROUTINE– “FFXXV3”

This routine will print a number without integer digits.

Note: 40F3H-40F4H is a temporary storage location

119A – LEVEL II BASIC MATH ROUTINE– “FFXXV7”

This routine will print trailing zeroes.

11A3 – LEVEL II BASIC MATH ROUTINE– “FFXIFL”

This routine will print an integer in fixed format/floating point notation.

11AA – LEVEL II BASIC MATH ROUTINE– “FFXFLV”

This routine will print a SINGLE or DOUBLE PRECISION number in fixed format/floating point notation.

1201 – Test the magnitude of SP and DP numbers, and clear the times the value was scaled– “FOUTNV”

This routine will scale (normalize) the number in the accumulator so that all the digits are in the integer part (i.e., between 99,999 and 999,999). The signed base 10 exponent is returned in Register A. Registers D and E are unchanged.

NOTE:The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:

- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.

1222 – LEVEL II BASIC MATH ROUTINE– “FOUNDB”

There is a big bug in this routine which was fixed in v1.2 of the ROM. The fixing of that bug caused a renumbering from 1228H-124CH. The numbering here will show both.

NOTE:The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:

- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.

The next two instructions load BCDE with 99999.95 so as to check to see if the number in FAC is too big.

1228-122A

122B-122D

122E-1230

The results are stored in A as follows:

If ACCumulator = BCDE | A=00 |

If ACCumulator > BCDE | A=01 |

If ACCumulator < BCDE | A=FF |

1236-1238

123C

123D-123F

1240

1241-1242

1244-1246

1247

1248-124A

124C

124D

124F – LEVEL II BASIC MATH ROUTINE– “FOUNVC”

This routine will see if the number in the ACCumulator is small enough yet

NOTE:The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:

- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.

The next two instructions load BCDE with 999999.5 to see if the number in the FAC is too large.

The results are stored in A as follows:

If ACCumulator = BCDE | A=00 |

If ACCumulator > BCDE | A=01 |

If ACCumulator < BCDE | A=FF |

1269H – LEVEL II BASIC MATH ROUTINE– “FOTZER”

This routine puts leading zeroes into the input buffer. The count is held in Register A and it can be zero, but the Z FLAG needs to be set in that case. Only (HL) and Register A are affected.

1271 – LEVEL II BASIC MATH ROUTINE– “FOTZNC”

This routine will put zeroes in the buffer along with commans or a decimal point in the middle. The count is held in Register A and it can be zero, but the Z FLAG needs to be set in that case. Registers B (decimal point count) and C (comma count) are updated accordingly. Everything but DE is affected.

127D – LEVEL II BASIC MATH ROUTINE– “FOUTCD”

This routine will put a possible comma count into Register C and will zero Register C if we are not using commas in the specification.

1291 – LEVEL II BASIC MATH ROUTINE– “FOUTED”

This routine will put decimal points and commas in their correct places. This subroutine should be called before the next digit is put in the buffer. Register B = the decimal point count and Register C = the comma count.

The counts tell how many more digits have to go in before the comma ;or decimal point go in.

The comma or decimal point then goes before the last digit in the count. For example, if the decimal point should come after the first digit, the decimal point count should be 2.

Note: 40F3H-40F4H is a temporary storage location

129C – LEVEL II BASIC MATH ROUTINE– “FOUED1”

Part of the above routine, jumped here to test to see if a comma needs to be placed at (HL).

12A4 – LEVEL II BASIC MATH ROUTINE– “FOUTCV”

This routine will convert a SINGLE PRECISION or a DOUBLE PRECISION number that has been normalized to decimal digits. The decimal point count is in Register B and the comma count is in Register C. (HL) points to where the first digit will go. Routine will exit with A=0.

NOTE:The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:

- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.

Top of a loop to convert the next digit. It is executed “A” times.

12EA – LEVEL II BASIC MATH ROUTINE– “FOUTCS”

This routine is to convert a SINGLE precision value to an INTEGER which will be the decimal digits. Divide the integer equivalent by 100,000 and 10,000. Use the code at 1335H to convert the last 1000 to ASCII.

12FC – LEVEL II BASIC MATH ROUTINE– “FOUCS1”

This routine is to calculate the next digit of the number.

130A – LEVEL II BASIC MATH ROUTINE– “FOUCS2”

This routine divides the integer portion of the current value by 100,000 using compound subtraction. The quotient is kept in Register B as an ASCII value.

132F – This routine will convert an INTEGER to ASCII– “FOUTCI”

This routine converts an integer into decimal digits by dividing the integer portion of the current value by 100,000 using compound subtraction. The quotient is kept in Register B as an ASCII value and A=0 on exit.

This loop divides the current value by a power of 10 starting at 10,000 and working down to 10. The remainder frome ach division is added to the division and the sum becomes the dividend for the next division until done. The quotient is +2FH (which is the ASCII equivalent of a quotient).

1364-136B – DOUBLE PRECISION CONSTANT STORAGE LOCATION– “TENTEN”

136C-1373 – DOUBLE PRECISION CONSTANT STORAGE LOCATION– “FOUTDL”

1374-137B – DOUBLE PRECISION CONSTANT STORAGE LOCATION– “FOUTDU”

137C-1383 – DOUBLE PRECISION CONSTANT STORAGE LOCATION– “DHALF”

BYTE SAVING NOTE: Referencing 1380H, which is half-way through this double precision value of .5, results in a single precision value of 0.5

BYTE SAVING NOTE: Referencing 1380H, which is half-way through this double precision value of .5, results in a single precision value of 0.5

1384-138B – DOUBLE PRECISION CONSTANT STORAGE LOCATION– “FFXDXM”

138C-13D1 – DOUBLE PRECISION INTEGER CONSTANT STORAGE LOCATION– “FODTBL”

13D2-13D9 – SINGLE PRECISION POWER OF TEN TABLE LOCATION– “FOSTBL

13D8 – SINGLE PRECISION POWER OF TEN TABLE LOCATION– “FOITBL

13E2-13E6 – LEVEL II BASIC MATH ROUTINE– “PSHNEG”

13E7-13F1 – LEVEL II BASIC SQR(n)– “SQR”

This routine computes the square root of any value in ACCumulator. It processes it by raising n to the power of 0.5. The root is left in ACCumulator as a single precision value. Single-precision values only should be used

↳ SQR

13F2-1478H LEVEL II BASIC X to the Y Power (X^Y) ROUTINE– “FPWRQ”

A call to 13F2H raises the single precision value which has been saved to the STACK to the power specified in ACCumulator. The result will be returned in ACCumulator. The method of computation is e ** (y ln x).

13F7 – LEVEL II BASIC Exponentiation routine– “FPWR”

This routine handles the exponentiation routine of X^Y. To do so, first Y is checked for 0 and, if so, then the answer is simply 1. Then we check X for 0 and, if so, then the answer is simply 0.

If neither of those scenarios is the case, then must check to see if X is positive and, if not, check to see if Y is negative and if it is even or odd.

If Y is negative, the we negate it to avoid the LOG routine giving a ?FC ERROR when we call it.

If X is negative and Y is odd, the NEG routine is pushed to the STACK as the exit rouine so that the result will be negative.

The actual math here is X^Y = EXP(Y*LOG(X)).

↳ FPWR

/0 ERROR entry point

The results are stored in A as follows:

If ACCumulator = BCDE | A=00 |

If ACCumulator > BCDE | A=01 |

If ACCumulator < BCDE | A=FF |

1439 – LEVEL II ROM EXPROUTINE.

Single-precision only. (ACCumulator = EXP(REG1)).

To process this function we first save the original argument and multiply the ACCumulator by log2(e). The result of that is then used to determine if we will get overflow, since exp(x)=2^(x*log2(e)) where log2(e)=log(e) base 2.

We then save the integer part of this to scale the answer at the end, since 2^y=2^int(y)*2^(y-int(y)) and 2^int(y) is easy to compute.

So in the end we compute 2^(x*log2(e)-int(x*log2(e))) by p(ln(2)*(int(x*log2(e))+1)-x) where p is an approximation polynomial.

The result is then scaled by the power of 2 we previously saved.

A call to 1439H raises E (natural base) to the value in ACCumulator which must be a single precision value. The result will be returned in ACCumulator as a single precision number.

1479-1499 – SINGLE PRECISION CONSTANT STORAGE LOCATION

This represents 1/6, -1/5, 1/4, -1/3, 1/2, -1, and 1– “EXPCON”

149A-14C8 – LEVEL II BASIC MATH ROUTINE– “POLYX”

This is a general purpose summation routine which computes the series C0*X+C1*X^3+C2*X^5+C3*X^7+…+C(N)*X^(2*N+1) for I=0 to N when entered at 149AH If entered at 14A9H the series changes to SUM ((((x*c0+c1)x*c2)x+c3)x+.cN. On entry, the x is held in BC/DE and HL points to a list containing the number of terms followed by the coefficients.

The pointer to degree+1 is in (HL) and the constants should follow the egree, stored in reverse order. X is in the ACCumulator.

14A9 – LEVEL II BASIC MATH ROUTINE– “POLY”

General polynomial evaluator routine. Pointer to degree+1 is in (HL), and that gets updated through the computation. The Constants follow the degree and should be stored in reverse order. The ACCumulator has the X. The formula is c0+c1*x+c2*x^2+c3*x^3+…+c(n-1)*x^(n-1)+c(n)*x^n

PUSH BCD5

14C9-1540 – LEVEL II BASIC RND(n)ROUTINE– “RND”.

If the passed argument is 0, the last random number generated is returned. If the argument is < 0, a new sequence of random numbers is started using the argument.

To form the next random number in the sequence, we multiply the previous random number by a random constant, and add in another random constant. Then the HIGH ORDER and LOW ORDER bytes are switched, the exponent is put where it will be shifted in by normal, and the exponent in the ACCUMULATOR is set to 80H so the result will be less than 1. This is then normalized and saved for the next time.

The reason we switch the HIGH ORDER and LOW ORDER bytes is so we have a random chance of getting a number less than or greater than .5

Integer, single or double-precision. Output will be single-precision. (ACC=RND (ACC))

A call to 14C9H Generates a random number between 0 and 1, or 1 and n depending on the parameter passed in ACCumulator, The random value is returned in ACCumulator as an integer with the mode flag set. The parameter passed will determine the range of the random number returned. A parameter of 0 will return an interger between 0 and 1. A parameter greater than 0 will have any fraction portion truncated and will cause a value between 1 and the integer portion of the parameter to be returned.

There is a bug in the operation of this command. According to Vernon Hester RND(n) where n is an integer from 1 to 32767 is supposed to return an integer from 1 to n. However, when n is a power of two raised to a positive integer exponent from 0 to 14 sometimes returns n+1

↳ RND

POP DEC1

14F0 – This routine calculates RND(0)– “RND0”.

Note: 40AAH-40ADH holds the random number seed

Note: 40AAH-40ADH holds the random number seed

Note: 4125H-4126H is used by floating point routines

1541-1546 – LEVEL II BASIC COS

ROUTINE– “COS”.

Single-precision only.(ACCumulator = COS(ACCumulator)). A call to 1541H computes the cosine for an angle given in radians. The angle must be a floating point value in ACCumulator; the cosine will be returned in ACCumulator as a floating point value.

The formula being used is COS(X) = SIN(X+PI/2)

1547-158A – LEVEL II BASIC SINROUTINE– “SIN”

Single-precision only.(ACCumulator = SIN(ACCumulator)).

A call to 1549H returns the sine as a single precision value in ACCumulator. The sine must be given in radians in ACCumulator.

The actual calculation routine is:

- Assume X <= 360 degrees.
- Recompute x as x=x/360 so that x=< 1.
- If x <= 90 degrees go to step 7.
- If x <= 180 degrees then x=0.5-x and then go to step 7.
- If x <= 270 degrees then x=0.5-x.
- Recompute x as x=x-1.0.
- Compute SIN using the power series.

POP DEC1

POP DEC1

158B-158E – SINGLE PRECISION CONSTANT STORAGE LOCATION– “PI2”

158F-1592 – SINGLE PRECISION CONSTANT STORAGE LOCATION– “FR4”

1593-15A7 – SINGLE PRECISION CONSTANTS STORAGE LOCATION– “SINCON”

15A8-15BC – LEVEL II BASIC TAN(n)ROUTINE– “TAN”

Single-precision only.(ACCumulator = TAN(ACCumulator)).

A call to 15A8H computes the tangent of an angle in radians. The angle must be specified as a single precision value in ACCumulator. The tangent will be left in ACCumulator.

Uses the fact that TAN(x) = SIN(x) / COS(x)

↳ TAN

POP HLC1

15BD-15E2 – LEVEL II BASIC ATN(n)ROUTINE– “ATN”.

Single-precision only.(ACCumulator = ATN(ACCumulator)).

A call to 15BD returns the angle in radians, for the floating point tangent value in ACCumulator. The angle will be left as a single precision value in ACCumulator.

The method of computation used in this routine is:

- Test the sign of the tangent to see if a negative angle is in the 2nd or 4th quadrant. Set the flag to force the result to positive on exit. If the value is negative, invert the sign.
- Test magnitude of tangent. If it is < 1 go to step 3. Otherwise, compute its reciprocal and put the return address on the STACK that will calculate pi/2 – series value.
- Evaluate the series: (((x^2*c0+c1) x^2+c2) . c8)x
- If the flag from step 1 is not set, then invert the sign of the series result.
- If the original value is < 1 then return to the caller. Otherwise, compute pi/2-value from step 4 and then return.

↳ ATN

15E3-1607 – SINGLE PRECISION CONSTANTS STORAGE LOCATION– “ATNCON”

1608-18C8 – LIST OF BASIC RESERVED WORDS, TOKENS, AND ENTRY LOCATIONS AS FOLLOWS:

The original ROM source code makes an interesting note about the order of these reserved words. Some reserved words are contained in other reserved words, which will cause a problem. They given examples of:SO, the smaller word always has to appear later in the reserved word table.

- IF J=F OR T=5will process a FOR
- INPis part of INPUT
- IF T OR Q THENwill process a TO

ABS | D9 | 0977 | | | AND | D2 | 25FD |

ASC | F6 | 2A0F | | | ATN | E4 | 15BD |

AUTO | B7 | 2008 | | | CDBL | F1 | 0ADB |

CHR$( | F7 | 2A1F | | | CINT | EF | 0A7F |

CLEAR | B8 | 1E7A | | | CLOAD | B9 | 2C1F |

CLOSE | A6 | 4185 | | | CLS | 84 | 01C9 |

CMD | 85 | 4173 | | | CONT | B3 | 1DE4 |

COS | El | 1541 | | | CSAVE | BA | 2BF5 |

CSNG | F0 | 0ABl | | | CVD | E8 | 415E |

CVI | E6 | 4152 | | | CVS | E7 | 4158 |

DATA | 88 | 1F05 | | | DEF | DD | 415B |

DEFDBL | 9B | 1E09 | | | DEFINT | 99 | 1E03 |

DEFSNG | 9A | 1E06 | | | DEFSTR | 98 | 1E00 |

DELETE | B6 | 2BC6 | | | DIM | 8A | 2608 |

EDIT | 9D | 2E60 | | | ELSE | 95 | 1F07 |

END | 80 | 1DAE | | | EOF | E9 | 4161 |

ERL | C2 | 24DD | | | ERR | C3 | 24CF |

ERROR | 9E | 1FF4 | | | EXP | E0 | 1439 |

FIELD | A3 | 417C | | | FIX | F2 | 0B26 |

FN | BE | 4155 | | | FOR | 81 | 1CA1 |

FRE | DA | 27D4 | | | GET | A4 | 4174 |

GOSUB | 91 | 1EB1 | | | GOTO | 5D | 1EC2 |

IF | 8F | 2039 | | | INKEY$ | C9 | 019D |

INP | DB | 2AEF | | | INPUT | 89 | 219A |

INSTR | C5 | 419D | | | INT | D8 | 0B37 |

KILL | AA | 4191 | | | LEFT$ | F8 | 2A61 |

LEN | F3 | 2A03 | | | LET | 8C | 1F21 |

LINE | 9C | 41A3 | | | LIST | B4 | 2B2E |

LLIST | B5 | 2B29 | | | LOAD | A7 | 4188 |

LOC | EA | 4164 | | | LOF | EB | 4167 |

LOG | DF | 0809 | | | LPRINT | AF | 2067 |

LSET | AB | 4197 | | | MEM | C8 | 27C9 |

MERGE | A8 | 418B | | | MID$ | FA | 2A9A |

MKD$ | EE | 4170 | | | NAME | A9 | 418E |

NEW | BB | 1B49H | | | NEXT | 87 | 22B6 |

NOT | CB | 25C4 | | | ON | A1 | 1FC6 |

OPEN | A2 | 4179 | | | OR | D3 | 25F7 |

OUT | AO | 2AFB | | | PEEK | E5 | 2CAA |

POINT | C6 | 0132 | | | POKE | B1 | 2CB1 |

POS | DC | 27F5 | | | B2 | 206F | |

PUT | A5 | 4182 | | | RANDOM | 86 | 01D3 |

READ | 8B | 21EF | | | REM | 93 | 1F07 |

RESET | 82 | 0138 | | | RESTORE | 90 | 1D91 |

RESUME | 9F | 1FAFH | | | RETURN | 92 | 1EDEH |

RIGHT$ | F9 | 2A91 | | | RND | DE | 14C9 |

RSET | AC | 419A | | | RUN | 8E | 1EA3 |

SAVE | AD | 41A0 | | | SET | 83 | 0135 |

SGN | D7 | 098A | | | SIN | E2 | 1547 |

SQR | CD | 13E7 | | | STEP | cc | 2B01 |

STOP | 94 | 1DA9 | | | STR$ | F4 | 2836 |

STRING$ | C4 | 2A2F | | | SYSTEM | AE | 02B2 |

TAB( | BC | 2137 | | | TAN | E3 | 15A8 |

THEN | CA | | | TIME$ | C7 | 4176 | |

TO | BD | | | TROFF | 97 | 1DF8 | |

TRON | 96 | 1DF8 | | | USING | BF | 2CBD |

USR | C1 | 27FE | | | VAL | FF | 2AC5 |

VARPTR | C0 | 24EB | | | + | CD | 249F |

– | CE | 2532 | | | CF | ||

/ | D0 | | | ? | D1 | ||

> | D4 | | | = | D5 | ||

< | D6 | | | & | 26 | ||

‘ | FB | 3A93 |

18C9-18F6 – STORAGE LOCATION FOR LEVEL II BASIC ERROR MESSAGES– “ERRTAB”

18F7-1904 – STORAGE LOCATION FOR THE SINGLE PRECISION DIVISION ROUTINE

This code is moved from 18F7-191DH to 4080H-40A5H during non-disk initial setup.

1905-191C – STORAGE LOCATION FOR VALUES PLACED IN RAM UPON INITIALIZATION.

This code is moved to 408E during non-disk initial setup.

191D-1923 – MESSAGE STORAGE LOCATION– “ERR”

1929-192F – MESSAGE STORAGE LOCATION– “REDDY”

1930-1935 – MESSAGE STORAGE LOCATION– “BRKTXT”

1936-1954 – SCAN STACK ROUTINE– “FNDFOR”

This routine is called with DE as the address of the NEXT index. It scans the STACK backwards looking for a FORpush. If one is found, it gets the address of the index and compares with the DE that was in place when this routine was called. If it is equal, then it exits with A=0 and HL=Address of the variable. If it is not equal it will keep scanning until no FOR push is found and then exit with A<>0.

According to the original ROM source, this routine is part of the general storage management routines, and if designed to find a FORentry on the STACK with the variable pointer passed in Register Pair DE.

OR E7A

1955-1962 – DATA MOVEMENT ROUTINE– “BLTU”

This routine moves a variable into another area specified by the caller. On entry BC is set as the end address of the list to move (which is the upper limit); DE is set as the start address of the list to move; and HL is the end of the area to move it to.

According to the original ROM source, this routine is part of the general storage management routines, and if designed to make space by shoving everything forward and to check to make sure a reasonable amount of space remains between the top of the STACK and the highest location transferred to. On Entry, HL should be the destination of the high address, DE should be the low address to be transferred there, and BC should be the high address to be transferred there. On exit, HL=DE=Low BC=The location LOW was moved to.

1963-197D – MEMORY CHECK ROUTINE– “GETSTK”

This routine computes the amount of space between HL and the end of memory at FFC6. On entry, Register C should hold the number of desired bytes.

According to the original ROM source, this routine is part of the general storage management routines, and if designed to make sure that a certain number of locations remain available for the STACK. To use this routine, Register C needs to hold the number of two byte entries needed, and then do a CALL GETSTK. This routine must be called by any reoutine which puts an arbitrary amount of stuff into the STACK (such as a recursive routine like FRMEVL). It is also called by routines such as GOSUBand FORwhich make permanent entries in the STACK.

Note: 40FDH-40FEH holds Free memory pointer

LD A,256-(2*NUMLEV)3E C6

197A-197B – ?OM ERROR ENTRY POINT– “OMERR”

197E-1AF7 – LEVEL II BASIC COMMAND MODE ERROR HANDLING– “PRGEND”

Note: 40A2H-40A3H holds the current BASIC line number

Note: 40DAH-40DBH holds DATA line number

Note: 40A2H-40A3H holds the current BASIC line number

The next few instructions are all Z-80 tricks to allow Register E to hold its value while passing through them all.

↳ DV0ERR

↳ NFERR

↳ REERR

Note: 40EAH-40EBH holds Line number with error

19AEH – Routine used when a catastropic BREAK key occurs

Note: 40E8H-40E9H holds STACK pointer pointer

19B4 – LEVEL II BASIC COMMAND MODE ERROR HANDLING– “ERRMOR”

Note: 409AH holds the RESUME flag

Note: 40E6H-40E7H holds the temporary storage location

Note: 40EEH-40EFH is used by RESUME

Note: 40EAH-40EBH holds Line number with error

AND L7C

Note: 40F5H-40F6H holds the last line number executed

Note: 40F7H-40F8H holds Last byte executed

Note: 40F0H-40F1H is used by ON ERROR

OR L7C

Note: 40F2H holds Error flag

19E3 – LEVEL II BASIC COMMAND MODE ERROR HANDLING– “NOTRAP”

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.

Note: 40EAH-40EBH holds Line number with error

This basically reserves the line number 65534 as a trigger for the next few steps

The original ROM has this note: The following code is for “LIST” command stopping and for returning from a failed “CVER” and to correct a direct GOSUB which does input.

Re-entry into BASIC command mode entry point. (see 6CCH also)

1A33 – MAIN LEVEL II BASIC INTERPRETER ENTRY– “MAIN”

If the jump here was from an AUTOcall, (40E4H) will have the increment number, (40E1H) will be 0 if no AUTOand non-zero if AUTO, and (40E2H) will have the starting line number.

While not for this specific routine, this is the best place to mention it. Vernon Hester has pointed out that while BASIC is supposed to ignore spaces in commands, it fails to properly handle some commands because of spaces

If you have a statement with a type declaration tag after a number and a space before an add or subtract arithmetic operator, the ROM applies the operator as a unary operator for the following argument

Example: PRINT 2% + N will display two numbers. PRINT 2%+N will display one number.

Also, if you have a statement with a type declaration tag after a number and a space before a multiply or divide arithmetic operator, the ROM willl throw a ?SN ERROR

Example: PRINT 2%*N will display a number. PRINT 2% * N will display a ?SN ERROR.

Note: 40A2H-40A3H holds the current BASIC line number

Note: 40E2H-40E3H holds Current BASIC line number