68k Interrupts

Ask anything your want about the 32X Mushroom programming.

Moderator: BigEvilCorporation

Post Reply
ob1
Very interested
Posts: 463
Joined: Wed Dec 06, 2006 9:01 am
Location: Aix-en-Provence, France

68k Interrupts

Post by ob1 » Fri Feb 13, 2009 10:43 am

Hi you all.
I wan't to ask you how the 68k handled the Interrupt Process with the 32X, but I think I've found by myself. Thus, here's how I understand it.

A custom ROM in the 32X (you know, the 32X_G_BIOS.BIN) masks the 0h-100h from the cartrdige ROM. This custom ROM reads :

Code: Select all

00h	0088 0200h
04h	0088 0206h
08h	0088 020Ch
...
78h	0088 02D0h
...
The cartridge ROM reads :

Code: Select all

...
0200h	$4E73,0,0		; RTE
0206h	$4E73,0,0		; RTE
020Ch	$4E73,0,0		; RTE
...
02D0h	$4EF9,$0088,$1000	; V_INT code that means JMP $881000
...
1000h	RTE			; V_INT code. Dummy instruction
When an Interrupt (for example, Level 6, V_INT) occurs,
the Status Register is saved,
the 68k enters Privilege Mode,
the 68k fetches the Exception Vector Number (
well well well, I got a Level 6 Interrupt, so I know that the related Exception Number is at 78h
),
the PC and SR are savec on the Supervisor Stack,
the Exception Vector Number is fetched and loaded into the PC (
OK so, what do we have from 78h ? Damn', it is located on the custom ROM. And reading 78h, I can see ... 88 02D0h ! 88 02D0h ? Oh right, that's because I have the 32X settled. OK, I'll branch to 88 0000 + 02D0h then. OK. Here we go !
)
and ... here we go ! The 68k executes the code :

Code: Select all

02D0h	JMP	$881000
...
1000h	RTE
in our case a dummy RTE, but anyway ...)

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

Post by Chilly Willy » Fri Feb 13, 2009 9:10 pm

Yes, with the 32X, there's at least one level of indirection (often two), which adds a few more cycles to the response of INTs. So don't forget those extra cycles due to the jumps.

ob1
Very interested
Posts: 463
Joined: Wed Dec 06, 2006 9:01 am
Location: Aix-en-Provence, France

Post by ob1 » Mon Feb 16, 2009 4:03 pm

OK, so, I think I've got a problem.
Here's my code :

Code: Select all

	dc.l	$01000000		; Initial SSP
	dc.l	$3F0			; Initial PC
	dc.l	$880200			; Bus error (2)
	dc.l	$880206			; Address error (3)
	dc.l	$88020C			; Illegal Instruction (4)
	dc.l	$880212			; Divide by 0 (5)
	dc.l	$880218			; CHK Instruction (6)
	dc.l	$88021E			; TRAPV Instruction (7)
	dc.l	$880224			; Privilege Violation (8)
	dc.l	$88022A			; Trace (9)
	dc.l	$880230			; Line 1010 Emulator (10)
	dc.l	$880236			; Line 1111 Emulator (11)
	ds.l	12			; Unassigned, Reserved (12-23)
	dc.l	$88023C			; Spurious Interrupt (24)
	dc.l	$880242			; Level 1 Interrupt Autovector (25)
	dc.l	$880248			; Level 2 Interrupt Autovector (26)
	dc.l	$88024E			; Level 3 Interrupt Autovector (27)
	dc.l	$880254			; Level 4 Interrupt Autovector (28)
	dc.l	$88025A			; Level 5 Interrupt Autovector (29)
	dc.l	$880260			; Level 6 Interrupt Autovector (30)
	dc.l	$880266			; Level 7 Interrupt Autovector (31)
	dc.l	$88026C			; TRAP #0 Instruction Vector (32)
	dc.l	$880272
	dc.l	$880278
	dc.l	$88027E
	dc.l	$880284
	dc.l	$88028A
	dc.l	$880290
	dc.l	$880296
	dc.l	$88029C
	dc.l	$8802A2
	dc.l	$8802A8
	dc.l	$8802AE
	dc.l	$8802B4
	dc.l	$8802BA
	dc.l	$8802C0
	dc.l	$8802C6			; TRAP #15 Instruction Vector (47)
	ds.l	16			; Unassigned, Reserved (48-63)


