The PAUSE Bug Explained

Anything Sinclair ZX Basic related; history, development, tips - differences between BASIC on the ZX80 and ZX81
Post Reply
stroebeljc
Posts: 67
Joined: Thu Apr 23, 2020 6:02 am

The PAUSE Bug Explained

Post by stroebeljc »

The ZX81 "PAUSE bug" Explained

After trying to understand the exact nature of the ZX81 ROM PAUSE bug, I decided to write down the observed behavior for anyone interested. I'm sure there are details that others on this forum could add or correct, and I hope this thread can pull them out to be a one-stop shop for the information.

The PAUSE Bug is easily observed on systems with First Edition ROMs after executing the PAUSE command (either from the command line or in a BASIC program) in FAST mode with a value of 32767 or less. It's insidious that the system freeze does not occur immediately but will manifest after several minutes unless the solution prescribed in the ZX81 User Manual (POKE 16437,255) is applied. It also only occurs if the PAUSE is not interrupted by a key press.

The PAUSE Bug actually has two issues that result in a system crash. The first and most prevalent issue, along with other issues in the First Edition ROM were addressed in the subsequently released Second Edition ROM. The second PAUSE issue was addressed in the third and final edition of the ROM.

The PAUSE issues stem from the fact that the PAUSE command utilizes the video FRAMES counter, which is described in the ZX81 User Manual as follows:
ZX81 User Manual wrote:Counts the frames displayed on the television. Bit 15 is 1. Bits 0 to 14 are decremented for each frame set to the television. This can be used for timing, but PAUSE also uses it. PAUSE resets to 0 bit 15, puts in bits 0 to 14 the pause length. When these have been counted down to zero, the pause stops. If the pause stops because of a key depression, bit 15 is set to 1 again.
This explanation sets the stage for how things eventually go wrong. It is important to understand just how the FRAMES counter works. After a reset or NEW command, FRAMES is set to zero. At the start of each frame, the display routine decrements FRAMES by one. This means the counter actually counts down from 0. After FRAMES is decremented, bits 14 through 0 are checked. If they are all zero, bit 15 is evaluated to determine if the PAUSE command is active (0 is PAUSE active). If this bit is zero, the display routine returns to the calling function, which is assumed to be the PAUSE command. If bit 15 is one, then PAUSE is not active, and bit 15 is set to zero so that an underflow condition does not occur. This leaves FRAMES in its reset state allowing it to be decremented from zero on the next frame.

Next, the display routine checks for a keypress and returns to the calling routine if one occurs. The calling routine is either the PAUSE routine or the routine that waits for key presses when the edit line is displayed. PAUSE ignores which key is pressed and finishes its processing, while the wait-for-keypress routine expects a valid keypress to have occurred.
Pause Bug.PNG
The designers chose to temporarily enter FAST Mode during the PAUSE command, presumably because no user code would be running, and the display needed to be drawn for the duration of the pause. The result is the familiar screen flicker seen when pressing keys while in FAST mode. At the end of the PAUSE command, the display mode is restored to its original state.

