ROM Errors

ROM Errors by Vernon Hester

What is a ROM error?

A ROM error is a BASIC software anomaly in the Radio Shack’s TRS-80 Model I and/or Model III microcomputers. i.e., the result and/or displayed output does not adhere to what should be expected – violates rules, etc.

I compiled the errors based on remarks in a 1998 issue of Computer News 80 that said “Model 4 MULTIDOS is simply Model III MULTIDOS with VID 80.”

I created SuperBASIC for the Lobo MAX-80 in 1983. My primary goal was to create a seamless transition from Radio Shack’s TRS-80 Model I and Model III with minimum changes to Model I and Model III BASIC programs. While testing SuperBASIC, I discovered differences between SuperBASIC and Microsoft BASIC thinking that I erred; however, it was not errors in my code but errors in Microsoft’s BASIC.

I numbered the Model I ERROR 1 through ERROR 26; however, there are multiple errors in 5, 7, 14, 15, 22, and 25 bringing the total number of errors to 33. When Radio Shack released the Model III, they kept all of the 33 errors in the Model I and created 6 additional errors as well as a hardware error.

I set out below, the 39 errors in my sequence.

Model I

ERROR 1

RULE: When BASIC prints an unformatted number, BASIC prints a leading space if the number is positive or a leading negative sign if the number is negative and a trailing space; and keeps the number on one video (or line printer) line. However, in the 32 and/or 40 characters per line mode, the ‘keep it on one video line’ rule is violated. e.g.,

10 CLS:PRINT CHR$(23);
20 FOR X = 12345 TO 12350:PRINT X;:NEXT

Output:
Click to Enlarge

ERROR 2

EXPECTATION: RND(n) where n is an integer from 1 to 32767, returns 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. To get there quickly:

In ROM BASIC/SuperBASIC

POKE 16554,2 POKE 28989, 2
POKE 16555,15 POKE 28990, 15
POKE 16556,226 POKE 28991, 226

or in TRSDOS 6 BASIC

POKE 16554,2 POKE 28989, 2
POKE 16555,15 POKE 28990, 15
POKE 16556,226 POKE 28991, 226

Otherwise, it takes 12,516,774 executions of RND(n) from a cold start.

Output:
Click to Enlarge

ERROR 3

EXPECTATION: Double-precision quotients should have the same range as single-precision quotients. e.g.,

PRINT 1.76E33 / 8.8E37

produces a quotient of 2E-05 or .00002 whereas

PRINT 1.76D33 / 8.8D37

produces a quotient of zero.

Output:
Click to Enlarge

ERROR 4

EXPECTATION: 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.,

10 Y# = .5 [ 120 * .5 [ 8: REM 2.938735877055719D-39
20 PRINT Y#
30 PRINT 0 / Y#
40 PRINT 1 / Y#

produces

2.938735877055719D-39
.5
2.938735877055719D-39

This error occurs because the ROM converts 2.938735877055719D-39 to zero

Output:
Click to Enlarge

ERROR 5a

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

Output:
Click to Enlarge

ERROR 5b

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

Output:
Click to Enlarge

ERROR 6

EXPECTATION: 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

Output:
Click to Enlarge

ERROR 7a

RULE: In BASIC, spaces have no significance (except in messages to be printed). However, when processing 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. e.g.,

PRINT 2# + N

Output:
Click to Enlarge

ERROR 7b

RULE: In BASIC, spaces have no significance (except in messages to be printed). However, when processing a statement with a type declaration tag after a number and a space before a multiply or divide arithmetic operator, the ROM declares syntax error. e.g.,

PRINT 2# * N

Output:
Click to Enlarge

ERROR 8

RULE: A PRINT USING statement with a negative sign at the end of the field prints a negative sign after negative numbers and prints a space for positive numbers. However, if the field specifiers in the string also has two asterisks at the beginning of the field, the ROM prints an asterisk instead of a space after a positive number.

10 PRINT USING “**####-“;1234

