Why are my VINTs and HINTs firing at the same rate?

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Why are my VINTs and HINTs firing at the same rate?

Post by BigEvilCorporation » Wed Nov 11, 2015 11:03 pm

I do hope this is just a schoolboy error that someone can spot, but I noticed I was getting multiple vertical interrupts for each of my game frames, something I thought I'd protected against by waiting for the next VBLANK at the top of the frame.

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:

Image

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)
Any ideas at all?
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

Mask of Destiny
Very interested
Posts: 616
Joined: Thu Nov 30, 2006 6:30 am

Re: Why are my VINTs and HINTs firing at the same rate?

Post by Mask of Destiny » Thu Nov 12, 2015 1:46 am

I think we're either going to need more of your source code or a ROM. I'm not aware of any way to get the level 6 interrupt to fire more often than once per frame/field so I'm guessing your handler is being called inadvertently some other way.

BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Re: Why are my VINTs and HINTs firing at the same rate?

Post by BigEvilCorporation » Thu Nov 12, 2015 9:30 am

I'll see if I can narrow it down to a minimal test case this evening, this code base is a bit of a monster.
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Re: Why are my VINTs and HINTs firing at the same rate?

Post by BigEvilCorporation » Thu Nov 12, 2015 7:11 pm

Ahah I feel like such an idiot, I'd left this in from some experimentation ages ago:

Code: Select all

move.w #0x8ADF, vdp_control     ; Set H interrupt timing
The VINTs and my game frames match up, which is what's important. This threw my debug counter off.

I am, however, still seeing the original problem - I'm getting VINT fired in the middle of my game frames - but I'm wondering if that's to do with the debugger's ability to break on command, perhaps the 68K stalls a bit when entering and exiting breakpoints leaving the VDP to carry on.
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Re: Why are my VINTs and HINTs firing at the same rate?

Post by BigEvilCorporation » Thu Nov 12, 2015 7:24 pm

Yep confirmed - if I let it roll the numbers are perfectly in sync, hitting breakpoints messes it all up and I get several VINTs fired whilst the debugger is trying to get the machine to stop.
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

Sik
Very interested
Posts: 939
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Why are my VINTs and HINTs firing at the same rate?

Post by Sik » Sat Nov 14, 2015 7:58 pm

Welp. (and that was one of the dumbest mistake ever =P not like I haven't done worse)

I'm not surprised about breakpoints, though. I recall reading from the chunks of 32X devkit around (which includes some non-32X stuff too, just to make it clear) that the debugger works by overwriting the 68000 vectors with its own (after the "ROM" is loaded into the devkit's RAM). I assume this is what's going on here too.
Sik is pronounced as "seek", not as "sick".

Post Reply