After some debugging I figured out that I was getting VINTs at the same rate as my HINTs, which I've confirmed by debug drawing the counters:
This happens on hardware (Cross Products kit) and in the Regen emulator. I've confirmed it's not caused by the HINT trick required to run the MegaCD in Genesis (it's all compiled out in my emulator build).
What on Earth is going on? Here's the relevant parts of my VDP regs, header and interrupt routines for reference:
Code: Select all
; ******************************************************************
; Sega Megadrive ROM header
; ******************************************************************
dc.l stack_top ; Initial stack pointer value
dc.l EntryPoint ; Start of program
dc.l Exception ; Bus error
dc.l Exception ; Address error
dc.l Exception ; Illegal instruction
dc.l Exception ; Division by zero
dc.l Exception ; CHK exception
dc.l Exception ; TRAPV exception
dc.l Exception ; Privilege violation
dc.l NullInterrupt ; TRACE exception
dc.l NullInterrupt ; Line-A emulator
dc.l NullInterrupt ; Line-F emulator
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Unused (reserved)
dc.l NullInterrupt ; Spurious exception
dc.l NullInterrupt ; IRQ level 1
dc.l NullInterrupt ; IRQ level 2
dc.l NullInterrupt ; IRQ level 3
dc.l HBlankInterrupt ; IRQ level 4 (horizontal retrace interrupt)
dc.l NullInterrupt ; IRQ level 5
dc.l VBlankInterrupt ; IRQ level 6 (vertical retrace interrupt)
dc.l NullInterrupt ; IRQ level 7
Code: Select all
VBlankInterrupt:
addi.l #0x1, vblank_counter ; Increment vinterrupt counter
cmp.b #0x0, (vint_enabled)
beq @VINTDisabled
; Jump to game rendering subroutine
movem.l d0-d7/a0-a6, -(sp)
jsr __vinterrupt
movem.l (sp)+, d0-d7/a0-a6
@VINTDisabled:
rte
HBlankInterrupt:
addi.l #0x1, hblank_counter ; Increment hinterrupt counter
rte
Code: Select all
VDPRegisters:
VDPReg0: dc.b 0x14 ; 0: H interrupt on, palettes on
VDPReg1: dc.b 0x74 ; 1: V interrupt on, display on, DMA on, Genesis mode on
VDPReg2: dc.b 0x30 ; 2: Pattern table for Scroll Plane A at VRAM 0xC000 (bits 3-5 = bits 13-15)
VDPReg3: dc.b 0x00 ; 3: Pattern table for Window Plane at VRAM 0x0000 (disabled) (bits 1-5 = bits 11-15)
VDPReg4: dc.b 0x07 ; 4: Pattern table for Scroll Plane B at VRAM 0xE000 (bits 0-2 = bits 11-15)
VDPReg5: dc.b 0x78 ; 5: Sprite table at VRAM 0xF000 (bits 0-6 = bits 9-15)
VDPReg6: dc.b 0x00 ; 6: Unused
VDPReg7: dc.b 0x00 ; 7: Background colour - bits 0-3 = colour, bits 4-5 = palette
VDPReg8: dc.b 0x00 ; 8: Unused
VDPReg9: dc.b 0x00 ; 9: Unused
VDPRegA: dc.b 0x01 ; 10: Frequency of Horiz. interrupt in Rasters (number of lines travelled by the beam)
VDPRegB: dc.b 0x00 ; 11: External interrupts off, V scroll fullscreen, H scroll fullscreen
VDPRegC: dc.b 0x81 ; 12: Shadows and highlights off, interlace off, H40 mode (320 x 224 screen res)
VDPRegD: dc.b 0x3F ; 13: Horiz. scroll table at VRAM 0xFC00 (bits 0-5)
VDPRegE: dc.b 0x00 ; 14: Unused
VDPRegF: dc.b 0x02 ; 15: Autoincrement 2 bytes
VDPReg10: dc.b 0x01 ; 16: Vert. scroll 32, Horiz. scroll 64
VDPReg11: dc.b 0x00 ; 17: Window Plane X pos 0 left (pos in bits 0-4, left/right in bit 7)
VDPReg12: dc.b 0x00 ; 18: Window Plane Y pos 0 up (pos in bits 0-4, up/down in bit 7)
VDPReg13: dc.b 0xFF ; 19: DMA length lo byte
VDPReg14: dc.b 0xFF ; 20: DMA length hi byte
VDPReg15: dc.b 0x00 ; 21: DMA source address lo byte
VDPReg16: dc.b 0x00 ; 22: DMA source address mid byte
VDPReg17: dc.b 0x80 ; 23: DMA source address hi byte, memory-to-VRAM mode (bits 6-7)