* Header
	dc.b	'SEGA GENESIS    '	; Console Name (16)
	dc.b	'(C)SEGA 2009.FEB'	; Copyright Information (16)
	dc.b	'SUPER VDP       '	; Domestic Name (48)
	dc.b	'                '
	dc.b	'                '
	dc.b	'SUPER VDP       '	; Overseas Name (48)
	dc.b	'                '
	dc.b	'                '
	dc.b	'GM MK-0000 -00'	; Serial Number (14)
	dc.w	0			; Checksum (2) - Leave it at #0 when using 32x
	dc.b	'J6              '	; I/O Support (16)
	dc.l	$00000000,ROM_SIZE	; ROM area (2x4)
	dc.l	$00FF0000,$00FFFFFF	; RAM area (2x4)
	dc.b	'                '	; Modem Support (24)
	dc.b	'                '	; Memo (40)
	dc.b	'                '
	dc.b	'                '
	dc.b	'JUE             '	; Country Support (16)

* Exception Jump Table
	jmp	$880000+INT		; Bus error
	jmp	$880000+INT		; Address Error
	jmp	$880000+INT		; Illegal Instruction
	jmp	$880000+INT		; Divide by 0
	jmp	$880000+INT		; CHK Instruction
	jmp	$880000+INT		; TRAPV Instruction
	jmp	$880000+INT		; Privilege Violation
	jmp	$880000+INT		; Trace
	jmp	$880000+INT		; Line 1010 Emulator
	jmp	$880000+INT		; Line 1111 Emulator
	jmp	$880000+INT		; Spurious Interrupt
	jmp	$880000+INT		; Level 1 Interrupt
	jmp	$880000+INT		; Level 2 Interrupt
	jmp	$880000+INT		; Level 3 Interrupt
	jmp	$880000+H_INT		; HBL
	jmp	$880000+INT		; Level 5 Interrupt
	jmp	$880000+V_INT		; VBL
	jmp	$880000+INT		; Level 7 Interrupt
	jmp	$880000+INT		; Trap 0
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT
	jmp	$880000+INT		; Trap 15
...

Code: Select all

	move	#$2500,SR	; Enable V_INT

main:
	trap	#2

	move.w	vTimer,d0
vSync:
	cmp	vTimer,d0
	beq	vSync

	bra	main


INT:
	addq	#1,d5
	rte

H_INT:
	addq	#1,d6
	rte

V_INT:
	addq	#1,d7
	rte
And ... guess what.
d5 is incremented, triggered by the TRAP #2, but d6 and d7 will NOT move. So, I guess that V_INT and H_INT are not triggered to the 68k !?! BTW, they are triggered to SH2, since in my case, vTimer is plugged on CommPort, and Master write its own vTimer there.
So ... what's the problem ?

Snake
Very interested
Posts: 206
Joined: Sat Sep 13, 2008 1:01 am

Post by Snake » Mon Feb 16, 2009 9:04 pm

This stuff definitely works. Maybe you didn't enable V-INTS on the VDP? It's unclear if what you posted is all of your code.

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

Post by Chilly Willy » Mon Feb 16, 2009 10:25 pm

What Snake said. The vblank works fine in my 32X code. Here's the snippets:

Code: Select all

| At this point (0x800), the Work RAM is clear, the VDP initialized, the
| VRAM/VSRAM/CRAM cleared, the Z80 initialized, the 32X initialized,
| both 32X framebuffers cleared, the 32X palette cleared, the SH2s
| checked for a startup error, the adapter TV mode matches the MD TV
| mode, and the ROM checksum checked. If any error is detected, the
| carry is set, otherwise it is cleared. The 68000 main code is now
| entered.

        jmp     __start+0x00880000+0x3F0

| 68000 General exception handler at 0x806

        jmp     __except+0x00880000+0x3F0

| 68000 Level 4 interrupt handler at 0x80C - HBlank IRQ

        jmp     __hblank+0x00880000+0x3F0

| 68000 Level 6 interrupt handler at 0x812 - VBlank IRQ

        jmp     __vblank+0x00880000+0x3F0

__except:
        move.l  d0,-(sp)
        move.l  4(sp),d0    /* jump table return address */
        sub.w   #0x206,d0   /* 0 = BusError, 6 = AddrError, etc */

| handle exception

        move.l  (sp)+,d0
        addq.l  #4,sp       /* pop jump table return address */
        rte

__hblank:
        rte

__vblank:
        move.l  d0,-(sp)
        move.l  0xF00FFC,d0
        beq.b   1f
        move.l  a0,-(sp)
        movea.l d0,a0
        jmp     (a0)
1:
        move.l  (sp)+,d0
        rte


__start:
        cmp.l   #0x4D5F4F4B,0xA15120    /* M_OK */
        bne.b   __start                 /* wait for master ok */