When a PAUSE command is issued on the command line or in a BASIC program, there are three possible behaviors:
  1. The value passed to PAUSE is in the range 32768 to 65535 (bit 15 set), and FRAMES is set to that value (with the upper bit set, we are effectively in the range -1 to -32768) for the first frame, and then decrements each frame thereafter. Because FRAMES is forced to zero when it reaches -32768, the PAUSE command will remain in effect indefinitely until a keypress, after which the display mode is returned to its original setting, followed by the setting of FRAMES bit 15. This is inconsequential since the bit is already set. The behavior works as intended, and there is no system error.
  2. Display mode is FAST, and the value passed to the PAUSE command is 0 to 32767. FRAMES is set equal to the value passed to the PAUSE command (bit 15 is 0). Video frames are continuously displayed as FRAMES decrements toward zero. There are now two options:
    1. Display frames stop when a key is pressed, and execution returns to the PAUSE routine. No display mode transition is necessary, so no additional frames are displayed. Bit 15 of FRAMES is set to 1, effectively subtracting 32768 from the current count, which has not reached zero. The value of FRAMES after leaving the PAUSE command is in the range of -32767 (1-32768) to -1 (32767-32768). This is the expected range for FRAMES when not paused, so the behavior works as intended, and there is no system error.
    2. Display frames stop when FRAMES reaches zero, and execution returns to the PAUSE routine. No display mode transition is necessary, so no additional frames are displayed. Bit 15 of FRAMES is set to 1 at the end of the PAUSE command, effectively subtracting 32768 from zero. Herein lies the cause of the infamous “PAUSE Bug”. FRAMES is now -32768 (0x8000), but the display routine never gets a chance to check for the underflow condition because it always decrements FRAMES before performing the check. On the next frame, FRAMES gets decremented to 32767 (0x7FFF) causing the display routine to assume the PAUSE command is active (bit 15 is 0). The display routine continues to decrement FRAMES and process keypresses. However, the calling routine is now the wait-for-keypress routine. When FRAMES reaches 0, the display routine returns to the keyboard decoder routine, but no key has been pressed. The keyboard decoder does not expect this and gets stuck in an infinite loop. This system freeze occurs 32767 frames after the PAUSE command is completed. Divide this by your fps of choice to figure out how long that is. Also, remember that FRAMES freezes when frames are not being displayed during FAST mode.
  3. Display mode is SLOW, and the value passed to the PAUSE command is 0 to 32767. FRAMES is set equal to the value passed to the PAUSE command (bit 15 is 0). The display mode is set to FAST, and video frames are continuously displayed as FRAMES decrements toward zero. Display frames stop when FRAMES equals zero (the end of the pause) or a key is pressed. Execution control returns to the PAUSE routine, and the display mode is restored to SLOW. Since a display mode transition is required, another frame is displayed, and FRAMES is decremented. After displaying this frame, the PAUSE routine sets bit 15 of FRAMES to 1. The behavior works as intended and there is no system error for all values of FRAMES except for one. I’ll call this one the “Lesser-Known Pause Bug.” If FRAMES was 1 when the keypress is serviced, the subsequent decrement to 0 for the display mode transition with a clear bit 15 causes the display routine to assume that PAUSE is still active, and it attempts to return execution to the PAUSE routine. However, since this already happened after the keypress, the top of the program stack does not contain the next instruction in the PAUSE routine and could cause the Z80 to vector anywhere. In this scenario, the program crash occurs immediately. This scenario was left over in edition 2 of the ROM and subsequently corrected in edition 3. Due to the required timing of having the keypress coincide with FRAMES equaling 1, it is unlikely to be observed, but not impossible.
The Pause Bug Solution

As mentioned previously, Sinclair knew about the Edition 1 Pause Bug before the User Manual was published. The manual included instructions to POKE memory after completing a PAUSE to allow users to fix the problem. This solution was also employed in the Edition 2 ROM by replacing the instruction that set only the upper bit of FRAMES with one that sets the upper byte to 255. The POKE also sets the upper byte of FRAMES to 255, which forces the counter to be in the range of -256 to -1, eliminating the underflow situation while still causing the display routine to determine that a pause is not active.

The Lesser-Known Pause Bug Solution

Ironically, while the Pause Bug only occurs during FAST mode, the Lesser-Known Pause Bug only occurs during SLOW mode. Apparently, due to the low probability of this bug, Sinclair was either unaware of it when they issued the second edition ROM, or they knew about it but wanted to fix the bigger problems with the first edition ROM and hastily released the second edition before solving this one. The solution to this bug, implemented in the third edition of ROM, was simply to force the FRAMES update before switching back to SLOW mode rather than after, thereby preventing this unique underflow situation from occurring. Without the third edition ROM, the only solution that can prevent this scenario is to switch to FAST mode before a PAUSE command is issued. Otherwise, you're playing the odds, hoping that your user doesn't press a key at precisely the wrong time. :D
John
User avatar
1024MAK
Posts: 5118
Joined: Mon Sep 26, 2011 10:56 am
Location: Looking forward to summer in Somerset, UK...

Re: The PAUSE Bug Explained

Post by 1024MAK »

Thank you 8-)

Mark
ZX81 Variations
ZX81 Chip Pin-outs
ZX81 Video Transistor Buffer Amp

:!: Standby alert :!:
There are four lights!
Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb :!:
Looking forward to summer later in the year.
Post Reply