On Sat, 23 Sep 2000, I wrote:
> Anyway, I'll program the following test tonight:
>
> 1. set line interrupt to line 100 (any line is OK)
> 2. enable line interrupt (IE1:=1)
> In the interrupt handler:
> 3. poll until start of line (using HR)
> 4. disable line interrupt (IE1:=0)
> 5. read FH (status register 1)
>
> Step 4 and 5 are short enough to occur within a single display line. So if
> my model is right, FH will be 0, if your model is right, FH will be 1.
I had to add a step at the start of the interrupt handler, to return if it is
a vertical retrace interrupt instead of a line interrupt.
After that, the test ran OK and it returns 1. So you (Alex Wulms) were right!
If I add a little wait loop, the test returns 0. I calculated the number of
clockcycles and the number of Z80 cycles necessary to make the test return 0
and it corresponds with approximately 1 line.
However, there is still a strange thing. When IE1 is 0 and I read FH several
times on a row, it will return 1 four times, after that it will return 0. The
execution time of four times "IN A,(&H99) \ LD (ADDRESS),A" is roughly
equivalent of "LD B,7 \ LOOP: DJNZ LOOP".
When I swap step 4 and 5 in the test program, so that IE1 is 1 while reading
FH, FH is reset after the first read. So it seems FH is only reset when read,
if IE1 is set.
I verified this with a simpler test program, the one that does a lot of
INIRs. The result: when IE1==0, FH==1 for 2 to 3 INIR cycles, but when
IE1==1, FH==1 for only 1 INIR.
A new attempt to a model of the line interrupt:
(I used the notation of Alex Wulms, because it was very clear)
All relevant definitions on a row:
-FH: Bit 0 of status register 1
-IE1: Bit 4 of mode register 0
-IL: Line number in mode register 19
-DL: The line that the VDP is going to display (corrected for vertical scroll)
-IRQ: Interrupt request line of VDP to Z80
At the start of horizontal refresh (HR becomes 1), the VDP does:
-FH = FH || (IL==DL)
At the end of horizontal refresh (HR becomes 0), the VDP does:
-FH = FH && IE1
After reading of status register 1 by the CPU, the VDP does:
-FH = FH && !IE1
Furthermore, the following is true all the time:
-IRQ = FH && IE1
The resulting behaviour:
When IE1=0:
-FH will be set as soon as display line IL is reached
-FH will be reset as soon as the next horizontal refresh is finished
Note:
-FH will *not* be reset when status register 1 is read
When IE=1:
-FH and IRQ will be set as soon as display line IL is reached
-FH and IRQ will be reset as soon as status register 1 is read
Note that "HR becomes 0" and "HR becomes 1" are educated guesses. It matches
the timing I observed (for example, SCREEN0 horizontal refresh is about 400
VDP XTAL cycles) and it seems logical. But I didn't test it explicitly.
I think this model explains all the measurements I did so far. Please look at
it critically and try to spot errors.
One question that is still bugging me, is why David's trick works. Does it
depend on pure coincidence that the "HR becomes 0" moment is just inbetween
disabling IE1 and re-enabling it? Or does writing VDP register 0 affect FH?
In case anyone wants to verify thing, or do some more test, I included the
test programs.
First test program:
============================================================
; If IE1=0, is FH reset immediately (my theory) or at the start of
; next line (theory of Alex Wulms)?
RG0SAV: EQU &HF3DF
OUTPUT: EQU &HD000
ORG &HC000
DI
; setup interrupt handler
LD A,&HC3
LD HL,INT_RT
LD (&HFD9A),A
LD (&HFD9B),HL
; set interrupt line
LD A,100
OUT (&H99),A
LD A,&H93
OUT (&H99),A
; enable line interrupt
LD A,(RG0SAV)
OR &H10
OUT (&H99),A
LD A,&H80
OUT (&H99),A
; done
EI
RET
INT_RT:
; return if this is a vertical retrace interrupt
IN A,(&H99)
RLA
RET C
; status register 2
LD A,2
OUT (&H99),A
LD A,&H8F
OUT (&H99),A
; wait until end of line
LOOP1:
IN A,(&H99)
BIT 5,A
JR Z,LOOP1
; wait until start of line
LOOP2:
IN A,(&H99)
BIT 5,A
JR NZ,LOOP2
; status register 1
LD A,1
OUT (&H99),A
LD A,&H8F
OUT (&H99),A
; disable line interrupt
LD A,(RG0SAV)
OUT (&H99),A
LD A,&H80
OUT (&H99),A
; read and store FH
IN A,(&H99)
LD (OUTPUT),A
; status register 0
XOR A
OUT (&H99),A
LD A,&H8F
OUT (&H99),A
; disable interrupt handler
LD A,&HC9
LD (&HFD9A),A
; done
RET
============================================================
Second test program:
(remove the "OR &H10" to run the test with IE1==0)
============================================================
; Reads and stores line interrupt status a whole lot of times.
RG0SAV: EQU &HF3DF
ORG &HC000
DI
; set line interrupt
LD A,128
OUT (&H99),A
LD A,&H93
OUT (&H99),A
; enable line interrupt
LD A,(RG0SAV)
OR &H10
OUT (&H99),A
LD A,&H80
OUT (&H99),A
; VDP status reg 1
LD A,1
OUT (&H99),A
LD A,&H8F
OUT (&H99),A
; read and store &H1000 times
LD HL,&HC200
LD BC,&H99
INIR
INIR
INIR
INIR ;4x
INIR
INIR
INIR
INIR ;8x
INIR
INIR
INIR
INIR ;12x
INIR
INIR
INIR
INIR ;16x
; disable line interrupt
LD A,(RG0SAV)
OUT (&H99),A
LD A,&H80
OUT (&H99),A
; VDP status reg 0
LD A,0
OUT (&H99),A
LD A,&H8F
OUT (&H99),A
; the end
EI
RET
============================================================
Bye,
Maarten
****
Problems? contact [EMAIL PROTECTED] See also http://www.faq.msxnet.org/
****