-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
1 changed file
with
171 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
|
||
/* PCM channel increment */ | ||
.equ PCM_FDL, 0xFF0005 | ||
.equ PCM_FDH, 0xFF0007 | ||
|
||
/* General use timer */ | ||
.equ TIMER, 0x8030 | ||
.equ INT_MASK, 0x8032 | ||
.equ _LEVEL3, 0x5F82 /* TIMER INTERRUPT jump vector */ | ||
|
||
|
||
.text | ||
.align 2 | ||
|
||
|
||
| uint8_t pcm_lcf(uint8_t pan); | ||
| Convert pan setting to simple linear crossfade volume settings | ||
.global pcm_lcf | ||
pcm_lcf: | ||
move.l 4(sp),d0 /* pan */ | ||
addq.b #8,d0 | ||
bcc.b 0f | ||
move.l 4(sp),d0 | ||
0: | ||
andi.w #0x00F0,d0 /* right pan volume nibble */ | ||
|
||
move.l 4(sp),d1 | ||
not.b d1 | ||
addq.b #8,d1 | ||
bcc.b 1f | ||
move.l 4(sp),d1 | ||
not.b d1 | ||
1: | ||
lsr.b #4,d1 /* left pan volume nibble */ | ||
or.b d1,d0 | ||
rts | ||
|
||
|
||
| void pcm_delay(void); | ||
| Delay after writing PCM register | ||
.global pcm_delay | ||
pcm_delay: | ||
moveq #20,d1 | ||
0: | ||
dbra d1,0b | ||
rts | ||
|
||
|
||
| void pcm_set_period(uint32_t period); | ||
.global pcm_set_period | ||
pcm_set_period: | ||
move.l 4(sp),d1 | ||
cmpi.l #4,d1 | ||
blo.b 0f /* saturate increment to 65535 */ | ||
addq.l #1,d1 | ||
move.l #446304,d0 | ||
divu.w d1,d0 | ||
lsr.w #1,d0 /* incr = (446304 / Period + 1) >> 1 */ | ||
bra.b 1f | ||
0: | ||
move.w #65535,d0 | ||
1: | ||
move.b d0,PCM_FDL.l | ||
bsr.b pcm_delay | ||
lsr.w #8,d0 | ||
move.b d0,PCM_FDH.l | ||
bra.b pcm_delay | ||
|
||
|
||
| void pcm_set_freq(uint32_t freq); | ||
.global pcm_set_freq | ||
pcm_set_freq: | ||
move.l 4(sp),d0 | ||
cmpi.l #1041648,d0 | ||
bhs.b 0f /* saturate increment to 65535 */ | ||
lsl.l #8,d0 | ||
lsl.l #3,d0 /* shift freq for fixed point result */ | ||
move.w #32552,d1 | ||
divu.w d1,d0 /* incr = (freq << 11) / 32552 */ | ||
bra.b 1f | ||
0: | ||
move.w #65535,d0 | ||
1: | ||
move.b d0,PCM_FDL.l | ||
bsr.b pcm_delay | ||
lsr.w #8,d0 | ||
move.b d0,PCM_FDH.l | ||
bra.b pcm_delay | ||
|
||
|
||
| 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 | ||
add.w d1,d1 | ||
beq.b 0f /* safety check... passing 0 will just exit */ | ||
divu.w d1,d0 | ||
subq.w #1,d0 | ||
ble.b 0f /* safety check */ | ||
move.w d0,TIMER.w | ||
0: | ||
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 | ||
|
||
|
||
.data | ||
|
||
|
||
.align 4 | ||
|
||
int3_callback: | ||
.long 0 | ||
|
||
int3_cntr: | ||
.word 0 | ||
|