; Copyright 2016, 2017, 2019 Richard Dymond (rjdymond@gmail.com)

[Bug:noStepForward:No step forward]
Consider this PRINT command:

<code>PRINT 12;CHR$ 9;34</code>

You might, because of the cursor-right control character (CHR$ 9) between '12'
and '34', expect it to print:

<code>12 34</code>

But in fact it prints:

<code>1234</code>

The reason is that the routine at #R$0A3D, which is responsible for handling
CHR$ 9, does not update the print position after overprinting a space to the
right of the '2', and so effectively prints nothing at all.

Note, however, that even if the print position were updated, CHR$ 9 would still
not be a true cursor-right control character, because it overprints a space
using the current colours rather than leaving the colours as they are. The
following PRINT command demonstrates this bug:

<code>PRINT AT 0,0;1; INK 2;AT 0,0;CHR$ 9</code>

[Bug:noStepBack:No step back]
Consider the following PRINT commands:

<div><code>PRINT 1</code></div>
<div><code>PRINT CHR$ 8;2</code></div>
<div><code>PRINT CHR$ 8;3</code></div>

They should print '2' at the right end of the top line of the display - because
of the cursor-left character (CHR$ 8) before the '2' - but instead the '2' is
printed at the beginning of the second line, as if the CHR$ 8 were not there.
However, the '3' is (correctly) printed at the right end of the second line.

The reason is that the instruction at #R$0A32 is '#S/LD A/,#o18' instead of
'#S/LD A/,#o19', which prevents CHR$ 8 from moving the print position up to
the top line of the display.

[Bug:stepBackTooFar:A step back too far]
In addition to sometimes not working when it should, the cursor-left character
(CHR$ 8) also sometimes works when it shouldn't - specifically, when the print
position is at the top-left of the screen. For example:

<code>PRINT AT 0,0;CHR$ 8;12</code>

Here the CHR$ 8 should have no effect, but instead the '1' is printed at
(-1,0), which the ROM calculates to be at address #h58FF, or (7,31) in the
attribute file.

The reason, again, is that the instruction at #R$0A32 is '#S/LD A/,#o18'
instead of '#S/LD A/,#o19', which allows CHR$ 8 to move the print position up
beyond the top line of the display.

[Bug:savingASimpleString:Saving a simple string]
It is possible to save a simple string (as opposed to an array) to tape, but it
cannot be restored. For example:

<div><code>LET a$="12"</code></div>
<div><code>SAVE "a" DATA a$()</code></div>

saves the simple string variable a$ to tape without giving an error. When the
same variable is loaded from tape:

<code>LOAD "" DATA a$()</code>

no error is given until a$ is accessed - both <code>PRINT a$</code> and
<code>PRINT a$(1)</code> result in a '3 Subscript wrong' error.

The reason it's possible to save a simple string to tape is that the routine at
#R$0605, when it finds the string variable to be saved, does not check whether
it is an array.

[Bug:neverendingRestore:The neverending RESTORE]
When the following program is run, the Spectrum will enter an infinite loop:

<code>10 RESTORE 60000</code>

The reason is that the routine at #R$19B8 - which is called from #R$196E to
find the next line in the BASIC program - does not stop at the end of the BASIC
program (if there even is one), but keeps going through the variables area and
the rest of the RAM. Depending on the contents of the RAM, the routine can end
up examining the same memory area over and over again, never finding anything
that looks like a BASIC line with a suitably high number.

[Bug:curseTheCursor:Curse the cursor]
In some circumstances, pressing EDIT can bring the current line cursor down to
the editing area along with the current line, and the cursor must be removed
before the line is re-entered. For example, type in the following program,
pressing ENTER where shown:

<div><code>10 PRINT&lt;ENTER&gt;</code></div>
<div><code>11&lt;ENTER&gt;</code></div>

Then press EDIT, and see line 10 come down to the editing area with the cursor
in tow.

The reason this happens is that the routine at #R$0FA9 decrements the line
number at #SYSVAR(E-PPC) (from 11 to 10) so as to avoid printing the cursor,
but doesn't take into account that the number of the line that will be brought
down for editing is one less than its current value.

[Bug:str$AndSmallNumbers:STR$ and small numbers]
Because of a bug in the handling of the calculator stack at #R$2E24, a binary
expression with STR$ on the right hand side is evaluated as if its left hand
side is empty. For example:

<code>PRINT "2"+STR$ 0.5</code>

prints '0.5' instead of '20.5'.

