Hello everyone.
I have been trying to implement a disassembled PCM code in my game.
The dissassemble seems to be fine (I already tested a recompiled version of the same file in the game where I took it), but, the interrupts doesn't seem to work fine on mine game.
According to certain parts of the manual and the way it's done in the game I took the code from, it uses the interrupt Level3 (which has timing) to run the code. And the code is done like this:
http://pastebin.com/KpKQUu8A
However, it only makes the Sub-CPU to be stuck at $5EE (part of BIOS/CD-SYSTEM section), doing a btst #0,($5EA4).w (_Usermode-2). With Gens's debugging tool, I see that magically a random $01 number appears there, so that's what what makes it stick there.
Any ideas of what is going on?
Thanks
Usercalls and _LEVEL3
Moderator: Mask of Destiny
Usercalls and _LEVEL3
skype: hcktrox
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 pm
For a level 3 int to fire, you have to set the int mask to $2200, not $2300. That's masking the int.
Here's how I set the int and use it in my libpcm...
Note that I don't bother saving or restoring the int since the system doesn't use it, and my program is the only thing running... the SegaCD doesn't multi-task, after all. ![Laughing :lol:](./images/smilies/icon_lol.gif)
Note that int3_callback is a pointer to a plain C function, like this:
Here's how I set the int and use it in my libpcm...
Code: Select all
/* General use timer */
.equ TIMER, 0x8030
.equ INT_MASK, 0x8032
.equ _LEVEL3, 0x5F82 /* TIMER INTERRUPT jump vector */
...
| void pcm_set_timer(uint16_t bpm);
| TIMER = 32552 / (bpm * 2) - 1
| should be 32552 * 5 / (bpm * 2) - 1, but that's too big for TIMER, so
| we leave out the * 5 and compensate in the int handler
.global pcm_set_timer
pcm_set_timer:
move.l #32552,d0
move.l 4(sp),d1
cmpi.l #64,d1
bhs.b 0f
moveq #64,d1 /* lowest tempo TIMER can handle */
0:
add.w d1,d1
divu.w d1,d0
subq.w #1,d0
ble.b 1f /* safety check */
move.w d0,TIMER.w
1:
rts
| void pcm_stop_timer(void);
.global pcm_stop_timer
pcm_stop_timer:
move #0x2700,sr /* disable interrupts */
move.w #0,TIMER.w /* stop General Timer */
move.w INT_MASK.w,d0
andi.w #0xFFF7,d0
move.w d0,INT_MASK.w /* disable General Timer interrupt */
move #0x2000,sr /* enable interrupts */
rts
| void pcm_start_timer(void (*callback)(void));
.global pcm_start_timer
pcm_start_timer:
move #0x2700,sr /* disable interrupts */
move.l 4(sp),int3_callback /* set callback vector */
move.w #0,int3_cntr /* clear int counter */
move.w #0x4EF9,_LEVEL3.w
move.l #timer_int,_LEVEL3+2.w /* set level 3 int vector for timer */
move.w #129,TIMER.w /* 125 BPM */
move.w INT_MASK.w,d0
ori.w #0x0008,d0
move.w d0,INT_MASK.w /* enable General Timer interrupt */
move #0x2000,sr /* enable interrupts */
rts
timer_int:
move.l d0,-(sp)
move.w int3_cntr,d0
addq.w #1,d0
cmpi.w #5,d0
blo.b 0f /* once every 5 ints for actual beats per minute rate */
movem.l d1/a0-a1,-(sp)
movea.l int3_callback,a1
jsr (a1)
movem.l (sp)+,d1/a0-a1
moveq #0,d0
0:
move.w d0,int3_cntr
move.l (sp)+,d0
rte
![Laughing :lol:](./images/smilies/icon_lol.gif)
Note that int3_callback is a pointer to a plain C function, like this:
Code: Select all
pcm_start_timer(&callback);
...
static void callback(void)
{
...
}