You know, the VDP can trigger two kind of interrupts: a vblank, and a line interrupt. The code you posted looks correct and only handles vblank. Or at least, it looks like that.
First, the stat reg should prolly already be set at zero, so just do IN A,(#99) directly. Second, by doing RLCA you might wanna check Carry flag, not the zero flag. The Cy should contain bit 7 of A.
Here's a snippet of my code called from #38 (I've left out some, this is the base you need)
; Int. Service Routine (RST &H38) ISR: PUSH AF IN A,($99) ;statreg should be 0 RLCA LNIISR: JP NC,LNI_00 ;jump directly to line int. PUSH BC PUSH DE PUSH HL EX AF,AF EXX PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY CALL VBLANK ;the vbl int POP IY POP IX POP HL POP DE POP BC POP AF EXX EX AF,AF POP HL POP DE POP BC LNI_00: POP AF EI RET
Notice you don't have to DI, it's already disabled at this point. Second, after saving AF, a check for which int follows. In the NC case (b7=0), I assume a line interrupt. Now, in this example there's some self modifying code going on if you want a line interrupt routine be called. In this case, it just end the ISR.
By reading statreg 0, you will also automatically reset the interrupt flag.
The reason why I jump to LNI as fast as possible, is because you prolly need that timing. If you are familiar with line interrupts, screensplits, etc, you'll know what I mean. (I'm from the demo scene).
But yeah, nothing more to it. Make sure #38 is accessible, that's all.
Hey ro, thanks for the follow-up - I wanted to clarify some things since this is a common beginner issue and its all about compatibility with multiple systems.
1. SREG may actually be not 0, I do a lot of VDP commands so I use status reg 2 fairly often.
2. Ah yes... should check the correct flag of course lol. In the example code, I was cp $80 ; jr z just to be 100% sure I was doing it right. I usually do rlca ; jr c . My code is right but I do make mistakes like that late at night .
3. Thanks for the tips on speed. My current project uses mode 6 so its not a fast game overall, but Ill adjust things if I do buffer effects or timing critical stuff.
4. I could have been seeing some other bug, but in my tests on emulator, both $fd9a and $fd9f (HKEYI and HTIMI) must be called to reset all the interrupt lines. This matches the BIOS code in my MSX2, which didn't have any interrupt woes.
In addition, to make sure that the code will execute on ALL systems across all page formats, the best place for the routine is in page 3, which to my knowledge is a RAM page that is almost never paged out. The beginning of my program now starts with
ld hl,_irq ld de,0xc580 ld bc,_endirq-_irq ldir ; install ISR ld a,$c3 ld ($0038),a ld hl,0xc580 ld ($0039),hl
Again, this matches my working MSX2 system which only stores a vector to page 3 in page 0, contrasting to the A1ST whose vector remains in page 0.
Under Dos, addresses 0-255 are system reserved area, so you can't hook your interrupt routine directly to address 56.