Deja Vu #08
31 мая 1999 |
|
CODING - an undocumented feature of the processor Z80.
AY-Track: Muzic theme from game "FAIRLIGHT" __________________________________________ (C) Ivan Roshchin __________________________________________ Undocumented feature CPU Z80 Allowed free This article provided no kakihlibo make changes and save my copyright. 1. How it all began I wrote once the next version of the program BestView (v2.4) and used it Here's a snippet: .... EI CALL SUBR1 HALT .... SUBR1 LD A, R PUSH AF DI .... POP AF DI RET PO EI RET In the snippet is a procedure call SUBR1, which at the time of his work disables the interrupts, while output recovers the previous regime of their work. Verifying that are allowed or disallowed interruption in the procedure call, and restore interrupt mode is as follows: - The team LD A, R enters into a flag P / V coc Toyan trigger interrupt IFF2; - Register pair AF is stored in the degree Ke (PUSH AF); - Do not Interrupt (DI); - Are satisfied, in fact, the functions for which was designed and procedure SUBR1; - The contents of AF recovered (POP AF); - Interrupts are prohibited (DI); - If the flag P / V reset is exited of the procedure prohibited by interrupting mi (RET PO); - Or exits to the allowed Interrupt (EI: RET). I began to notice that when running this fragment BestView hangs - not always, and not even too often, but in very rare cases. But still, it was not very nice. The program, like, did not contain no errors, at least at first See anything suspicious, I did not notice. Had only to resort to more a powerful tool ... 2. The situation begins to brighten After another hang-up, I put a blank disk and confidently pressed the MAGIC. Then loaded the debugger "STS 6.2 + @" (not I reworked it for nothing - now using it after downloading @ file, you can restore the contents of CPU registers on the instant relief to disk). Pressure a pair of keys - and now I see where in the program crash happened. .... EI CALL SUBR1 HALT <------------ here! .... A typical case - Interrupt prohibited and the processor has stopped execution of the program on the command HALT. But why break proved to be forbidden - it is not clear. After all, before calling the procedure SUBR1 they were allowed Team EI, and after work SUBR1 they too should be allowed SUBR1-procedure should not affect on the mode of their work. They trace SUBR1. Everything goes as expected - And at the entrance and exit interrupts are allowed. Repeat trace: once, twice ... tenth. Everything is going fine. And maybe the fact that SUBR1 something happens with the stack? And because of this sometimes incorrectly restored the contents of AF? We ought to check out ... 3. Hanging: double second Well, rewrote the program. Now there I'll know exactly what it was: SUBR1 LD A, R PUSH AF DI 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 DI RET PO EI RET WR_HH1 DW 0 WR_HH2 DW 0 The contents of AF now remembered not only in the stack, but in variable WR_HH1 (Control), and at the exit from the procedure - Removal from the stack value is stored in WR_HH2. If the procedure works correctly, WR_HH1 and WR_HH2 must match, and the flag P / V to be installed. Run ... For a moment BestView works fine ... Look through with it the same file, while viewing that it hung the last time ... Well, again! And no wonder, because the reason I not eliminated. Okay, we understand. Again, press MAGIC, load "STS 6.2 + @ ", And immediately check the value and WR_HH1 WR_HH2. And there, and there is written # 5908. Values are the same - hence, when working with a stack of errors was not. But if the flags register contains # 08 - hence the flag P / V is reset, and the procedure call SUBR1 interrupts were prohibited. But it's absolutely impossible! Indeed, in program is EI: CALL SUBR1! Probably Spectrum just overheated and because such glitches. Nothing is more intelligent I am in this day never came up. 4. False scent The next day I found a possible explanation for the mysterious Prohibition interrupts. Suppose, after the team EI, but before command LD A, R, there was an interruption. As is known, the procedure for its treatment must end teams EI: RET (because in the beginning of treatment there is an automatic ban on interrupts). If the interrupt handler completes the team just RET, then the interrupt remain prohibited. Of course, the likelihood that an interrupt will occur precisely between the teams and EI LD A, R is very small, but you and lag are very rare. So it's an extra just confirmed my hypothesis. Nevertheless, it was unclear why would this hook ended with command RET, but not EI: RET. I decided to check whether this is the whole thing, and for this added after the command HALT EI (See below). If the interrupt handler did not completed successfully, then after adding HALT'a interrupts are always will be prohibited and, accordingly, BestView will always hang. .... EI HALT <------ add commands CALL SUBR1 HALT .... SUBR1 LD A, R PUSH AF DI .... POP AF DI RET PO EI RET Compile, run ... An unexpected result - hangs completely stopped! Like everything and leave, but he decided to find out why this happens. 5. Acceptance of "simplification program When finding an error by conventional means can not, I delete all of the programs that possible, but that the error in this case remained. As a result, when the program is with a dozen lines, the error is noticeable immediately. So I entered and this time: ORG # 6000 EI M1 CALL SUBR1 JR M1 SUBR1 LD A, R DI JP PO, M2 EI RET M2 LD A, 4 OUT (254), A RET That such a program, a total of 19 bytes. Allowed interruption and in an infinite loop procedure is called SUBR1. This procedure sets the green border, if at the entrance to her termination was prohibited, and does not change the color of the border, if the interruption allowed. Thus, if an spontaneous ban interrupt it will be immediately noticeable. Run - yes, border changes color to green. The reason for this strange behavior of the program remains unknown. Perhaps this fault interrupt handling routine one of the first kind? Add to Playing multiple teams, setting IM 2 mode with a handler, which consists 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 DI JP PO, M2 EI RET M2 LD A, 4 OUT (254), A RET ORG # 8181 EI RET Run - the same result! Although the tracing, and this and the previous program in the debugger border is black. Careful examination of the program leads to hypothesis: maybe the team LD A, R sometimes sets a bit P / V as if the interruption is prohibited while on Indeed, they allowed? 6. Is the error in the processor? Once again change the program. Now do not interrupt will be banned (removed command DI). If when you run LD A, R-bit P / V becomes equal to 0, for some time border is green (for This provides for the delay): 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 Run ... And what I see? Upper part border'a flashes green: This suggests that, firstly, the team LD A, R do sometimes incorrectly sets bit P / V, and secondly - what this is happening at the moment of arrival interrupt, but not when you want (indeed, then it would blink green border in a completely random locations). The fact that the upper part border'a flashes and not always painted in green, also receives an explanation. Apparently, the team LD A, R is not working only when the impulse to interrupt comes during its execution, as it happens not always - an interrupt can occur during the execution of another team. 7. Final confirmation We verify this fact. Let processor interrupt determines where in a interrupted program. If it was interrupted just after the command LD A, R, let the curb for some time to yellow: 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 BP1 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 EXX EX AF, AF ' POP HL PUSH HL LD DE, BP1 SBC HL, DE JR NZ, NE_BP1 LD A, 6 OUT (254), A LD HL, 0 LD DE, 0 LD BC, # 600 LDIR; WAIT NE_BP1 EXX EX AF, AF ' EI RET If incorrect operation command LD A, R not connected with the fact that during its execution of the pulse interrupt, then we see how the top will border'a flashes then green, then yellow. But if the relationship between these two events there, then we should see how top border'a flashing yellow and the lower part - the green, and they should blink completely in sync. Run - and I see exactly what and expected. Indeed, such a relationship exist: But as can be related interruptions and teamwork LD A, R? This team puts in a flag P / V content trigger interrupt IFF2. When interrupt enable this trigger is 1, and when it comes to interrupt the momentum, it is automatically reset to 0 to eliminate reprocessing interruption. However, query processing interrupt begins during the last execution carried out by the bar team (Ie, commands LD A, R). And, apparently, already thrown trigger IFF2 copied to the flag P / V (indeed, in terms of CPU, interrupt at this point is already prohibited). All of the above applies to the command LD A, I. This information has been verified on the original Z80 CPU ZILOG firm and domestic counterparts KR1858VM1. 8. What does it lead and what to do? Application commands LD A, R and LD A, I for determine the status of interrupt trigger, generally used in many programs (and even in the ROM TR-DOS). Here you and an explanation of a number of strange lockups. It seems as if the probability of the pulse interrupt it at the time of the command LD A, R is small. But, first, the probability increases due to that this command can be executed in program more than once (and for hovering enough only incorrect execution), and secondly - if the program to This team met HALT, that is, synchronization with interrupts, it may happen that the command LD A, R will always be executed at a time when most likely the next interrupt (or was BestView). Thus, this method is unreliable. But how do be? It turns out that with 100% accuracy determine the status of interrupt trigger by the following simple rule: - Execute the command LD A, R; - If the flag P / V = 1 - means Interrupt in fact authorized; - If the flag P / V = 0 - any interruption in actually prohibited, or permitted, but the team LD A, R incorrectly planted a flag. To resolve this uncertainty, again run the command LD A, R. If now Flag P / V = 0 - hence, interrupts are prohibited (in fact, may not be so and run-time second-team LD A, R has occurred - between the two preemption is 1 / 50 seconds, and between the two teams LD A, R - much less time). If the flag P / V = 1 - mean interrupts are enabled. Here's the relevant code fragment: SUBR1 LD A, R JP PE, M1 LD A, R M1 PUSH AF DI .... POP AF DI RET PO EI RET 9. How do I use it? With a team of LD A, R is convenient to carry out testing of the processor to recognize the program under the emulator. Z80 emulator executes instructions sequentially, one after another, and the team LD A, R will always be properly installed Flag P / V. A real-Z80 is not. Here is a simple procedure for testing the processor, which returns the battery 1, if it is running on a real Z80, and 0 otherwise. She tries to 65536 times read register R for interrupt enable, and if this even though least once a flag P / V set to 0 - it is concluded that the procedure works on Real-Z80. TESTZ80 EI LD BC, 0 M1 LD A, R JP PO, QUIT INC BC LD A, B OR C JR NZ, M1 RET QUIT LD A, 1 RET If recognized by the emulator, you can either terminate the program (a kind of protection), or disable some program segments that can be wrong work under the emulator (for example, instead of direct work with the use point VG93 Input # 3D13, etc.). 10. Correction STS 6.2 In a debugger STS definition status of trigger interrupt also occurs with the command LD A, R. Because of this, may not hold tracing program. When tracing STS runs each command (except for command transfer control) with the help of residents and after its implementation stores the contents of processor registers and trigger status interrupts. That's where mistakes are possible. Assume interrupts are enabled and traced a simple program: # 8000 NOP # 8001 JR # 8000 Stopping the trace after a time (if this option is disabled Indicate one minute is enough), we see that interrupts were prohibited. If traced to a real program, such a ban could have an interrupt impact on the entire course of its further implementation and even lead to a crash (if when tracing has got to command HALT). It is obvious that the STS should be correction. Here's how for version 6.2: You must first download and run the STS file "sts6.2", which will be made and corrections. Then you need to find a free 14-byte - Their function will be explained below. You can use the clipboard user function (With address # FE37). But in the version of the STS, I use this buffer is occupied by procedure of disassembling an assembly with labels ZX ASM, so I decided to cut Some text messages: 'Block' -> 'Bl.' (Save 2 bytes) 'Save' -> 'S.' (----/----- 2 --/--) 'Load' -> 'L.' (----/----- 2 --/--) 'DEFB' -> '' (----/----- 4 --/--) 'FileName' -> 'Name' (----/----- 4 --/--) For this purpose, the address must be entered # EB24 the following sequence of bytes: # EB24: AE 46 72 6F ED 54 EF 46 # EB2C: 69 6C E5 53 65 63 74 6F # EB34: F2 53 AE 4C AE 53 74 6F # EB3C: 70 20 69 E6 42 61 6E EB # EB44: 51 75 69 F4 54 72 61 63 # EB4C: E5 53 74 61 72 44 69 F4 # EB54: 73 61 73 ED A0 46 69 6C1 # EB5C: E5 42 41 53 49 C3 20 44 # EB64: 4F D3 At # E702 changes the value of # 0A at # 0E, to correctly print the name File (FileName as string instead of just left Name). So now with the address # EB66 free 14 bytes. See where the STS is to determine the state trigger interrupts: # DFFE: LD (# 5BA1), SP LD SP, # 5BA1 PUSH BC PUSH AF LD A, R DI LD BC, # 7FFD LD A, # 1F OUT (C), A LD B, # BF LD A, # 00 OUT (C), A JP # E028 Replace command LD A, R: DI on NOP, but team JP # E028 - to JP # EB66. C address # EB66 put this snippet: # EB66: LD A, R JP PO, # EB6E NOP JR # EB70 LD A, R < > DI JP # E028 Please note - this piece in any case, their work enhances Register R by the same amount (7). The fact is that more will be done yet one team LD A, R, this time the desired is to determine the value of the register R, and correction will be made resulting values, because R register value increases with each command, and need to know its value at the end of the implementation team traced. Here it looks like: # DCA2: LD A, # 5A LD HL, # FEF4 SLA (HL) RLA ADD A, (HL) RRCA LD (HL), A RET Constant # 5A at # DCA3 should replaced by # 53, ie, reduced by 7 - since the program was added an additional fragment, which increases the register R at 7, and must compensate for this change. After that you only write modified file to disk.
Other articles:
Similar articles:
В этот день... 21 November