Skip to content

Commit

Permalink
Added missing pcm-io.s file
Browse files Browse the repository at this point in the history
Added missing pcm-io.s file
  • Loading branch information
matteusbeus authored Jul 26, 2023
1 parent c9fe0a2 commit 621f5a0
Showing 1 changed file with 171 additions and 0 deletions.
171 changes: 171 additions & 0 deletions pcm-io.s
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

0 comments on commit 621f5a0

Please sign in to comment.