Hi again,

Interrupts are REEAALLY interesting stuff, aren't they?

> > The interrupt routine should end with an instruction that re-enables the
> > interrupts. I think RETI does that. Anyway, the MSX BIOS uses EI followed
> > by RET instead.
> 
> Yup. That the BIOS uses EI is very weird. But play it safe, and use EI; RET
> like they do :)

Does RETI re-enable interrupts or not? Is this so difficult to 
determine? I think most Z80 programmers will know there are two flags 
that determine wheter (maskable!) interrupts are accepted, or not. 
These are called IFF1 and IFF2. I think everyone will agree that EI 
sets both, and DI resets both. At a reset of the Z80 CPU, these are 
both cleared (0 = DI). Note that for instance the MSX BIOS ROM 
starts at address 0 with a DI (I think it was at address 0 itself). 
Why? Well simple, because when you get to address 0, this is not 
always as a result of power on, or reset, but might also be the 
result of some jump to address 0 ("warm boot"). You would like 
things to work the same after that, right? So that's what this DI 
is for...

During a NON-maskable interrupt, these 2 IFF1 & 2 CAN differ, but not 
in the case of MASKABLE interrupts (the ones you have in the MSX). At 
least that simplifies things a bit.

At the acceptance of a (maskable!) interrupt, IFF1 and IFF2 are both 
cleared (=DI), and must be set again after that by the 
programmer/interrupt-processing routine.

But does RETI do this, or is a seperate EI needed for this?
Well, a RETI cannot restore the interrupt status from one of these 
IFF1 or 2, because in that case they might be different during 
maskable interrupts, and they're not. ANY data on the Z80 is quite 
clear these 2 can only differ in the case of NON-maskable interrupts.

So, a RETI then either works as a RET, OR as an EI/RET combination. 
Which will it be? Let's find out by just using a RETI in place of a 
RET, using this for a mini-subroutine, and check whether it 
re-enabled interrupts, or not. Let's try this piece of code, for 
instance:


sub:
        RETI
test:
        DI                  ;clear both IFF's
        CALL sub     ;and return, and EI?
        NOP
        NOP               ;just to avoid any complications
        HALT             ;that should make things clear
        RET               ;back to BASIC/DOS whatever?

If RETI does re-enable interrupts, the HALT would just give a 
1-interrupt delay, and continue after that.
If RETI does not re-enable interrupts, this HALT will bring the 
machine really to a HALT (hangs)

Now just POKE this stuff somewhere, CALL it at the "test:" address, 
and either of these 2 things will happen:
-'Ok': RETI must have re-enabled the interrupts
-hangs: RETI seems to have left the interrupts disabled

Ofcourse, don't try this on your emulator, but on a real Z80...
(will somebody try it on a R800 as well? Just for the fun of it? 
Ofcourse, use some R800 mode, and the result will be the same, no 
doubt)


I found this interesting enough to try it myself, I used a Sony 
HB-F9P for the purpose (there is a real Z80 in there somewhere).
The result: the above piece of code made the machine HANG.

So that leaves no doubt on this tiny issue: RETI does NOT, I repeat 
NOT re-enable interrupts, it works just like a normal RET, and does 
NOT, I repeat NOT include an EI-function. I said this earlier, the 
above proves I was right, at least on this one. 

To make sure I didn't make a mistake, I tried this again, replacing 
the 1st NOP in the above example with an EI. As expected: "Ok"

Then, out of curiosity, I took the same piece of code, and replaced 
only the second NOP with an EI (the first one back to "NOP"), giving 
an EI-HALT directly after each other. With interrupts disabled before 
that, theory would suggest: EI -> 1 instruction to be executed first 
(the HALT here), with interrupts still disabled, then re-enabled 
again. This should hang the machine. To my surprise, it did not.
(removing the CALL to this RETI gave the same result). What's going 
on in this case?

I found the answer to this in my Z80 databook again, I quote: "While 
in the HALT state, the processor will execute NOP's to maintain 
memory refresh logic."

In other words: In this case, when entering this HALT, interrupts ARE 
still disabled for one more instruction, but the HALT works as a 
sequence of NOP's (until an interrupt occurs). After the first 
simulated NOP, interrupts ARE re-enabled, allowing a next interrupt 
to complete the HALT instruction. Ofcourse, at that point, first the 
interrupt routine is processed, and only then the instructions after 
the HALT get executed.


Why does a MSX BIOS interrupt routine end with a EI-RET combination 
then?
a) I guess the "EI" serves as a 'just in case', in case interrupts 
are still disabled at that point, and
b) The RET after that is simply shorter, and faster than a RETI

The 'signal' function of a RETI mentioned earlier by someone, is 
simply not used in any MSX hardware, so ending the interrupt routine 
with a normal RET just makes it a tiny bit faster.


The rest of interrupt-related stuff is just a matter of how 
peripherals, like the VDP, generate them, and how you can control 
these peripherals doing this. Damn, these VDP's are complicated 
enough, though....


I hope this helps things a bit further,

Alwin Henseler    ([EMAIL PROTECTED])

http://www.twente.nl/~cce/index.htm     (computerclub Enschede)
http://huizen.dds.nl/~alwinh/msx    (MSX Tech Doc page)


****
MSX Mailinglist. To unsubscribe, send an email to [EMAIL PROTECTED] and put
in the body (not subject) "unsubscribe msx [EMAIL PROTECTED]" (without the
quotes :-) Problems? contact [EMAIL PROTECTED] (www.stack.nl/~wiebe/mailinglist/)
****

Reply via email to