PROCESSOR GLITCH (1/2)

ZXNet echo conference «code.zx»

From Kirill Frolov To All 27 November 1998

Hi, All! Taken from ZX.SPECTRUM: =================================================================================== = (c) Ivan Roshchin, Moscow, 11/13/1998 Fido: 2:5020/689.53 E-mail: asder_ffc@softhome.net ┌─────────────────────────────────┐ │ │ │ Undocumented feature │ │ Z80 processor │ │ │ └─────────────────────────────────┘ Permission is granted to freely distribute this article, subject to without making any changes and maintaining my copyright ta. 1. How it all started ────────────────────── I once wrote the next version of the BestView program (v2.4), and I used this fragment in it: .... EI CALL SUBR1 HALT .... SUBR1 LD A,R PUSH AF D.I. .... POP AF D.I. RET PO EI RET In this fragment, the procedure SUBR1 is called, which for the duration of its operation, it disables interruptions, and when it exits, it restores restores their previous mode of operation. Checking whether call interrupts are enabled or disabled procedures, and restoration of the interrupt mode occurs as follows: in a general way: - the LD A,R command enters the trigger state into the P/V flagIFF2 interrupts; - register pair AF is stored on the stack (PUSH AF); - interrupts (DI) are disabled; - in fact, those functions are performed for which the SUBR1 procedure was intended; - AF contents are restored (POP AF); - interrupts are disabled (DI); - if the P/V flag is cleared, the procedure exits with disabled interrupts (RET PO); - otherwise there is an exit with interrupts enabled (EI: RET). I began to notice that when this BestView fragment was running, hangs - not always, and not even too often, but in very rare cases cases. But still it was not very pleasant. Program, seemed to contain no errors, at least from the first I didn’t notice anything suspicious. All that remained was resort to stronger means... 2. The situation is starting to clear up ──────────────────────────────── After another freeze, I inserted a blank disk and confidently pressed the MAGIC button. Then I loaded the debugger "STS 6.2 +@" (not in vain I remade it - now with its help after loading the @-file you can restore the contents of processor registers at the time reset the program to disk). Press a couple of keys - and now I see where in the program did the freeze occur? .... EI CALL SUBR1 HALT <------------ here! ....A typical case is that interrupts are disabled and the processor stops working. executing the program using the HALT command. But why interruptions? turned out to be prohibited - it is unclear. After all, before calling procedure SUBR1 they were resolved by the EI command, and after finishing SUBR1 they must also be allowed - procedure SUBR1 should not render call influence on their operating mode. I'm tracing SUBR1. Everything goes as expected - both at the entrance and at interrupts remain enabled at the output. I repeat the trace: once, twice, ... tenth. So far, so good. Or maybe it's because there's something wrong with SUBR1 stack? And because of this, sometimes the co- held AF? We should check... 3. Freezes: take two ────────────────────────── Well, I remade the program. Now I will know for sure what's the matter: SUBR1 LD A,R PUSH AF D.I. PUSH HL PUSH AF POP HL LD (WR_HH1),HL POP HL .... POP AF PUSH HL PUSH AF POP HL LD (WR_HH2),HL POP HL D.I. RET PO EI RET WR_HH1 DW 0 WR_HH2 DW 0 AF contents are now remembered not only in the stack, but also in variable WR_HH1 (for control), and when exiting the procedure -The value removed from the stack is stored in WR_HH2. If the procedure works correctly, WR_HH1 and WR_HH2 should match, and the P/V flag be installed. I launch it... BestView has been working fine for a minute now... Using it, I view the same file that, when viewing it froze last time... Well, here we go again! And no wonder After all, I haven’t eliminated the cause. Okay, we'll figure it out. I press MAGIC again, load "STS 6.2 +@" and immediately check I change the values of WR_HH1 and WR_HH2. Both there and there #5908 is recorded. Know- The values coincide - therefore, when working with the error stack there are no it was. But if the flag register contains #08, then the flag P/V was reset, and when calling the SUBR1 procedure, interrupts were disabled puppies. But this is completely impossible! After all, the program contains EI: CALL SUBR1! Probably the Spectrum just overheated, and that’s why glitches. I didn’t come up with anything smarter that day. 4. False trail ────────────── The next day I found a possible explanation for the mysterious disable interrupts. Let's say after the EI command, but before execution The LD A,R command was interrupted. As is known, the process the foolishness of its processing should end with EI:RET commands (because that at the beginning of processing there is an automatic prohibition of pre- jerking). If the interrupt handler simply terminates with the RET command, interrupts will remain disabled.Of course, the probability that an interruption will occur is between the commands EI and LD A,R is very small, but also freezes come out very rarely. So this once again confirmed my gi- hypothesis. However, it remained unclear why this handler interrupts ended with the RET command, not EI:RET. I decided to check to see if this is really the whole point, and for this I added le EI command HALT (see below). If the interrupt handler really terminates incorrectly, then after the added HALT interrupts will always be disabled, and, accordingly, BestView will always freeze. .... EI HALT <------ added command CALL SUBR1 HALT .... SUBR1 LD A,R PUSH AF D.I. .... POP AF D.I. RET PO EI RET I compile, run... A completely unexpected result - Freezing has completely stopped! I wanted to leave it like that, but Still, I decided to figure out why this happens. 5. “Program simplification” technique ────────────────────────────── When I can't find an error using normal means, I delete from the program everything that is possible, but so that the error remains. As a result, when there are only a dozen lines left of the program, the error is met immediately. This is what I did this time: ORG #6000 EIM1 CALL SUBR1 JR M1 SUBR1 LD A,R D.I. JP PO,M2 EI RET M2 LD A,4 OUT(254),A RET Here is a program, only 19 bytes. Interrupts are enabled and in an endless loop, procedure SUBR1 is called. This procedure sets a green border if there is an interrupt when entering it were disabled, and does not change the border color if interrupts are enabled Sheny. Thus, if spontaneous prohibition occurs interruptions, this will be immediately noticeable. I run it - yes, the border changes its color to green. Reason Such strange behavior of the program remains unknown. Maybe Maybe the type 1 interrupt handling procedure is to blame for this? I add several commands to the program that set the IM mode 2 with a handler consisting of only two commands: EI:RET. ORG #6000 LD HL,#8000 LD (HL),#81 LD DE,#8001 LD BC,#100 LDIR LD A,#80 LD I,A IM 2 EI M1 CALL SUBR1 JR M1 SUBR1 LD A,R D.I. JP PO,M2 EI RET M2 LD A,4 OUT(254),A RET ORG #8181 EI RET I run it - the same result! Although when tracing both this andthe previous program in the debugger, the border remains black. Attention A careful study of the program leads to the assumption: maybe the LD A,R command sometimes sets the P/V bit as if Is jerking prohibited when in fact it is allowed? 6. Is there really an error in the processor? ─────────────────────────────── I'm changing the program again. Now there will be no interruptions at all disabled (DI command removed). If, when executing the LD command A,R bit P/V will become equal to 0, for some time the border will become green (there is a delay for this): ORG #6000 LD HL,#8000 LD (HL),#81 LD DE,#8001 LD BC,#100 LDIR LD A,#80 LD I,A IM 2 EI M1 CALL SUBR1 JR M1 SUBR1 LD A,R RET PE LD A,4 OUT(254),A LD HL,0 LD DE,0 LD BC,#600 LDIR ;WAIT XOR A OUT(254),A RET ORG #8181 EI RET I launch... And what do I see? The upper part of the border flashes green linen: ┌─────────────────────────────────┐ │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│ │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│ │▒▒▒▒ ▒▒▒▒││▒▒▒▒ ▒▒▒▒│ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────────┘ This suggests that, firstly, the command LD A,R is valid Actually, sometimes the P/V bit is set incorrectly, and secondly, that this happens at the moment the interrupt arrives, and not at any time (indeed, then the border would blink green in a completely pro- in random places). The fact that the top of the border is blinking and not constantly colored Shena in green also gets its explanation. Apparently the LD A,R command does not work correctly only when the pulse interruption comes during its execution, but this happens far away not always - interruption can occur during execution another team. ================================================================================