Soft Group - Interesting text from Ivan Roshchin for coders.

ZX Club #09
                                
CODING                                    
                                
                                
Interesting text from Ivan Roshchin for code-
ditch Wishes, suggestions, objections,
send to my address: 2:5020/689.53   
                                
November 20, 98 Alex Letaev
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(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
articles provided that no amendments are made
changes and preservation of my copyright.   
                                
1. Where it all started                    
----------------------                                
I once wrote the next version of the program
BestView (v2.4), and used it here
this fragment:                           
                                
 ....                              
        EI                                
        CALL SUBR1                     
        HALT                              
        ....                              
                                
SUBR1 LD A,R                       
        PUSH AF                        
        D.I.                                
                                
 ....                              
                                
 POP AF                        
DI                                
        RET RO                        
        EI                                
        RET                               
                                
In this fragment there is a call to the procedure
ry SUBR1, which during its operation
disables interrupts, and when exiting, restores
restores their previous mode of operation.Checking whether they are allowed or not
interrupt when calling a procedure, and restore
The interrupt mode changes as follows:
in the following way:                           
                                
-the command LD A,R enters the flag P/V sos-
 interruption trigger IFF2 waiting;         
-register pair AF is stored on the stack
 (PUSH AF);                               
-interrupts (DI) are disabled;             
-actually, those functions are performed for
 cat and the SUBR1 procedure was intended;  
-AF contents are restored (POP AF);
-interrupts are disabled (DI);             
-if the P/V flag is cleared, exit occurs
 from a procedure with disabled interrupts
 (RET RO);                                
-otherwise exit occurs with allowed
 interrupts (EI: RET).                  
                                
I began to notice that when working this
BestView fragment freezes - not always, and
not even too often, but very rarely
cases. But it still wasn't very good
nice. The program did not seem to contain
no errors, at least from the first
I didn’t notice anything suspicious in my gaze
till.  All that remained was to resort to more
strong means...                      
                                
2. The situation is starting to clear up          
--------------------------------                                
After another freeze, I inserted the number
th disk and confidently pressed the MAGIC button.
Then I loaded the debugger "STS 6.2 +@" (not
in vain I remade it - now with his
power after downloading the @-file, you can restore
update the contents of processor registers to
the moment the program is reset to disk).  Pressing
a couple of keys - and now I see where
The program froze.            
                                
 ....                              
        EI                                
        CALL SUBR1                     
        HALT <------------ here!     
        ....                              
                                
A typical case is that interrupts are disabled, and
The processor has stopped executing the program
on the HALT command. But why are the interruptions
are prohibited - unclear.  After all, in front of you-
they were resolved by the call of procedure SUBR1
by the EI team, and after finishing the work
SUBR1 they should also be allowed -
SUBR1 procedure should not affect
influence on their operating mode.                   
                                
I'm tracing SUBR1. Everything is going as expected - and
at input and at output interruptions remain -
Xia permitted.  I repeat the trace:
once, twice...tenth.  So far, so good.                                       
                                
Or maybe the fact is that in SUBR1
is something going on with the stack? And because of this
sometimes the co-
held AF? We should check...         
                                
3. Freezes: take two                
--------------------------                
                                
Well, I remade the program.  Now
I'll know exactly what's going on:             
                                
SUBR1 LD A,R                       
        PUSH AF                        
DI                                
                                
PUSH HL                        
        PUSH AF                        
        POP HL                        
        LD (WR_НН1),HL               
        POP HL                        
                                
 ....                              
                                
 POP AF                        
PUSH HL                        
        PUSH AF                        
        POP HL                        
        LD (WR_НН2),HL               
        POP HL                        
                                
DI                                
        RET RO                        
        EI                                
        RET                               
                                
WR_НН1 DW 0                             
WR_НН2 DW 0                             
                                
AF content is now remembered not only
on the stack, but also in the variable WR_НН1 (for
control), and when exiting the procedure -
The value popped from the stack is stored in
WR_НН2. If the procedure works correctly,
WR_НН1 and WR_НН2 must match, and the flag
P/V to be set.                   
                                
I’m launching... BestView has been working for a minute now
melts normally... I look through it from her
with the power of the same file, when viewing it
Why did it freeze last time... Well,
again!  And it’s not surprising, because I’m the reason
didn't eliminate it. Okay, we'll figure it out.    
                                
I press MAGIC again, load "STS 6.2 +@"
andI immediately check the values of WR_НН1 and
WR_НН2. Both there and there #5908 is recorded.  Know-
the values coincide - therefore, when working
those with a stack of errors did not occur. But if in re-
The flag registry contains #08 - which means
the P/V flag is reset, and when calling the procedure
SUBR1 interrupts were disabled.          
                                
But this is completely impossible!  After all, in
The program costs EI: CALL SUBR1!  Probably
it's just that the Spectrum overheated, and that's why
glitches.  Nothing smarter than me this day
I never came up with it.                        
                                
4. False trail                            
--------------                            
                                
The next day I found a possible explanation
oblivion to the mysterious prohibition of interrupts.
Let’s say after the EI command, but before execution
An interrupt occurred during the command LD A,R.
As is known, the procedure for its processing is
must end with EI:RET commands (because
that at the beginning of processing occurs automatically
tically disable interrupts).  If
the interrupt handler simply terminates
RET command, then the interrupts will remain recorded
resolved.                                
                                
Of course, the likelihood that an interruption
will happen between teams EI and LD
A,Rvery small, but freezes also occur
they go very rarely.  So this is one more time
confirmed my hypothesis.                
                                
However, it remained unclear why
it would be the interrupt handler ending
with the RET command, not EI:RET.  I decided to check
wondering if this is really the point, and
for this purpose I added the HALT command after EI
(see below).  If the interrupt handler
actually terminates incorrectly, then
after the added HALT interruption is always
may be prohibited, and, accordingly,
BestView will always freeze.           
                                
 ....                              
        EI                                
        HALT <------ added command  
        CALL SUBR1                     
        HALT                              
        ....                              
                                
                                
SUBR1 LD A,R                       
        PUSH AF                        
        D.I.                                
                                
 ....                              
                                
 POP AFD.I.                                
        RET RO                        
        EI                                
        RET                               
                                
I compile, run... Completely unexpected
This result is completely freezing
stopped! I wanted to leave it like that, but
nevertheless, I decided to figure out why it was so half-
is expected.                                   
                                
5. "Program simplification" technique            
------------------------------            
                                
When you can't find an error using normal means
succeeds, I delete everything from the program
possible, but so that the error remains
las. As a result, when what remains of the program
about a dozen lines, the error is immediately noticeable. Yes
I did this time too:                  
                                
 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                               
                                
                                
Here is a program, only 19 bytes. Allow
interruptions occur, and in an endless loop
procedure SUBR1 is called.  This procedure
sets green border if
interrupts were disabled when entering it, and
does not change border color if interrupted
allowed.  Thus, if it happens
spontaneous disabling of interrupts,
it will be immediately noticeable.               
                                
I run it - yes, the border changes its color to
green. The reason for such strange behavior
program remains unknown.    Maybe
be, the processing procedure is to blame
type 1 interrupts? Adding to the program
several commands that set 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      ВС,#100                   
        LDIR                              
        LD      A,#80                     
        LD      I,A                       
        IM      2                         
                                
        EI                                
                                
M1      CALL    SUBR1                     
        JR      M1                        
                                
SUBR1   LD      A,R                       
        DI                                
        JP      РО,M2                     
        EI                                
        RET                               
M2      LD      A,4                       
        OUT     (254),A                   
        RET                               
                                
        ORG     #8181                     
                                
        EIRET                               
                                
I run it - the same result!  Although when
trace of both this and the previous program
in the debugger the border remains black. Attention
careful study of the program leads to
guess: maybe the command LD A,R
sometimes sets the P/V bit as if
then interrupts are disabled, while on
Are they actually allowed?                 
                                
6. Is there a bug in the processor?           
-------------------------------           
                                
I'm changing the program again. Now interrupt-
tions will not be prohibited at all (removed
DI command).  If when executing the command
LD A,R bit P/V will become 0, at some point
The next time the border will turn green (for this
delay is provided):                  
                                
 ORG #6000                     
                                
LD HL,#8000                  
        LD (HL),#81                  
        LD DE,#8001                  
        LD Sun,#100                   
        LDIR                              
        LD A,#80                     
        LD I,AIM      2                         
                                
        EI                                
                                
M1      CALL    SUBR1                     
        JR      M1                        
                                
SUBR1   LD      A,R                       
        RET     РЕ                        
                                
        LD      A,4                       
        OUT     (254),A                   
        LD      HL,0                      
        LD      DE,0                      
        LD      ВС,#600                   
        LDIR             ;WAIT            
        XOR     A                         
        OUT     (254),A                   
        RET                               
                                
        ORG     #8181                     
                                
        EI                                
        RET                               
                                
Запускаю...  И что я вижу?Верхняя часть
border-а мигает зеленым цветом:           
                                
Это говорит о том, что, во-первых, команда LD A,R Region Commercial Counter- Picture of Р/V, и во-вторых - this Remove the snowflake from the snow, а не когда угодно (действительно, тогда бы
border border on black- вольных местах). То, что верхняя часть border-а мигает, а If you want to be on the sidelines, back Thanks for the rest. По-виимому, ко- Let LD A,R snowflake snowflakes тогда, когдаthe interrupt pulse comes during its execution, and this happens further but not always - an interruption can occur and while another command is running. 7. Final confirmation ------------------------------ Let's check this fact. Let the handler pre- jerking determines where it was program interrupted. If it was interrupted exactly after the command LD A,R, let the border will turn yellow for a while: ORG #6000 LD HL,#8000 LD (HL),#81 LD DE,#8001 LD Sun,#100 LDIR LD A,#80 LD I,A IM 2 EI M1 CALL SUBR1 JR M1 SUBR1 LD A,R ВР1 RET РЕ LD A,4 OUT (254),A LD HL,0 LD DE,0 LD ВС,#600 LDIR ;WAIT XOR A OUT (254),A RET ORG #8181 EXX EX AF,AF' POP HL PUSH HL LD DE,ВР1 AND A SBC HL,DE JR NZ,NE_ВР1 LD A,6 OUT(254),A LD HL,0 LD DE,0 LD Sun,#600 LDIR ;WAIT NE_BP1 EXX EX AF,AF' EI RET If the LD A,R command does not work correctly is due to the fact that during its execution the impulse of interruption comes, then we will see how the top part of the border will blink then green, then yellow. But if the connection between these two events exists, then we need to see how the top border blinks yellow, and the bottom some are green, and they should blink completely synchronized. I launch it and see exactly what I expect. laged. Indeed, such a connection exists howls:
Other snowflake snowflakes and ра- Do you want LD A,R? Эта команда помещает If you want Р/V you can get a smile IFF2. При разрешешеных прерываният тот pages 1, а когда приходит импульс прерывания, он ввтотически сбрсыается
At 0, you'll see the rest of the game прерывания. This is the cover of the picture- Pages Other Brand Website Personal Blog- The price of the snowflake (т.е. Small LD A,R). И, видимо, уже сброшенный Price IFF2 in the range Р/V (дей- snowflake, snowflake snowflakes, прерывания в втот моменяalready prohibited). All of the above also applies to the LD team A.I. The information provided has been verified on the original Z80 processor from ZILOG and on the domestic analogue KR1858VM1. 8. What does this lead to and what to do? ------------------------------------ Using the LD A,R and LD A,I commands for op- determining the state of the interrupt trigger, generally speaking, it is used in many pro- grams (and even in TR-DOS ROM). Here you go explanation of a certain number of strange dependencies saniy. It seems as if the probability of coming interrupt pulse precisely during execution The opinion of the LD A,R team is small. But first of all Thus, the probability increases due to the fact that that this command can be executed in program more than once (and for freezing a single incorrect execution is enough opinion), and, secondly, if the program contains up to this was encountered by the HALT command, i.e. syn- intermittent chronicity may happen so that the command LD A,R will be every time be performed at the time when the most probably another interruption (it happened in BestView). So this method is not reliable. But how be? It turns out that it is possible with 100% accuracy determineinterrupt trigger state according to the following simple rule: -execute the command LD A,R; -if the P/V flag = 1, it means that interrupts are in are actually allowed; -if flag P/V = 0 - or interrupts in sa- are prohibited in our case, or are they permitted, but the LD A,R command set incorrectly flag. To eliminate uncertainty, execute the command LD A,R again. If and now the P/V flag = 0 - that means interruptions prohibited (in fact, it cannot be so that during execution of the second command LD A,R interruption occurred - 1/50 passes between two interrupts seconds, and between two commands LD A,R - much less time). If the flag P/V = 1 - means interrupts are enabled. Here is the relevant program fragment: SUBR1 LD A,R JP PE,M1 LD A,R M1 PUSH AF D.I. .... POPA.F. D.I. RET RO EI RET 9. How can this be used? ------------------------------ Using the LD A,R command it is convenient to perform testing the processor to recognize execution of the program under the emulator. Emu- The lator executes Z80 commands sequentially but, one after another, and the command LD A,R always- Yes, it will be correct to set the P/V flag. But in the real Z80 this is not the case. Here is the simplest procedure for testing processor, which returns to the battery tor 1, if it is running on a real Z80, and 0 otherwise. She's trying 65536 read register R once when enabled interrupts, and if at least one once the P/V flag is set to 0, it is done conclusion that the procedure works on real Z80. TESTZ80 EI LD Sun,0 M1 LD A,R JP RO,QUITINC Sun LD A,B OR C JR NZ,M1 RET QUIT LD A,1 RET If the emulator is recognized, you can either stop program execution (specifically different protection), or disable some areas of the program that may be incorrect work under an emulator (for example, instead of direct work with VG93 use point input #3D13, etc.). 10. STS 6.2 fix ----------------------- In the well-known STS debugger, the definition of co- waiting for the interrupt trigger also occurs dit using the LD A,R command. Because of this Tracing may not work correctly programs. When tracing, STS runs each command (except for control transmission commands) management) with the help of a resident, and after after its execution, remembers the contents CPU register pressure and status interrupt trigger. This is where it's possible errors.Let's say interrupts are enabled and traces The following simple program is created: #8000 NOP #8001 JR #8000 Having stopped tracing after some time, name (with the Indicate option disabled, one a minute is enough), we will see that interrupts were disabled. If only a real program was traced, such disabling interrupts could have an impact for the entire course of its further implementation and even lead to freezing (if the trace would have encountered the HALT command). It is quite obvious that the STS needs to be updated corrections. Here's how to do it for ver- this 6.2: First you need to start STS and load file "stsб.2 <С>", in which there will be corrections are made. Then you need to find the free 14 bytes - their purpose will be explained below. You can use user function buffer (with addresses #FEЗ7). But in the version of STS that I'm using it, this buffer is occupied by pro- disassembly procedure with assembly marks Blair ZX ASM, so I decided to cutsome text messages: 'Block' -> 'Bl.' (2 bytes saved) 'Save' -> 'S.' (----/----- 2 --/--) 'Load' -> 'L.' (----/----- 2 --/--) ' DEFB' -> ' ' (----/----- 4 --/--) 'FileName' -> 'Name' (----/----- 4 --/--) To do this, from the address #EB24 you need to enter the following following byte sequence: #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 F4 44 69 #EB54: 73 61 73 ED A0 46 69 6C #EB5C: E5 42 41 53 49 C3 20 44 #EB64: 4F D3 At address #E702 we replace the value #0A with #0E to print the file name correctly (since instead of the line FileName there remains just Name). So, now 14 is free from address #EB66 byte. Let's see where in STS the definition occurs. division of interrupt trigger state: #DFFE: LD(#5BA1),SP LD SP,#5BA1 PUSH Sun PUSH AF LD A,R D.I. LD BC,#7FFD LD A,#1F OUT (C),A LD B,#BF LD A,#00 OUT (C),A JP#E028 Let's replace the commands LD A,R: DI with NOP, and mandu JP #E028 - to JP #EB66. From the address #EB66 let's place the following fragment: #EB66: LD A,R JP PO,#EB6E + NOP | +- JR #EB70 | | LD A,R <---+ +>DI JP#E028 Please note - this fragment in any case during its work increases the re- gist R by the same amount (by 7). De- The point is that more will be done next one command LD A,R, perthis time it's needed already to determine the value of register R, and the received information will be corrected values, because register R value increased is executed with each command executed, and you need to find out its value at the time of completion execution of the traced command. Here what it looks like: #DCA2: LD A,#5A LD HL,#FEFЧ SLA (HL) R.L.A. ADD A,(HL) RRCA LD(HL),A RET Constant #5A at address #DCA3 should be followed by change to #53, i.e. reduce by 7 - after all an additional a fragment that increments the R register by 7, and we need to compensate for this change. After this, all that remains is to record the changes saved file to disk.

Share your thoughts about the article