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

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.

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.

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

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.

Click to Enlarge
ERROR 5b
EXPECTATION: INT(value) should never overflow. However, if the value is double-precision 32767.9999#, the ROM overflows.

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

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

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

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

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

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

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

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

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

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

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

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

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

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#

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

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

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

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

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?

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

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

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.

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.

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.

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

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

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.