Output:
Click to Enlarge

ERROR 9

EXPECTATION: When a number is just under specific decimal magnitudes, the ROM prints a colon instead of 10. e.g.,

PRINT 9999999999999999 / 1D12 + 3D-13

Output:
Click to Enlarge

ERROR 10

EXPECTATION: Double-precision subtraction should produce an difference accurate to 16 digits. However, the difference resulting from double precision subtraction is erroneous when the smaller operand’s value is significantly less than the larger operand’s value. e.g.,

10 Y# = .20#
20 X# = 1D16
30 J# = X# – Y# ‘J# is valued incorrectly
40 PRINT J# – X# ‘the result should be negative; however, it is positive

Output:
Click to Enlarge

ERROR 11

EXPECTATION: FOR-NEXT loops with valid integer values should complete. e.g.,

10 FOR J% = 0 TO 30000 STEP 5000
20 PRINT J%,
30 NEXT

Output:
Click to Enlarge

ERROR 12

RULE: Logarithms – 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)

will display 8.26296E-08

Output:
Click to Enlarge

ERROR 13

RULE: 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

Output:
Click to Enlarge

ERROR 14a

EXPECTATION: 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. e.g.,

10 Z# = 1 / (2^125 + 2^125) * .25
15 ‘Line 10 values Z# with 2.938735877055719D-39
20 PRINT 1 / Z# ‘displays 2.938735877055719D-39 instead of overflow

Output:
Click to Enlarge

ERROR 14b

EXPECTATION: Double-precision division should perform correctly for absolute values that are from 2.938735877055719D-39 to 1.701411834604692D+38. If the dividend is the minimum magnitude or the minimum magnitude times 2, then double-precision division errors. e.g.,

10 Z# = 1 / (2^125 + 2^125) * .25
15 ‘Line 10 values Z# with 2.938735877055719D-39
20 PRINT Z# / 1 ‘displays 0 instead of 2.938735877055719D-39

Output:
Click to Enlarge

ERROR 15a

EXPECTATION: Single-precision division should perform correctly for absolute values that are from 2.93874E-39 to 1.70141E+38. If the divisor is the minimum magnitude, then single? Precision division errors. e.g.,

10 Z = 1 / (2^125 + 2^125) * .25 ‘values Z with 2.93874E-39
20 PRINT Z / 1 ‘displays 0 instead of 2.93874E-39

Output:
Click to Enlarge

ERROR 15b

EXPECTATION: Single-precision division should perform correctly for absolute values that are from 2.93874E-39 to 1.70141E+38. If the dividend is very large, then single precision division errors. e.g.,

10 PRINT 1.6E38 / .9 ‘displays 0 instead of overflow

MICROSOFT BASIC-80 release 5.0; i.e., BASIC 01.01.02

10 PRINT 1.5E38 / .9 ‘overflows instead of displaying 1.66667E38

Output:
Click to Enlarge

ERROR 16

EXPECTATION: PRINT USING should not clobber code from 4152H through 415BH disabling CVI, FN, CVS, and DEF. BASIC 01.01.02 just clobbers the space and ‘i’ in the ” in ” message.

10 A# = -2^53
20 B$=”.#######################-“
30 PRINT USING B$;A#

Output:
Click to Enlarge

ERROR 17

RULE: SIN(X) + SIN(-X) = 0. Unfortunately the ROM disobeys this rule.

10 FOR Y = 1 TO 100
20 X = Y / 100
30 PRINT SIN(X) + SIN(-X),
40 NEXT

Output:
Click to Enlarge

ERROR 18

RULE: SIN(X) should be less than X. Unfortunately the ROM disobeys this rule.

