Huh? Are there TWO Int2 entries on the jumptable?

Ask anything your want about Mega/SegaCD programming.

Moderator: Mask of Destiny

Post Reply
RamiroR
Interested
Posts: 18
Joined: Tue Jun 02, 2009 10:45 pm

Huh? Are there TWO Int2 entries on the jumptable?

Post by RamiroR » Fri Jun 12, 2009 1:33 am

Hi everybody.
Em.. I noticed something which is.. frustating me.
You know, the BIOS manual says that Int2 entry should not be changed since BIOS uses it.
But, I just found that there are two Int2 entries? WTF?
And Sonic CD changes these two.Why, weren't these supposed not to be changed?
$5F34: It's setup by subprogram header
$5F7C: I found it on that file full of EQUs, It's setup..... (¿¿¿¿????)

:cry:

I just noticed I am LOST

I dunno how, I made it work the last time, now I ruined it all , dammit.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Jun 12, 2009 3:18 am

If you mean on the Main-CPU side (Genesis), you only want to change the vectors at 0xFFFD00. If you mean the Sub-CPU side (CD), then you want to use the Sub-Processor Int2 entry in the Sub-Processor header table.

The Sub-Processor init code starts with a couple headers.

Code: Select all

	.org	0x6000

| Standard MegaCD Sub-CPU Program Header

SPHeader:
	.asciz	"MAIN SEGAOS"
	.word   0x0001,0x0000
	.long	0x00000000
	.long   0x00000000
	.long   SPHeaderOffsets-SPHeader
	.long   0x00000000

SPHeaderOffsets:
	.word   SPInit-SPHeaderOffsets
	.word   SPMain-SPHeaderOffsets
	.word   SPInt2-SPHeaderOffsets
	.word   SPNull-SPHeaderOffsets
	.word   0x0000
You should use that SPInt2 entry for the Int2 handling on the CD.

Clear your own VBlank vector in SPInit along with any other hardware that needs clearing.

Code: Select all

| Sub-CPU Program Initialization (VBlank not enabled yet)

SPInit:
        move.l	#0,VBlankHandler	/* clear VBlank handler vector */
        andi.b	#0xE2,0xFF8003		/* Priority Mode = off, 2M mode, Sub-CPU has access */
        move.l  #0,0xFF8020
        move.l  #0,0xFF8024
        move.l  #0,0xFF8028
        move.l  #0,0xFF802C
        move.b  #'I,0xFF800F            /* clear sub comm port - command = init */
	rts
Then in the SPInt2, check if your vector has been set and call it.

Code: Select all

| Sub-CPU Program VBlank (INT02) Service Handler

SPInt2:
	tst.l	VBlankHandler
	bne.b	0f
	rts
0:
	movem.l	d0-d1/a0-a1,-(sp)
	move.l	VBlankParam,d0
	move.l	d0,-(sp)
	movea.l	VBlankHandler,a0
	jsr	(a0)
	addq.l	#4,sp
	movem.l	(sp)+,d0-d1/a0-a1
	rts
Note that my example code above is doing a C call to the vblank handler, with a parameter passed to it.

You shouldn't be messing with INT02 in any other manner on the CD!!

On the Genesis side, you should set the vblank handler after all the init code.

Code: Select all

| set vblank int
        move.w  #0x2700,sr              /* interrupts disabled */
        lea     __vblank(pc),a0
        move.l  a0,0xFFFD08             /* level 6 redirection vector */
        move.w  #0x2000,sr              /* enable interrupts */
Note - setting the hblank handler requires setting a register in the CD gate array for redirecting it. I won't talk about that unless you really need it.

TascoDLX
Very interested
Posts: 262
Joined: Tue Feb 06, 2007 8:18 pm

Post by TascoDLX » Fri Jun 12, 2009 5:26 am

$5F7C is a vector to the level 2 (V-INT) interrupt routine. It is an interrupt/exception routine so it should finish with a RTE call. $5F34 is a vector to the program's V-INT subroutine. Since it is a subroutine, it should finish with a RTS call.

The default interrupt routine of the BIOS does only a few things. It calls a subroutine that restarts CDD communication if it stalls, it calls the program's V-INT subroutine, and it clears a flag used for the BIOS's 'wait for V-INT' subroutine. It also saves all registers so you can trash all registers in your V-INT subroutine if you want.

It's easy enough to replace the interrupt routine without screwing things up, but you shouldn't return (RTS) to the BIOS without restoring the original interrupt routine because the BIOS will call its 'wait for V-INT' subroutine and, therefore, needs that flag to be cleared.