| init MD VDP
        lea     0xC00004,a0
        move.w  #0x8004,(a0) /* reg. 0 - Disable HBL INT */
        move.w  #0x8174,(a0) /* reg. 1 - Enable display, VBL INT, DMA + 28 VCell size */
        move.w  #0x8230,(a0) /* reg. 2 - Plane A =$30*$400=$C000 */
        move.w  #0x832C,(a0) /* reg. 3 - Window  =$2C*$400=$B000 */
        move.w  #0x8407,(a0) /* reg. 4 - Plane B =$7*$2000=$E000 */
        move.w  #0x855E,(a0) /* reg. 5 - sprite table begins at $BC00=$5E*$200 */
        move.w  #0x8600,(a0) /* reg. 6 - not used */
        move.w  #0x8700,(a0) /* reg. 7 - Background Color number*/
        move.w  #0x8800,(a0) /* reg. 8 - not used */
        move.w  #0x8900,(a0) /* reg. 9 - not used */
        move.w  #0x8A01,(a0) /* reg 10 - HInterrupt timing */
        move.w  #0x8B00,(a0) /* reg 11 - $0000abcd a=extr.int b=vscr cd=hscr */
        move.w  #0x8C81,(a0) /* reg 12 - hcell mode + shadow/highight + interlaced mode (40 cell, no shadow, no interlace)*/
        move.w  #0x8D2E,(a0) /* reg 13 - HScroll Table = $B800 */
        move.w  #0x8E00,(a0) /* reg 14 - not used */
        move.w  #0x8F02,(a0) /* reg 15 - auto increment data */
        move.w  #0x9011,(a0) /* reg 16 - scrl screen v&h size (64x64) */
        move.w  #0x9100,(a0) /* reg 17 - window hpos */
        move.w  #0x92FF,(a0) /* reg 18 - window vpos */


| init joyports
        move.b  #0x40,0xA10009
        move.b  #0x40,0xA1000B
        move.b  #0x40,0xA1000D
| check for pad 1
        lea     0xA10003,a0
        bsr     get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        move.w  d0,d1
        bsr     get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        bsr     get_input       /* - 1 c b r l d u - 0 s a 0 0 0 0 */
        bsr     get_input       /* - 1 c b m x y z - 0 s a 1 1 1 1 */
        andi.w  #0x000C,d1
        lsr.w   #2,d1
        andi.w  #0x000C,d0
        or.w    d1,d0
        ror.w   #4,d0
| At this point, the high four bits hold the pad type we use to ID the controller
| 0000 if 3 btn pad
| 1100 if 6 btn pad
| 1111 if nothing (or multi-tap)
        move.w  d0,0xA15128     /* controller 1 type */
| check for pad 2
        lea     0xA10005,a0
        bsr     get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        move.w  d0,d1
        bsr     get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        bsr     get_input       /* - 1 c b r l d u - 0 s a 0 0 0 0 */
        bsr     get_input       /* - 1 c b m x y z - 0 s a 1 1 1 1 */
        andi.w  #0x000C,d1
        lsr.w   #2,d1
        andi.w  #0x000C,d0
        or.w    d1,d0
        ror.w   #4,d0
        move.w  d0,0xA1512A     /* controller 2 type */

| Copy 68000 main loop to Work RAM to keep contention for the ROM with
| SH2s to a minimum.
        lea     __m68k_start(pc),a0
        lea     0x00F01000,a1
        move.w  #__m68k_end-__m68k_start-1,d0
cpyloop:
        move.b  (a0)+,(a1)+
        dbra    d0,cpyloop

        move.l  #0,0xA1512C     /* clear the vblank count */

        move.w  0xA15100,d0
        or.w    #0x8000,d0
        move.w  d0,0xA15100     /* allow SH2 access to MARS hw */
        move.l  #0,0xA15120     /* let Master SH2 run */

| jump to main loop in Work RAM
        jmp     0xF01000.l

| this block of code must be pc relative as it's copied into Work RAM

__m68k_start:
        lea     vert_blank(pc),a0
        move.l  a0,0xF00FFC     /* set vertical blank interrupt handler */
        move.w  #0x2000,sr      /* enable interrupts */
main_loop:
        move.l  0xA15120,d0     /* get COMM0 */
        beq.b   main_loop
        /* process request from Master SH2 */

        move.l  #0,0xA15120     /* done */
        bra     main_loop

vert_blank:
        move.l  d1,-(sp)
        /* read controllers */
        lea     0xA10003,a0
        move.w  0xA15128,d0
        andi.w  #0xF000,d0       /* type */
        beq.b   rd_3btn_1
        cmpi.w  #0xC000,d0
        beq.b   rd_6btn_1
        bra.b   no_pad_1
rd_3btn_1:
        bsr.w   get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        move.w  d0,d1
        moveq   #0,d0
        bra.b   common_1