10 PRINT “Testing “;
20 FOR Z = 1 TO 7
30 FOR X = 9 TO 1 STEP -1
40 Y = VAL(STR$(X) + “E-” + STR$(Z))
50 IF Y < SIN(Y) THEN D = D + 1:B = D:IF C = 0 THEN PRINT:C = D
60 IF B THEN PRINT TAB(((D – 1) AND 1) * 32)Y;SIN(Y);:IF (D – 1) AND 1 THEN PRINT
70 B = 0
80 NEXT
90 IF D = 0 THEN PRINT “.”;
100 NEXT
110 IF POS(0) <> 0 THEN PRINT
120 IF D > 0 THEN PRINT
130 IF SIN(.01) + SIN(-.01) <> 0 THEN E = E + 1:PRINT SIN(.01), SIN(-.01)
140 IF SIN(.001) + SIN(-.001) <> 0 THEN E = E + 1:PRINT SIN(.001), SIN(-.001)
150 IF SIN(1E-4) + SIN(-1E-4) <> 0 THEN E = E + 1:PRINT SIN(1E-4), SIN(-1E-4)
160 IF E > 0 THEN PRINT
170 PRINT “Total errors”;D + E

Output:
Click to Enlarge

ERROR 19

EXPECTATION: PRINT USING without scientific specifier should display a negative sign if the value is <-9.999999999999999D+15. e.g.,

10 PRINT USING “##.##”;-1D16

This prints % 1D+16 and should print %-1D+16

Output:
Click to Enlarge

ERROR 20

EXPECTATION: When PRINT USING has scientific specifier the rounded value should ‘scale’ and not indicate the PRINT USING field is not large enough. The ROM fails this expectation. e.g.,

10 PRINT USING “##.##[[[[“;-999999

Will output %-10.00E+05

Output:
Click to Enlarge

ERROR 21

EXPECTATION: Strings in a relational statement should work regardless of a concatenated expression. e.g.,

10 IF “h”+”m” = “hm” THEN PRINT “X”
20 IF “hm” = “h”+”m” THEN PRINT “Y”

The ROM performs line 10 flawlessly and screams “Type mismatch” on line 20. Aren’t they the same?

Output:
Click to Enlarge

ERROR 22a

EXPECTATION: A statement with VAL(string) should return zero if the first character is not numeric. The ROM produces syntax error if the first character in a string is %.

Output:
Click to Enlarge

ERROR 22b

EXPECTATION: A statement with VAL(string) should not corrupt the BASIC program. The following program cannot execute in Microsoft BASIC.

10 ON ERROR GOTO 50
20 PRINT VAL(“1E44”)
30 PRINT MEM
40 END
50 RESUME NEXT

Best to fix up line 20 before you edit line 10

Output:
Click to Enlarge

ERROR 22c

EXPECTATION: A statement with VAL(string) should ignore leading spaces in the string. The ROM loses itself if a space precedes a positive or negative sign. e.g., the following program lines return a zero with the ROM

10 PRINT VAL(” -3″)
20 PRINT VAL(” – 4″)
30 PRINT VAL(” +7″)
40 PRINT VAL(” + 8″)

Radio Shack incorrectly states, “VAL will not always return the correct value of negative numbers although it does return the correct value of positive numbers.” This is a half-baked excuse for the ROM error.

Output:
Click to Enlarge

ERROR 23

EXPECTATION: Statements that use floating point multiplication should be able to create a product that is less than the upper limit of the floating point range ?1.70141 x 1038.

Microsoft BASIC indicates overflow if the product is => 8.507059 x 1037. e.g., EXP(88) = 1.65163 x 1038 which is less than 1.70141 x 1038; however, Microsoft BASIC indicates overflow.

This is wrong because EXP(-88) = 6.05462E-39.

Output:
Click to Enlarge

ERROR 24

EXPECTATION: Statements that use floating point division should be able to create a quotient that is greater than the lower limit of the floating point range ?2.93874 x 10-39.

Microsoft BASIC returns a zero if the quotient is < 5.8775 x 10-39. e.g., .5 / 8.50706 x 1037 = 5.87747 x 10- 39

Note: Ira could not duplicate this. Assuming the above math was really .5/8.50706*10E-37 and 5.87747*10E-39, they both show the same result.