I'm not entirely sure about losing that CDD subroutine. Things should work fine without it but it might be needed for certain unforeseen error conditions. I haven't seen what Sonic CD does, but whatever it does it seems to work fine. In any case, it's probably not worth replacing it unless you have a really good reason.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Jun 12, 2009 8:19 am

TascoDLX wrote:It also saves all registers so you can trash all registers in your V-INT subroutine if you want.
Good. One less thing to worry about with the int routine.
In any case, it's probably not worth replacing it unless you have a really good reason.
Yeah, best to play by the rules unless you have good reason not to. 8)

RamiroR
Interested
Posts: 18
Joined: Tue Jun 02, 2009 10:45 pm

Post by RamiroR » Fri Jun 12, 2009 2:43 pm

Hey, thank you two. But, about the Int2, I still don't get it :( .
At least now it doesn't crash, it just keeps doing what it should(Sub-CPU side)
On the main-cpu side..
I can't setup Vblank:
I first disable all the interrupts
Then I write to $FFFD08
Then.. I enable interrupts 6 and 7 (sr is $2500)
It looks like when Vblank happens, the thing crashes.
It can't be Hint (I disabled writting to the VDP register AND masking level 5 interrupt)

So I dunno, it just crashes..

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Jun 12, 2009 7:18 pm

Remember that the handler set by 0xFFFD08 is an exception handler. You must save and restore any registers you use, and exit using rte.

It's also the Main-CPU's responsibility to assert INT02 to the Sub-CPU in its vertical blank handler.

Code: Select all

        bset    #0,0xA12000             /* assert sub 68000 INT02 */

RamiroR
Interested
Posts: 18
Joined: Tue Jun 02, 2009 10:45 pm

Post by RamiroR » Fri Jun 12, 2009 11:00 pm

Yeah I've been told about that, now.........

Okay, I think the problem is basically..me
I don't know these terms:
V-int Handling
Int2 Handling
Interrupt processing

I don't know what "handling" would mean.
All I know about interrupts is:
You setup some entry, when the exception happens, the 68000 jumps to where it should.

I still don't get what the difference of those 2 entries is. (Sub)
And I don't get WHY this thing crashes when Vblank happens (Main)
Damn, I never can explain the problem I have.. :S

hm.. some question just came: Does Int2($5F7C) call $5F34?
Do I have to setup these two entries?
What is the difference between these two?(Sorry but I didn't understand that other post)

I'm sorry for being such a n00b at Sega CD..

I feel like when I asked how to write to the Sprite Attribute table, last year xD

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Jun 13, 2009 1:20 am

An exception handler is code the processor jumps to when an error or external event occurs. It usually pushes extra info on the stack that requires a different return opcode than the normal return from subroutine opcode. That opcode for the 68000 is rte, or return from exception. A typical exception handler looks like this:

Code: Select all

handler:
        movem.l d0-d7/a0-a6,-(sp)

        <other code here>

        movem.l (sp)+,d0-d7/a0-a6
        rte
You don't have to save ALL the registers, just the ones you use in the code. But you MUST save the ones you use, and do rte at the end.

An interrupt is an exception that is generated by an external device that is flagging a special occurance (like the vertical blank) or that the device needs service (like when the serial has a byte accumulated). As they are exceptions, they use exception handlers. The 68000 has a table of exception handler vectors so that different handlers can be called for each type of exception. That table is in the cart rom at the start.

Since it is in rom, that can't be changed to point to other routines. To get around that, the rom exception vectors often have another table in ram that they jump through so that the programmer can alter the exception vectors on the fly. That is what the table at 0xFFFD00 is: the main exception handler vector table for the main 68000 (the Genesis) is in the CD BIOS (when there is no cart plugged into the Genesis, the CD puts its own rom into the same location for the Genesis to boot from); those entries then make the 68000 jump through the entries at 0xFFFD00.

Now sometimes, an exception handler will call a user subroutine as part of its execution. It calls the routine like a normal subroutine, so the routine doesn't have to save the registers, and exits with the normal rts opcode. That is how the SPInt routine works. The sub CPU (the CD) jumps to its own exception handler, which saves the registers, does its thing, then does a jsr to the SPInt function. Your SPInt function does whatever you tell it to, then does a rts back to the exception handler, which then restores the registers and does rte. It's up to the programmer to know when you should or should not save/restore registers, and when to use rts or rte.

RamiroR
Interested
Posts: 18
Joined: Tue Jun 02, 2009 10:45 pm

Post by RamiroR » Sun Jun 14, 2009 4:42 am

Yay, that's all I needed to know, Vblank handler working (Main), sends INT2 ;)

Post Reply