Note that the bug is triggered only if the argument of STR$ is a non-zero
number strictly between -1 and 1.

[Bug:gotoAndlargeNumbers:GO TO and large numbers]
Since BASIC line numbers cannot be greater than 9999, you might expect a 'GO TO
<i>n</i>' command where <i>n</i>&gt;9999 to either do nothing or give an
appropriate error message. But GO TO does not behave consistently when <i>n</i>
is large.

The command 'GO TO <i>n</i>' always (appropriately) does nothing when
<i>n</i>&lt;32768, so long as there is no line number greater than or equal to
<i>n</i> and there are no variables present.

But if there are variables present, the command 'GO TO <i>n</i>' can give a 'C
Nonsense in BASIC' error when 9999&lt;<i>n</i>&lt;=32767; for example:

<code>LET a=1: GO TO 24832</code>

gives the error 'C Nonsense in BASIC, H832:1'. This happens because the routine
at #R$196E (called from #R$1B9E) finds the definition of the variable 'a' in
the variables area, the first two bytes of which are 97 (the ASCII code for
'a') and 0, and takes it to be line number 24832 (97*256).

The command 'GO TO <i>n</i>' gives an 'N Statement lost, 0:255' error when
32768&lt;=<i>n</i>&lt;=61439. (See the check at #R$1B83: a line number greater
than 32767 indicates the editing area.)

The command 'GO TO <i>n</i>' (appropriately) gives a 'B Integer out of range'
error when <i>n</i>&gt;=61440. (See the check at #R$1E6E.)

[Bug:dontCloseTheStreams:Don't close the streams]
It can be dangerous to close a stream, especially if it's aleady been closed or
was never opened. For example, on a freshly booted Spectrum:

<code>CLOSE #4</code>

makes the computer hang.

The root cause is that there is no end marker in the #R$1716(close stream
lookup table). This makes the '#S/JP (HL)/' at the end of the routine at
#R$1701 jump to #R$175B, and the '#S/RET/' that follows at #h175C causes an
indirect jump to #h5C1E (an address pushed onto the stack earlier at
#R$1701#$1701). After proceeding through the RAM at #h5C1E onwards, and
disabling interrupts along the way, the Spectrum finally hangs on the
'#S/HALT/' instruction at #R$1303.

If there were an end marker (&00) in the close stream lookup table, the
'#S/JP (HL)/' at the end of the routine at #R$1701 would jump to #R$171C, the
'#S/RET/' that follows at #h171D would return to #R$16EB, and the stream would
be closed successfully.

[Bug:pressAlmostAnyKey:Press (almost) any key]
Not every key besides 'n', 'N', BREAK and STOP will work at the 'scroll?' and
'Start tape then press any key.' prompts: pressing CAPS LOCK, or GRAPHICS, or
CAPS SHIFT and SYMBOL SHIFT together at these prompts causes the previous edit
line to appear at the bottom of the screen instead.

This is because the routine at #R$10A8, which is used (via #R$15D4) to decode a
keypress, copies the edit line to the lower part of the screen when the mode
changes (from 'L').

[Bug:scrollingTokens:The scrolling tokens]
When the program

<code>10 PRINT "a": GO TO 10</code>

is RUN, pressing CAPS LOCK (or GRAPHICS, or CAPS SHIFT and SYMBOL SHIFT
together) at the 'scroll?' prompt places 'RUN' in the edit area, and then
pressing ENTER fills the screen with BASIC tokens. Pressing ENTER at the next
'scroll?' prompt leads to more BASIC tokens and other characters being printed,
and then the program stops with a 'K Invalid colour' error.

This happens because the #REGde register pair - which is used by the section of
code at #R$203C to hold the address of the next character to be printed - is
corrupted during the call to #R$0010 (made by the '#S/RST/ #o10' instruction at
#R$2042) and ends up pointing at #R$00B8 after CAPS LOCK and ENTER are pressed
at the 'scroll?' prompt. #REGde is then incremented through the #R$0095(token
table) until it reaches #h01F4 and the 'scroll?'  prompt is printed again.
After ENTER is pressed at this prompt, #REGde is incremented through the
remainder of the token table, and then through the #R$0205(key tables), and
then into the routine at #R$028E, until it reaches #h0290, where it finds the
control character &11 (PAPER) followed by &FF (the first two bytes of the
'#S/LD DE/,#oFFFF' instruction at #R$0290), which produces the 'K Invalid
colour' error.

This bug would be prevented if #REGde were saved before the call to #R$15D4 at
#R$0CB3, and restored afterwards.

[Bug:impatientScrollPrompt:The impatient 'scroll?' prompt]
When the program

<code>10 FOR n=1 TO 100: PRINT n: NEXT n</code>

is RUN, pressing TRUE VIDEO or INV. VIDEO at the 'scroll?' prompt causes the
screen to scroll once, prints a 'scroll?' prompt, scrolls the screen again
without waiting for a keypress, and then prints another 'scroll?'  prompt
indented by 7 spaces.

This happens because when TRUE VIDEO or INV. VIDEO is pressed at the initial
'scroll?' prompt, the routine at #R$10A8 interprets the keypress as an INVERSE
control code (&04 or &05) and changes the input address for the current channel
from #R$10A8 to #R$110D (see #R$1105). This means that after the next 'scroll?'
prompt is printed and #R$15D4 is called, #R$110D (which picks up the parameter
for the INVERSE control code instead of waiting for a keypress, and does not
reset the print position for the lower part of the display in preparation for
the next 'scroll?'  prompt) is executed instead of #R$10A8 (which would wait
for a keypress, and then reset the print position for the lower part of the
display).