rd_6btn_1:
        bsr.w   get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        move.w  d0,d1
        bsr.w   get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        bsr.w   get_input       /* - 1 c b r l d u - 0 s a 0 0 0 0 */
        bsr.w   get_input       /* - 1 c b m x y z - 0 s a 1 1 1 1 */
        andi.w  #0x0F00,d0      /* 0 0 0 0 m x y z 0 0 0 0 0 0 0 0 */
        ori.w   #0xC000,d0      /* 1 1 0 0 m x y z 0 0 0 0 0 0 0 0 */
        eori.w  #0x0F00,d0      /* 1 1 0 0 M X Y Z 0 0 0 0 0 0 0 0 */
common_1:
        andi.w  #0x3F30,d1      /* 0 0 c b r l d u 0 0 s a 0 0 0 0 */
        lsl.b   #2,d1           /* 0 0 c b r l d u s a 0 0 0 0 0 0 */
        move.w  d1,d2
        lsr.w   #8,d1           /* 0 0 0 0 0 0 0 0 0 0 c b r l d u */
        or.b    d2,d1           /* 0 0 0 0 0 0 0 0 s a c b r l d u */
        eori.b  #0xFF,d1        /* 0 0 0 0 0 0 0 0 S A C B R L D U */
        move.b  d1,d0
        move.w  d0,0xA15128     /* controller 1 current value */
no_pad_1:
        lea     0xA10005,a0
        move.w  0xA1512A,d0
        andi.w  #0xF000,d0       /* type */
        beq.b   rd_3btn_2
        cmpi.w  #0xC000,d0
        beq.b   rd_6btn_2
        bra.b   no_pad_2
rd_3btn_2:
        bsr.b   get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        move.w  d0,d1
        moveq   #0,d0
        bra.b   common_2
rd_6btn_2:
        bsr.b   get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        move.w  d0,d1
        bsr.b   get_input       /* - 1 c b r l d u - 0 s a 0 0 d u */
        bsr.b   get_input       /* - 1 c b r l d u - 0 s a 0 0 0 0 */
        bsr.b   get_input       /* - 1 c b m x y z - 0 s a 1 1 1 1 */
        andi.w  #0x0F00,d0      /* 0 0 0 0 m x y z 0 0 0 0 0 0 0 0 */
        ori.w   #0xC000,d0      /* 1 1 0 0 m x y z 0 0 0 0 0 0 0 0 */
        eori.w  #0x0F00,d0      /* 1 1 0 0 M X Y Z 0 0 0 0 0 0 0 0 */
common_2:
        andi.w  #0x3F30,d1      /* 0 0 c b r l d u 0 0 s a 0 0 0 0 */
        lsl.b   #2,d1           /* 0 0 c b r l d u s a 0 0 0 0 0 0 */
        move.w  d1,d2
        lsr.w   #8,d1           /* 0 0 0 0 0 0 0 0 0 0 c b r l d u */
        or.b    d2,d1           /* 0 0 0 0 0 0 0 0 s a c b r l d u */
        eori.b  #0xFF,d1        /* 0 0 0 0 0 0 0 0 S A C B R L D U */
        move.b  d1,d0
        move.w  d0,0xA1512A     /* controller 2 current value */
no_pad_2:

        move.l  0xA1512C,d0
        addq.l  #1,d0
        move.l  d0,0xA1512C     /* increment the vblank count */

        move.l  (sp)+,d1
        movea.l (sp)+,a0
        move.l  (sp)+,d0
        rte

| read single phase from controller
get_input:
        move.b  #0x40,(a0)
        nop
        nop
        nop
        move.b  (a0),d0
        move.b  #0x00,(a0)
        lsl.w   #8,d0
        nop
        move.b  (a0),d0
        move.b  #0x40,(a0)
        rts

__m68k_end:

With that, the vblank does happen, the counter is advanced and the pads read (although nobody but gens likes the 6-button controller code yet).

ob1
Very interested
Posts: 463
Joined: Wed Dec 06, 2006 9:01 am
Location: Aix-en-Provence, France

Post by ob1 » Tue Feb 17, 2009 8:12 am

Snake wrote:Maybe you didn't enable V-INTS on the VDP?
:oops:

... thank you ?

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

Post by Chilly Willy » Tue Feb 17, 2009 8:25 am

ob1 wrote:
Snake wrote:Maybe you didn't enable V-INTS on the VDP?
:oops:

... thank you ?
It's always the EASY things that get you. :lol:

ob1
Very interested
Posts: 463
Joined: Wed Dec 06, 2006 9:01 am
Location: Aix-en-Provence, France

Post by ob1 » Tue Feb 17, 2009 8:51 am

Chilly Willy wrote:It's always the EASY things that get you. :lol:
;D

Post Reply