The Spectrum, as you may well know, is a machine of very many bugs. Some
of these bugs crop up only in BASIC, some occur only in the use of machine
code, while others are manifest all the time. Though the ROM (or ROMs, as
there is more than one type of Spectrum) cannot be written to, and therefore
the bugs cannot in general be cured, knowledge of their existence can
certainly help us to avoid them, or get round them in some way.
This article is therefore a compilation of all the bugs that I know of which
occur in the 16K and 48K Spectrums, the 128 and 128+2, and also the ZX
Interface One which runs the microdrives.
It is almost impossible to classify bugs in any sensible manner. What I have
done is to group them into fairly large and ambiguous clumps such as "PRINT
errors", "CALCULATOR errors", and so forth. Where possible credit has been
given, but no doubt other people will have made simultaneous discovery of
these bugs - this is always the way.
I shall start off with three bugs which I couldn't fit into any category at all.
The CLOSE # Bug
(from Understanding Your Spectrum, by Martin Wren-Hilton)
The CLOSE # bug is present on all Spectrums unless a ZX Interface One is
attached. If you attempt to close a stream which has not previously been
opened by using the BASIC CLOSE statement then the system will almost
invariably crash. More often than not causing a system reset. The presence
of the ZX Interface One cures this bug by transferring control to its own
ROM (the Shadow ROM) whenever the program counter reaches address 1708. The
bug is caused by the table in the 48K ROM at address 1716 not being
terminated by a 00 byte. It is interesting to note that Sinclair could have
cured this bug in the Spectrum 128 - after all, they did make a few other
alterations to the ROM - but alas they chose to leave the bug in place
despite its serious consequences.
The PLOT bug
(from ZX Computing Monthly - Toni Baker)
The BASIC PLOT statement suffers from the fact that it will accept negative
co-ordinates. In fact the statement PLOT X, Y really turns out to mean PLOT
ABS (X), ABS (Y). This is caused by a failure to test the D and E registers
on return from the CALL_STK_TO_BC instruction at address 22DC.
The SCREEN ONE bug
(from ZX Computing Monthly - Toni Baker)
The Spectrum 128 offers a choice of two different areas of memory which may
be used to hold the television picture. These are called SCREEN ZERO (the
normal one, at address 4000) and SCREEN ONE (the alternative, at address
7C00). The instruction POKE 23388, 24 will activate screen one, whereas POKE
23388, 16 will activate screen zero. The bug occurs in the rare
circumstances of the silicon disc area becoming full (in which case files
may collide with the screen) or if more than 217 files, however small, are
SAVE!d (in which case the catalogue collides with the screen. The bug is
caused by the complete failure of the RAMdisc system to recognise the
existence of screen one. The following BASIC program demonstrates this bug
and is fun to watch.
10 POKE 23388, 24: REM activate screen one
20 FOR I = 1 TO 562
30 SAVE! "F" + STR$ I CODE 0, 1
40 NEXT I
50 PAUSE 0
60 POKE 23388, 16: REM activate screen zero
The CHR$ 9 error
(from Understanding Your Spectrum, by Dr. Ian Logan)
CHR$ 9 is supposed to print as "forwardspace" (the opposite of backspace).
In other words the effect of PRINT CHR$ 9 is supposed to be that the print
position is moved rightward by one character square without altering the
contents of the screen. Sadly, this does not work. Not only does the print
position not move at all, but the character at the current print position is
accidentally recoloured with the current colours. The first of these faults
is due to the fact that the cursor right subroutine at address 0A3D ends
with RET, instead of with JP 0ADC, PO_STORE, however the second fault is due
to sloppy thinking as the system variable MASK_T should have been assigned
with FF and then restored.
The CHR$ 8 error
(from Understanding Your Spectrum, by Dr. Frank O'Hara)
CHR$ 8 prints as "backspace" - that is - when printed it will move the print
position leftward by one character square. However - if the current print
position is AT 1, 0; then backspace will not work. Furthermore, it is
possible to backspace from position AT 0, 0; (which should not be possible)
and this can produce some interesting results. The bug is caused by the
cursor-left subroutine at address 0A23 testing for line one instead of line
zero. The byte at address 0A33 should be 19h instead of 18h.
The STR$ error
(from Understanding Your Spectrum, by Tony Stratton)
This is a bug which manifests itself in both BASIC and machine code. In
BASIC the statement PRINT "BUG"+STR$ 0.5 will simply print "0.5". In
machine code the bug manifests itself in the PRINT_FP subroutine at address
2DE3, whose purpose is to print the floating point number at the top of the
calculator stack to the current channel. This subroutine is called by the
STR$ routine and in this way the bug also appears in BASIC. The bug occurs
whenever the number at the top of the calculator stack (or the argument of
STR$) lies between -1 and +1 exclusive (excluding zero). In such a case an
erroneous zero is left at the top of the calculator stack, and it is this
which causes all the problems. In BASIC the bug can be avoided by using
temporary variables - e.g. LET A$=STR$ 0.5: PRINT "BUG"+A$ will work. In
machine code it is advisable to use the following subroutine in place of
PRINT_FP, as this takes the bug into account.
2A,65,5C PRINT_FP_OK LD HL,(STKEND) ; HL points to end of calculator stack. 22,5F,5C LD (X_PTR),HL ; Store in system variable. CD,E3,2D CALL 2DE3; PRINT_FP ; Print the floating point number. 2A,5F,5C LD HL,(X_PTR) ; HL points to end of calculator stack +5. 11,FB,FF LD DE,FFFE ; DE = -5. 19 ADD HL,DE ; HL points to end of calculator stack. 22,65,5C LD (STKEND),HL ; Restore (STKEND) to its correct value. FD,36,26,00 LD (X_PTRhi),00 ; Cancel error pointer. C9 RET ; Return.
The COLOUR COMMANDS error
(from Master Your ZX Microdrive, by Andrew Pennell)
If any channel other than the screen or the keyboard is selected as the
current channel (i.e. if the last thing PRINTed was to a channel other than
"K" or "S") then the permanent colour commands will erroneously transmit the
colour control codes to the last channel used. The bug is caused by the
failure to select channel "S" at the start of the subroutine CO_TEMP_1 at
address 21E1. It is possible to get round the problem by preceding each
permanent colour command by a PRINT statement (e.g. PRINT;: INK 4).
The COLOUR CONTROLS error
(from ZX Computing Monthly - Toni Baker)
If any non-standard channel (e.g. a user-defined channel) is selected as the
current channel then the colour statements such as PAPER 4 (etc.) will
produce report C: Nonsense in BASIC if the channel output subroutine returns
with the carry flag set. This bug is only visible in machine code. To cure
the problem it is necessary to ensure that all channel output routines
return with the carry reset, at least for control codes 10h to 15h and their
second parameter.
The RS232 COLOUR COMMANDS error
(from ZX Computing Monthly - Toni Baker)
This is for users of 128K machines only. On both the Spectrum 128 and the
Plus2 the command LPRINT INK 4 will produce error report C; Nonsense in
BASIC. There are two reasons for this. Firstly, the new channel "P" (the
built in RS232 socket) erroneously expects the colour controls to be
followed by two parameters instead of just one, and secondly the ROM routine
sets the carry flag (oops! see previous error). Sinclair may like to know
that the byte at 086D (128) or 088C (128+2) should be 01 instead of 02, and,
further, that the byte at 087C (128) or 089B (128+2) which currently reads
CCF should be replaced by AND A.
The DIVISION error
(from Understanding Your Spectrum, by Dr. Frank O'Hara)
The BASIC statement IF 1/2<>0.5 THEN PRINT "BUG" is sufficient to
show that there is a bug somewhere in the works. The bug is in the division
routine, which fails to register the thirty-fourth bit of a division. The JR
displacement at address 3200 directs control to the label DIV_START instead
of DIV_34TH. This means that numbers may not be correctly rounded up. You
can avoid any major problems by using IF ABS (X-Y<2.15E+9) instead of IF
X=Y.
The -65536 error
(from Understanding Your Spectrum, by Dr. Ian Logan)
The ROM is inconsistent about the calculator five-byte form of the number
-65536. Some parts of the ROM assume that only numbers in the range -65535
to +65535 may be treated as integers, whereas other parts of the ROM allow
an integer from -65536 (as opposed to a full loading point form). This error
can be demonstrated by the now famous statement PRINT INT -65536 which gives
-1.
The SCREEN$ error
(from Understanding Your Spectrum, by Stephen Kelly and others.)
The BASIC routine for calculating SCREEN$ accidentally leaves a duplicate
entry of the string result at the top of the calculator stack. This means
that the BASIC statement IF "X"=SCREEN$(0,0) THEN PRINT "BUG" will
invariably print "BUG" no matter what happens to be on the screen at the
time. The bug is fortunately not present in machine code, and calling the
subroutine S_SCRN$_S will evaluate SCREEN$ correctly, leaving the stack
correct. As with the STR$ error the best way to avoid it in BASIC is to use
temporary variables, e.g.
LET A$=SCREEN$(0,0):IF "X"=A$ THEN PRINT "BUG" will work correctly.
The MOD/DIV error
(from ZX Computing Monthly - Toni Baker)
Calculator code 32 (initiated by RST 28) is supposed to remove two items
from the calculator stack - X and Y, say, and replace them by the quantities
X MOD Y, X DIV Y in that order. [Note: X MOD Y means X - Y * INT (X/Y),
whereas X DIV Y means INT (X/Y) ]. Unfortunately, it fails to take into
account the fact that the INT subroutine corrupts calculator memory zero
whenever its argument is negative. This means that the quantity X MOD Y will
be incorrect whenever X/Y is negative. The bug could have been cured had
Sinclair ensured that the MOD/DIV subroutine at address 36A0 utilised
memory one instead of memory zero.
The E-TO-FP error
(from ZX Computing Monthly - Toni Baker)
Calculator code 3C (initiated by RST 28) is supposed to multiply the item at
the top of the calculator stack by the factor 10^A. Unfortunately, unlike
the B register, the A register is not preserved by RST 28, and so by the
time the byte 3C is reached the A register will have already been corrupted.
The only way out of this problem is to use endcalc/LD A,XX/CALL 2D4F,
E_TO_FP/RST 28 instead of the byte 3C in your code.
The INKEY$#0 error
(from ZX Computing Monthly - Toni Baker)
Normally, stream zero represents the keyboard, so we would expect INKEY$#0
to be similar in operation to INKEY$ (without a stream number). This,
however, is not the case, and INKEY$#0 almost invariably produces an empty
string, making it completely useless. Note also that calculator code 1A
evaluates INKEY$#X (where X is the item at the top of the calculator stack)
and this too will be useless whenever stream X represents the keyboard. The
bug is in the subroutine at address 1634 which makes channel "K" the current
channel. The instruction RES 5,(FLAGS) at address 1638 erroneously cancels
out any key press which would otherwise have been detected. The bug could
have been cured in the READ_IN subroutine at address 3645 by preserving the
value of (FLAGS) during the call of CHAN_OPEN.
The FN error
(from ZX Computing Monthly - Toni Baker)
When a user-defined function is evaluated the value of the system variable
(CH_ADD) which stores the address of the next character to be interpreted,
is saved on the machine stack instead of in one of the dynamic variables
such as (X_PTR) during the evaluation of the function. This means that any
user-defined function which causes the BASIC program area to move up or down
in memory will cause error report C: Nonsense in BASIC. This is not normally
possible, but exceptions can occur if the DEF FN statement contains the
function USR, and could also conceivably happen with the function INKEY#X.
To avoid this bug you must ensure that any machine code subroutine which is
called by a DEF FN statement does not disturb the BASIC program area (e.g.
it is impossible to define a function FN D (X,Y) which would delete BASIC
lines X to Y inclusive without also manipulating the machine stack).
The USR error
(from ZX Computing Monthly - Toni Baker)
Machine code programmers will be so familiar with this one that they don't
even think of it as a bug any more. The problem is that the HL' register,
whose value is required by the RST 28 sequence at address 2756, is not
preserved by the USR subroutine at address 34B3. This means that any machine
code subroutine which disturbs the value of HL' (it should contain 2758)
will crash the system upon return. To avoid this bug simply ensure that HL'
contains 2758 upon execution of the final RET statement of any machine code
subroutine called by USR.
The SCROLL? error
(from Understanding Your Spectrum, by Dr. Ian Logan)
Whenever a prompt message such as "scroll?" Or the cassette messages appear,
the Spectrum waits for you to press a key. The problem is that if you press
the wrong key, things go wrong. Pressing TRUE VIDEO, INV VIDEO, CAPS LOCK,
GRAPHIC or EXTEND MODE causes the previous edit line to appear at the bottom
of the screen, with the 48K flashing cursor (even on 128K machines). This is
because the KEY_INPUT subroutine at address 10A8 is designed to deal with
CAPS LOCK, mode changing, and colour control parameters, however this is
inappropriate for prompt messages.
The CURRENT LINE CURSOR error
(from Understanding Your Spectrum, by Paul Harrison)
This bug is applicable only on the 16K and 48K Spectrums. 128s don't have
this problem because the EDIT key doesn't do quite the same thing. Type 9000
PRINT/9001/EDIT (note that "/" stands for ENTER) and, provided there are no
lines greater than 9000, you'll see the problem - a GREATER-THAN symbol
appears in the edit line. The bug occurs in the OUT_LINE routine at address
1855. The bug could have been avoided if the subroutine had refused to print
the GREATER-THAN cursor whenever bit four of (FLAGS2) is set.
The LEADING SPACE error
(from Understanding Your Spectrum, by Dr. Ian Logan)
Bit zero of (FLAGS) is supposed to be set whenever a leading space is not
required for a keyword token. Unfortunately, the ROM is not consistent about
its use, as the one-line program
CLS: FOR I=1 TO 5: PRINT CHR$ 244: NEXT I
will prove. The problem would be solved if the flag were to be set every
time CLS were executed, or whenever a control character 00 to 1F were
printed.
The K-MODE error
(from Understanding Your Spectrum, by Chris Thornton)
This is another one for 16K and 48K Spectrums only. If, when editing program
line, the cursor is a flashing "K" then the editor is said to be in K-mode.
This means that the next key you press will be interpreted as a keyword, so
that if you press "P" for instance, then you'll get PRINT. The problem is
that if you hold a key down so that it repeats then K-mode remains in force.
This means that you could end up with a line like "NEXT NEXT" instead of
"NEXT N". The bug is caused by the K_REPEAT routine at address 0310. To work
properly the routine would have to subtract hex A5 from the key value
whenever this was greater than hex E5. This would replace keywords with
capital letters.
The SYNTAX CHECK error
(from Master Your ZX Microdrive, by Andrew Pennell)
On the 16K and 48K Spectrums the four keywords ERASE, MOVE, FORMAT and CAT
have incorrect syntaxes. The statements ERASE (string) : MOVE (string),
(string) : FORMAT (string) : CAT will be accepted as program lines, but will
give error messages if you try to run them. On the 128K Spectrums the
statement MOVE (string), (string) will be accepted as a program line, but
treated as a REM statement on running. The bug in the 48K machine is due to
the fact that the syntaxes of these Interface One commands were incorrectly
anticipated. On the 128 a wholly new syntax routine is included, and the
commands ERASE and CAT have been taken over for use with the silicon disc
system, whilst FORMAT has been taken over for use with the RS232. MOVE,
however, is not used at all, and the original false syntax has been
reproduced in an entirely new syntax routine in the new ROM.
Hook codes are used to call subroutines in the Interface One's Shadow
ROM. There are two errors in these:
The READ-N error
(from Master Your ZX Microdrive, by Andrew Pennell)
Hook code 2F (READ_N) was intended to read a block of data from the "N"
channel (the local area Network). The carry flag is assigned to indicate
success or failure, but unfortunately the carry flag is subsequently
destroyed by a call to the border restore routine.
The SET-T-MCH error
(from Master Your ZX Microdrive, by Andrew Pennell)
On version one issues of the Interface One, hook code 2B (SET_T_MCH)
accidentally calls the OPEN_M routine instead of SET_T_MCH, making it
identical in operation to hook code 22. The bug has been cured in later
editions of the Interface One, and in these later editions it correctly
performs its task of creating a temporary "M" channel in the channel
information area.
The MONOPOLISING OF IY error
(from ZX Computing Monthly - Toni Baker)
Though not strictly an "error" as such it is worth noting that the
Spectrum's interrupt routine contains the instruction INC (IY+40), which is
intended to increment the high byte of the (FRAMES) variable (when
necessary), however to do this IY must have a value of 5C3A at all times
while interrupts are enabled (unless of course you define your own interrupt
routines). Unfortunately, IY is not temporarily assigned with this value
within the interrupt routine itself. The effect of this misdemeanour is that
the value contained by IY must never be changed (unless interrupts are
disabled or an alternative interrupt routine supplied). This restricts us,
because it means that a machine code register which could have been
available to us now must not be touched. It is possible to cure this
condition by using the following program as an interrupt routine.
FD,E5 INT_ROUTINE PUSH IY ; Preserve the IY register. FD,21,3A,5C LD IY,5C3A ; IY contains value required by normal interrupt routine. FF RST 38 ; Execute normal interrupt routine. FD,E1 POP IY ; Restore IY register. C9 RET ; Return.
The SWAP error
(from ZX Computing Monthly - Toni Baker)
The SWAP routine which switches between the two ROMs of the 128K Spectrum
invariably enables interrupts, which may not always be desired. Fortunately,
this error may be cured by the following program:
ORG 5B00 C3,??,?? SWAP JP SWAP_OK ; Redirect control to revised routine. ORG ???? F5 SWAP_OK PUSH AF ; Stack A and F. C3 PUSH BC ; Stack B and C. ED,5F LD A,R ; P/V flag = interrupt status. F5 PUSH AF ; Stack interrupt status. 01,FD,7F LD BC,7FFD ; BC=port number required for paging. 3A,5C,5B LD A,(BANK_M) ; A=current page. EE,10 XOR 10 ; Complement 'ROM' bit. F3 DI ; Disable interrupts (in case an interrupt occurs between the next two instructions. 32,5C,5B LD (BANK_M),A ; Store revised page. ED,79 OUT (C),A ; Actually change ROM. F1 POP AF ; P/V flag=former interrupt status. E2,??,?? JP PO,SWAP_OK_2 ; Jump if interrupts previously disabled. FB EI ; Re-enable interrupts. C1 SWAP_OK_2 POP BC ; Restore B and C. F1 POP AF ; Restore A and F. C9 RET ; Return.
Simply write the instruction JP SWAP_OK to location 5B00, where SWAP_OK is the address of the program.
The PLAY error
(from ZX Computing Monthly - Toni Baker)
At address 09CD in the 128, or 09EC in the 128+2, the STK_FETCH subroutine
is called from the old ROM. At this point interrupts are disabled and IY is
now being used as a pointer to the master PLAY information block.
Unfortunately, because of the two bugs listed above, interrupts are enabled
during the STK_FETCH call, leaving IY containing the wrong value. This means
that if an interrupt were to occur during execution of the subroutine then
there would be a one in 65536 chance that (IY+40) will be corrupted - this
corresponds to the volume setting for music channel A. In practice this
circumstance is very rare indeed. Rewriting the SWAP routine as above will
cure this bug.
This group of errors are bugs in the Spectrum's own error handling routines!
The INVALID FILENAME error
(from Master Your ZX Microdrive, by Andrew Pennell)
If the Interface One is attached then the error message "Invalid filename"
is replaced by the message "Nonsense in BASIC", which is not particularly
helpful.
The INVALID DEVICE EXPRESSION error
(from ZX Computing Monthly - Toni Baker)
Most ironic of all is the curious error which only occurs with the
combination of ZX Interface One and Spectrum 128 or 128+2. If you have a
BASIC line such as 1000 OPEN 4, "X" (the line number must be greater than
999) then you should by rights get the error message "Invalid device
expression, 1000:1" - indeed, true to form, the Spectrum does indeed attempt
to produce this message for us. Unfortunately, the message is just too long
to fit on a line! The thirty three characters in the error message will not
fit on a line of only thirty two squares. The Spectrum 128's marvellous
little full screen editor only allows for a lower screen of two lines
(including one blank line above the error message), but this particular
error message takes three lines, not two! If you're using only the lower two
lines as the editor then the effects of the bug aren't too bad: you merely
get a few spurious things happening at the bottom of the screen. If you're
using the whole screen as an editor however then the bug is FATAL, causing
an unavoidable system reset in 48K mode! A shame really - the poor thing was
only trying to tell you about a bug in your BASIC. Never mind - after all
nobody is perfect.
These errors have been reported after the original article was published.
The CLEAR PRINTER BUFFER Bug (48K mode only)
This routine should really start by checking bit 1 of FLAGS to see if stream
3 is in use. As a consequence of ignoring this the printer buffer is
needlessly cleared after the COPY command and also when the COPY command is
interrupted by pressing BREAK. Even worse, if stream 2 is in use, i.e. COPY,
then the DFCC system variable is loaded with the address of the start of
the printer buffer as the CLEAR-PRB routine exits to PO-STORE via CLS-SET.
This will lead to an "Out of screen" error if subsequent PRINT commands do
not include an AT clause. e.g.
PRINT : COPY : PRINT
The rest of the ROM is so well developed that this check must once have been
in place. Instead there's a half-baked attempt to circumvent the use of
23681.
The PRCC Error (48K mode only)
This is more a bug in the manual although the ROM code is untidy (see
above). The manual says that 23681 is unused whereas it is the high byte of
PRCC and should never be altered. At one time the printer buffer followed
the system variables as it did on the ZX81. With a few more system variables
for network and RS232 the high byte could increment as characters were
printed. When the printer buffer was moved to it's current location an
attempt was made to set the low byte of the system variable directly within
the CLEAR-PRB routine. However this instruction is superfluous and the
variable is updated in full by PO-STORE. This can be demonstrated with
10 POKE 23681,64 : LLIST
This uses the first 256 bytes of the screen as a printer buffer and if you
look carefully at the screen, you may be able to make out the listing.
The NEW COMMAND Bug (128K mode only)
The initialisation routine of the 128K ROMs (Sinclair 128K, Amstrad +2,
Amstrad +3, and possibly +2A) intentionally set main memory to the following
values
60435,0
65316,0
65317,236
This is very hard to detect as the only non-zero byte is immediately below
the machine stack and soon overwritten. The NEW command unfortunately also
sets these locations even if they are above RAMTOP. Consequently utilities
which are designed to survive NEW don't.
Examples are Zeus assembler, Devpac, Basic extensions and other languages.
MAIN-4, (48 ROM-1303h)
There are two problems with the MAIN-4 routine. First if it is called with
interrupts disabled it will crash because of the HALT instruction. Second it
is missing a SET 1,(IY+1) instruction (which tells the Spectrum to use the
printer instead of the screen). The result is that typing LPRINT "bug";:
PRINT, pressing enter and then typing PRINT will generate an Out of screen
error.
KEYCLICK, (128 ROM-26F1h)
(Ian Collier)
On the +3, the 128 (and presumably the +2) also has the wrong memory
location to check the length of the keyclick. This is why it sounds deeper
in 128 Basic.
LOWER SCREEN EDITING, (128 ROM-2DA1)
(Ian Collier)
Also spotted on the +3, replicated at this address on the 128 (and somewhere
else on the +2).
128 MENU (128 ROM)
Not exactly a bug. The menu is centred over the copyright message on the 128
but on later machines it no longer looks centred because of the length of
the copyright message. Amstrad only needed to change four bytes to centre it
on the screen!
WRITE TO ROM (48 ROM-33FEh)
Not so much a bug as poor coding. The ROM tries to write four bytes starting
at 0000h. On a real Spectrum there is usually no effect because you can't
actually write to the ROM, but if a copy of the ROM is really in RAM (to
give better compatibility on a +3 or +2A for instance), the 'ROM' could be
overwritten.
The SCROLL? error (48 ROM)
Not only does this affect the 'Scroll?' prompt, but also the 'Start tape and
press any key.' prompt. Pressing 'any' key will not always work!
The RAM test (48 ROM-11CEh)
Again, not a bug as such. The RAM test had a secondary function on the
original Spectrum of detecting if it was a 48K or 16K machine but as it only
tests the first 48K of RAM serves no purpose on 128 machines and could have
been replaced with a more efficient memory wipe routine.
The EDIT key bug (48 ROM-1860h)
If you enter a line 9000 REM bug. Then enter 9001 and then press EDIT the
'>' cursor appears in the line.
The DRAW commands (48 ROM)
The PLOT, DRAW, CIRCLE and POINT commands are limited to the normal
printable area (32x22 characters). There was no reason to stop users using
the lower two lines of the screen.
The GOTO bug (48 ROM)
The result you get of attempting to GOTO a non-existent line depends on
whether it is above or below 16384. It appears the ROM originally supported
line numbers up to 16383 and the only logical reason for limiting it to 9999
is the problem of error messages going off the screen.
The RESTORE bug (48 ROM)
Basically, typing RESTORE 61250 will put the machine in a continual loop,
effectively crashing it.
The CHR$ 27 bug (48 ROM-09F7h, only affects 128)
(Andrew Owen)
The Spectrum character set is just like normal ASCII (except for the POUND
and COPYRIGHT symbols) from code 32 to 127. But, codes lower than those are
used for setting colour and position and so on, while some are not used at
all. The upshot of which is, 128 machines cannot generate special printer
codes (using code 27) from BASIC. Changing one byte from 20h to 18h would
allow the use of codes 24-31, and while they would print garbage on the
screen, they would be able to control a printer connected to the RS232 port
(or parallel on the +3/+2A).
My thanks to Geoff Wearmouth, Ian Collier and Andrew Owen for expanding my original list and for their continued work on the Spectrums previously undocumented features.