[Bug:anythingEqualsSCREEN$xy:Anything equals SCREEN$ (x,y)]
Some care is needed when using SCREEN$, because it doesn't always work as you
would expect. For example:

<code>IF ""=SCREEN$ (0,0) THEN PRINT "?"</code>

will print "?" no matter what is on the screen at (0,0) at the time.

The reason is that the routine at #R$2535 exits via #R$2AB2, which results in
the character found at (0,0) being stored on the calculator stack twice instead
of just once. So when the '=' operation above is performed, the last two items
on the stack - the two copies of SCREEN$ (0,0) - are equal, and the result of
the operation is always true, regardless of what's on the left hand side of the
equation.

Note that the calculator stack is cleared before each statement of a BASIC
program (or the edit line) is executed, so the bug is confined to the statement
that contains SCREEN$, and will not affect any other statements.

[Bug:34thBitOfDivision:The 34th bit of division]
In the division loop at #R$31D2, the 34th bit of the quotient is always set to
0, meaning that some results - such as 1/10 and 1/1000 - are not rounded up as
they should be. For example:

<code>PRINT 1/2-.5</code>

prints '2.3283064E-10' instead of '0', because while '1/2' is calculated
correctly, '.5' is evaluated as '5 * 1/10', which is not calculated correctly.
Specifically, '1/10' is represented as #S/7D 4C CC CC CC/ (0.0999999999767) in
floating point form, but if the 34th bit were included, it would be rounded up
to #S/7D 4C CC CC CD/ (0.100000000006), which is more accurate.

The problem is caused by the jump at #R$31FF, which should be to #R$31DB
instead of #R$31E2.

[Bug:troubleWith-65536:The trouble with -65536]
In some circumstances, the number -65536 is stored in short form instead of
full floating point form, which causes problems. For example:

<code>PRINT -65535-1</code>

prints '-1E-38', and:

<code>PRINT INT -65536</code>

prints '-1'.

The first of these problems is caused by the routine at #R$3014, which fails to
detect an overflow when adding two small negative integers whose sum is -65536.
Specifically, when #R$302B is reached, the carry flag is set, #REGa holds &FF
(the sign byte of the second number), and #REG[(HL)] also holds &FF (the sign
byte of the first number). Then:

#TABLE(asm,address-1,instruction,comment-1)
{ #h302B | #S/ADC A,(HL)/    | #REGa=&FF (&FF plus &FF plus carry). }
{ #h302C | #S/RRCA/          | #REGa=&FF, carry flag set. }
{ #h302D | #S/ADC A/,#o00    | #REGa=&00. }
{ #h302F | #S/JR NZ/,#R$303C | This jump is not made. }
TABLE#

The result is then stored as 00 #S/FF/ 00 00 00, which other ROM routines do
not always handle correctly.

The second problem is caused by the routine at #R$3214. Specifically, the
section of code at #R$3225 checks whether the argument <i>x</i> satisfies
-65537&lt;<i>x</i>&lt;=-65536; if it does, its floating point form is
(erroneously) modified to 00 #S/FF/ 00 00 00. (-65537 in floating point form is
91 80 00 80 00, which explains why the mask &80 is used when testing the fourth
byte of <i>x</i> at #R$3230.)
