247 lines
3.9 KiB
ArmAsm
247 lines
3.9 KiB
ArmAsm
.EQU AUDIO_BASE $A00
|
|
.EQU IRQC_REG $980
|
|
.EQU IRQC_EN $80
|
|
|
|
; args: sample rate
|
|
START_PCMAUDIO:
|
|
; calculate clock divider
|
|
LOADCP 77000000
|
|
SWAP
|
|
LOADCP _DIV
|
|
CALL
|
|
|
|
LOADC AUDIO_BASE + 1
|
|
SWAP ; put clock divider on ToS
|
|
; LOADCP 4812 ; clock divider for 16KHz sample rate
|
|
; LOADCP 2406 ; clock divider for 32KHz sample rate
|
|
STOREI 1
|
|
LOADCP 32768 ; set amplitude to biased 0
|
|
STOREI
|
|
DROP
|
|
LOADC AUDIO_BASE
|
|
LOADC 17 ; enable channel, enable interrupt
|
|
STOREI
|
|
DROP
|
|
RET
|
|
|
|
STOP_AUDIO:
|
|
LOADC AUDIO_BASE
|
|
LOADC 0
|
|
STOREI
|
|
DROP
|
|
RET
|
|
|
|
; args: pointer to pascal string, sample rate
|
|
.EQU PS_PTR 0
|
|
.EQU PS_COUNT 4
|
|
.EQU PS_FS 12
|
|
PLAYSAMPLE:
|
|
FPADJ -PS_FS
|
|
|
|
LOADCP START_PCMAUDIO
|
|
CALL
|
|
|
|
DUP
|
|
LOADI ; get string size from header
|
|
SHR ; divide by 4 to get word count
|
|
SHR
|
|
|
|
STORE PS_COUNT
|
|
INC 8 ; skip rest of header
|
|
STORE PS_PTR ; store sample data pointer
|
|
|
|
PS_L0:
|
|
LOAD PS_PTR ; load pointer
|
|
INC.S1.X2Y 4 ; increment and keep old value
|
|
STORE PS_PTR ; store incremented value
|
|
|
|
LOADI ; load 32 bit word
|
|
DUP
|
|
BROT ; get upper 16 bit word
|
|
BROT
|
|
LOADCP $FFFF
|
|
AND
|
|
|
|
LOADCP PLAY_1SAMPLE
|
|
CALL
|
|
|
|
LOADCP $FFFF ; get lower 16 bit word
|
|
AND
|
|
LOADCP PLAY_1SAMPLE
|
|
CALL
|
|
|
|
LOAD PS_COUNT ; load word count
|
|
DEC 1 ; decrement
|
|
DUP
|
|
STORE PS_COUNT
|
|
CBRANCH.NZ PS_L0 ; loop if not zero
|
|
|
|
LOADCP STOP_AUDIO
|
|
CALL
|
|
|
|
FPADJ PS_FS
|
|
RET
|
|
|
|
; play one sample, waiting
|
|
; for the clock divider, which
|
|
; is visible via the phase flag
|
|
; args: 16-bit unsigned sample
|
|
PLAY_1SAMPLE:
|
|
|
|
PLAY1_L0:
|
|
LOADC AUDIO_BASE
|
|
LOADI
|
|
LOADC 8 ; get fifo_full flag
|
|
AND
|
|
CBRANCH.NZ PLAY1_L0 ; loop if fifo is full
|
|
|
|
LOADC AUDIO_BASE+2 ; store amplitude value
|
|
SWAP
|
|
STOREI
|
|
DROP
|
|
RET
|
|
|
|
; start interrupt-driven sample playback
|
|
; args: pointer to pascal string, sample rate
|
|
SAMPLEQSTART:
|
|
LOADCP START_PCMAUDIO
|
|
CALL
|
|
|
|
LOADCP SMPLQ_COUNT
|
|
OVER
|
|
LOADI ; get string size from header
|
|
SHR ; divide by 4 to get word count
|
|
SHR
|
|
|
|
STOREI
|
|
DROP
|
|
|
|
LOADCP SMPLQ_PTR
|
|
SWAP
|
|
INC 8 ; skip rest of header
|
|
STOREI ; store sample data pointer
|
|
DROP
|
|
|
|
LOADCP SMPLQ_ISR ; set interrupt handler
|
|
STOREREG IV
|
|
|
|
LOADC IRQC_REG ; enable irq
|
|
LOADC IRQC_EN
|
|
STOREI
|
|
DROP
|
|
|
|
RET
|
|
|
|
SAMPLEQSTOP:
|
|
LOADCP SMPLQ_PTR
|
|
LOADC 0
|
|
STOREI
|
|
DROP
|
|
|
|
LOADCP STOP_AUDIO
|
|
CALL
|
|
|
|
LOADC IRQC_REG ; disable irq
|
|
LOADC 0
|
|
STOREI
|
|
DROP
|
|
RET
|
|
|
|
SAMPLEQSIZE:
|
|
LOADCP SMPLQ_COUNT
|
|
LOADI
|
|
RET
|
|
|
|
SMPLQ_PTR: .WORD 0
|
|
SMPLQ_COUNT: .WORD 0
|
|
|
|
SMPLQ_ISR:
|
|
LOADC IRQC_REG
|
|
LOADI
|
|
LOADC 4 ; check for audio interrupt
|
|
AND
|
|
CBRANCH.Z SMPLQ_I_XT ; if flag not set, exit
|
|
|
|
SMPLQ_I_L:
|
|
LOADCP SMPLQ_PTR
|
|
LOADI ; load word pointer
|
|
DUP
|
|
CBRANCH.NZ SMPLQ_I_B ; check for null pointer
|
|
DROP
|
|
BRANCH SMPLQ_I_XT ; if null, end interrupt routine
|
|
SMPLQ_I_B:
|
|
LOADI ; load next word
|
|
DUP
|
|
|
|
BROT ; get high half-word
|
|
BROT
|
|
LOADCP $FFFF
|
|
AND
|
|
|
|
LOADC AUDIO_BASE+2
|
|
SWAP
|
|
STOREI ; write sample, keep addr
|
|
|
|
SWAP ; addr to NoS, lower halfword on ToS
|
|
LOADCP $FFFF
|
|
AND
|
|
STOREI ; write sample
|
|
DROP
|
|
|
|
; decrement word count
|
|
LOADCP SMPLQ_COUNT
|
|
LOADI.S1.X2Y ; load counter, keep addr
|
|
DEC 1
|
|
DUP
|
|
CBRANCH.Z SMPLQ_I_END ; end if zero
|
|
|
|
STOREI ; store new counter value
|
|
DROP
|
|
|
|
; increment pointer
|
|
LOADCP SMPLQ_PTR
|
|
LOADI.S1.X2Y
|
|
INC 4
|
|
STOREI
|
|
DROP
|
|
|
|
; check if fifo is full
|
|
LOADC AUDIO_BASE
|
|
LOADI
|
|
LOADC 8 ; fifo_full
|
|
AND
|
|
CBRANCH.Z SMPLQ_I_L ; next sample if not full
|
|
|
|
LOADC AUDIO_BASE
|
|
LOADC 17 ; re-enable channel interrupt
|
|
STOREI
|
|
DROP
|
|
|
|
BRANCH SMPLQ_I_XT
|
|
|
|
; end playback, set ptr and counter to zero
|
|
SMPLQ_I_END:
|
|
DROP
|
|
DROP
|
|
LOADCP SMPLQ_PTR
|
|
LOADC 0
|
|
STOREI
|
|
DROP
|
|
LOADCP SMPLQ_COUNT
|
|
LOADC 0
|
|
STOREI
|
|
DROP
|
|
|
|
; set amplitude out to zero (biased)
|
|
LOADC AUDIO_BASE+2
|
|
LOADCP 32768
|
|
STOREI
|
|
DROP
|
|
|
|
SMPLQ_I_XT:
|
|
LOADC IRQC_REG ; re-enable interrupts
|
|
LOADC IRQC_EN
|
|
STOREI
|
|
DROP
|
|
LOADREG IR ; jump via interrupt return register
|
|
JUMP
|