Output:
Click to Enlarge

ERROR 25a

EXPECTATION: Exponentiation where both the base and exponent is an small integer should produce a correct result. The ROM fails to meet this expectation. e.g.,

PRINT 3[12 returns 531442, but it should be 531441

PRINT 7[7 returns 823544, but it should be 823543

Output:
Click to Enlarge

ERROR 25b

EXPECTATION: Square roots of perfect squares should produce a correct result. Microsoft BASIC fails to meet this expectation. e.g.,

PRINT SQR(625) – 25<>0

Output:
Click to Enlarge

ERROR 26

EXPECTATION: Editing a REM statement should not corrupt a BASIC program. However, if the REM statement – all REM – is 254 or 255 characters the BASIC program is corrupted.


Model III

The Model III ROM includes all of the 33 errors found in the Model I ROM; and, the Model III ROM has six additional errors.

In describing the additional MODEL III errors, I will be code specific; whereas, most of the Model I errors were created by Microsoft’s code fundamentals and cannot be corrected without rewriting significant chunks of code.

With the capability to modify the Model III ROM code in a Model 4, I created ‘fixes’ (1 to 81 bytes) to code segments keeping as much of the original code as possible. Each of these ‘fixes’ were limited to a single area (one exception) and are independent of other ‘fixes’. To fix floating point multiplication and division, I would have to completely change the way the resulting exponent is determined. This would create modifications to, at least, five areas.

ERROR 27

Location 0072H: Instruction here is JP 06CCH. Location 06CCH on the Model I contained the correct entry to BASIC from a machine language routine that moved the stack pointer. On the Model III, 0072H still has the instruction JP 06CCH; however, that is in the middle of the Model III’s modified list routine. This is a bona fide screw up that was never fixed.

ERROR 28

Location 02B5H: Instruction here is LD SP,4288H. The instruction here should be LD SP,4388H because the Model III moved up the start of BASIC by 100H. This is another bona fide screw up that was never fixed.

ERROR 29

Location 02C3H: Instruction here is JP 06CCH. Location 06CCH on the Model I contained the correct entry to BASIC from a machine language routine that moved the stack pointer. On the Model III, 0072H still has the instruction JP 06CCH; however, that is in the middle of the Model III’s modified list routine. This is the same jump foul up as ERROR 27. In Model III BASIC, key SYSTEMENTER then press BREAK.

ERROR 30a

Location 0348H: Instruction here is LD A,(403DH). 403DH is the code that is jumped to when port 0E0H has bit 3 reset (IOBUS interrupt). 403DH was used in the Model I to hold an image of what was outputted to port 0FFH. If bit 3 of port 0FFH is set then the Model I is in the 32 characters per line video mode. Another screw up. The Model III uses bit 2 of port 0ECH with image in 4210H.

ERROR 30b

Location 034BH: Instruction here is AND 08H. Wrong bit is tested. The correct instruction should be AND 04H. OP-ED: Once Radio Shack explained the cursor movement when in the 32 characters per line video mode, Radio Shack did not fix the code. And, Radio Shack made Logical Systems modify TRSDOS 6 to behave the same way! However, with LSDOS 6.3, someone should have had the guts to correct the code.

ERROR 31 part 1

The routine located at 06CCH in the Model I resets the stack pointer to the last CLEAR n address when returning from a machine language routine that moved the stack pointer. If the machine language routine did not move the stack pointer then a simple return would suffice; or, exit to 0A9AH to pass a value back to the variable used in the USR statement.

ERROR 31 part 2

The Model III does not have a routine to reset the stack pointer to the last CLEAR n address when returning from a machine language routine that moved the stack pointer. The code necessary is LD BC,1A18H followed by JP 19AEH. That’s all of six bytes. Instead of wasting (what a waste!) 2K of the 14K ROM on ridiculous stuff, put the routine in the 3000H to 37FFH area; or, use ‘dead’ code created by Model III changes.