mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
7a03b1fe16
Most of these correspond to changes made in devkitPro/libogc@b1b8ecab3a.
The numeric vlaues of ACC0 and ACC1 in Dolphin are different (see b06d38389b
, though I'm not sure when this difference first appeared). Technically it's not even necessary to list the registers at the start like this anymore, but old programs do it, so it seems useful to have a test that covers it.
The binary itself does not need to be changed; the warnings were simply stating that "although you wrote $ACL0, the generated binary instead is using $ACC0" or similar; by changing the code to use $ACC0 directly the warnings are resolved.
1087 lines
22 KiB
C++
1087 lines
22 KiB
C++
/* DSP_MIXER -> PCM VOICE SOFTWARE PROCESSOR (8-16 Bits Mono/Stereo Voices)
|
|
|
|
// Thanks to Duddie for you hard work and documentation
|
|
|
|
Copyright (c) 2008 Hermes <www.entuwii.net>
|
|
All rights reserved.
|
|
|
|
SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*/
|
|
|
|
#include "HermesText.h"
|
|
|
|
const char s_hermes_text[21370] = R"(
|
|
/********************************/
|
|
/** REGISTER NAMES **/
|
|
/********************************/
|
|
|
|
AR0: equ 0x00 ; address registers
|
|
AR1: equ 0x01
|
|
AR2: equ 0x02
|
|
AR3: equ 0x03 // used as jump function selector
|
|
|
|
IX0: equ 0x04 // LEFT_VOLUME accel
|
|
IX1: equ 0x05 // RIGHT_VOLUME accel
|
|
IX2: equ 0x06 // ADDRH_SMP accel
|
|
IX3: equ 0x07 // ADDRL_SMP accel
|
|
|
|
R08: equ 0x08 // fixed to 48000 value
|
|
R09: equ 0x09 // problems using this
|
|
R0A: equ 0x0a // ADDREH_SMP accel
|
|
R0B: equ 0x0b // ADDREL_SMP accel
|
|
|
|
ST0: equ 0x0c
|
|
ST1: equ 0x0d
|
|
ST2: equ 0x0e
|
|
ST3: equ 0x0f
|
|
|
|
CONFIG: equ 0x12
|
|
SR: equ 0x13
|
|
|
|
PRODL: equ 0x14
|
|
PRODM: equ 0x15
|
|
PRODH: equ 0x16
|
|
PRODM2: equ 0x17
|
|
|
|
AXL0: equ 0x18
|
|
AXL1: equ 0x19
|
|
AXH0: equ 0x1A // SMP_R accel
|
|
AXH1: equ 0x1b // SMP_L accel
|
|
|
|
ACC0: equ 0x20 // accumulator (global)
|
|
ACC1: equ 0x21
|
|
|
|
ACL0: equ 0x1c // Low accumulator
|
|
ACL1: equ 0x1d
|
|
ACM0: equ 0x1e // Mid accumulator
|
|
ACM1: equ 0x1f
|
|
ACH0: equ 0x10 // Sign extended 8 bit register 0
|
|
ACH1: equ 0x11 // Sign extended 8 bit register 1
|
|
|
|
/********************************/
|
|
/** HARDWARE REGISTER ADDRESS **/
|
|
/********************************/
|
|
|
|
DSCR: equ 0xffc9 ; DSP DMA Control Reg
|
|
DSBL: equ 0xffcb ; DSP DMA Block Length
|
|
DSPA: equ 0xffcd ; DSP DMA DMEM Address
|
|
DSMAH: equ 0xffce ; DSP DMA Mem Address H
|
|
DSMAL: equ 0xffcf ; DSP DMA Mem Address L
|
|
|
|
DIRQ: equ 0xfffb ; DSP Irq Request
|
|
DMBH: equ 0xfffc ; DSP Mailbox H
|
|
DMBL: equ 0xfffd ; DSP Mailbox L
|
|
CMBH: equ 0xfffe ; CPU Mailbox H
|
|
CMBL: equ 0xffff ; CPU Mailbox L
|
|
|
|
DMA_TO_DSP: equ 0
|
|
DMA_TO_CPU: equ 1
|
|
|
|
/**************************************************************/
|
|
/* NUM_SAMPLES SLICE */
|
|
/**************************************************************/
|
|
|
|
NUM_SAMPLES: equ 1024 ; 1024 stereo samples 16 bits
|
|
|
|
|
|
/**************************************************************/
|
|
/* SOUND CHANNEL REGS */
|
|
/**************************************************************/
|
|
|
|
MEM_REG2: equ 0x0
|
|
MEM_VECTH: equ MEM_REG2
|
|
MEM_VECTL: equ MEM_REG2+1
|
|
RETURN: equ MEM_REG2+2
|
|
|
|
/**************************************************************/
|
|
/* CHANNEL DATAS */
|
|
/**************************************************************/
|
|
|
|
MEM_REG: equ MEM_REG2+0x10
|
|
|
|
ADDRH_SND: equ MEM_REG // Output buffer
|
|
ADDRL_SND: equ MEM_REG+1
|
|
|
|
DELAYH_SND: equ MEM_REG+2 // Delay samples High word
|
|
DELAYL_SND: equ MEM_REG+3 // Delay samples Low word
|
|
|
|
CHAN_REGS: equ MEM_REG+4 // specific regs for the channel
|
|
|
|
FLAGSH_SMP: equ CHAN_REGS+0 // countain number of bytes for step (1-> Mono 8 bits, 2-> Stereo 8 bits and Mono 16 bits, 4-> Stereo 16 bits)
|
|
FLAGSL_SMP: equ CHAN_REGS+1 // 0->Mono 8 bits, 1->Stereo 8 bits, 2->Mono 16 bits 3 -> Stereo 16 bits
|
|
|
|
ADDRH_SMP: equ CHAN_REGS+2 // start address
|
|
ADDRL_SMP: equ CHAN_REGS+3
|
|
|
|
ADDREH_SMP: equ CHAN_REGS+4 // end address
|
|
ADDREL_SMP: equ CHAN_REGS+5
|
|
|
|
FREQH_SMP: equ CHAN_REGS+6 // Freq in Hz to play
|
|
FREQL_SMP: equ CHAN_REGS+7
|
|
|
|
SMP_L: equ CHAN_REGS+8 // last sample for left (used to joint various buffers)
|
|
SMP_R: equ CHAN_REGS+9 // last sample for right (used to joint various buffers)
|
|
|
|
COUNTERH_SMP: equ CHAN_REGS+10 // pitch counter
|
|
COUNTERL_SMP: equ CHAN_REGS+11
|
|
|
|
LEFT_VOLUME: equ CHAN_REGS+12 // volume (0 to 255)
|
|
RIGHT_VOLUME: equ CHAN_REGS+13
|
|
|
|
ADDR2H_SMP: equ CHAN_REGS+14 // start address of buffer two (to joint)
|
|
ADDR2L_SMP: equ CHAN_REGS+15
|
|
|
|
ADDR2EH_SMP: equ CHAN_REGS+16 // end address of buffer two (to joint)
|
|
ADDR2EL_SMP: equ CHAN_REGS+17
|
|
|
|
LEFT_VOLUME2: equ CHAN_REGS+18 // volume (0 to 255) for buffer two
|
|
RIGHT_VOLUME2: equ CHAN_REGS+19
|
|
|
|
BACKUPH_SMP: equ CHAN_REGS+20 // start address backup
|
|
BACKUPL_SMP: equ CHAN_REGS+21
|
|
|
|
/**************************************************************/
|
|
/* VOICE SAMPLE BUFFER DATAS */
|
|
/**************************************************************/
|
|
|
|
MEM_SAMP: equ CHAN_REGS+0x20
|
|
|
|
|
|
data_end: equ MEM_SAMP+0x20
|
|
|
|
/**************************************************************/
|
|
/* SND OUTPUT DATAS */
|
|
/**************************************************************/
|
|
|
|
MEM_SND: equ data_end ; it need 2048 words (4096 bytes)
|
|
|
|
|
|
|
|
/*** START CODE ***/
|
|
|
|
/**************************************************************/
|
|
/* EXCEPTION TABLE */
|
|
/**************************************************************/
|
|
|
|
jmp exception0
|
|
jmp exception1
|
|
jmp exception2
|
|
jmp exception3
|
|
jmp exception4
|
|
jmp exception5
|
|
jmp exception6
|
|
jmp exception7
|
|
|
|
lri $CONFIG, #0xff
|
|
lri $SR,#0
|
|
s16
|
|
clr15
|
|
m0
|
|
|
|
/**************************************************************/
|
|
/* main */
|
|
/**************************************************************/
|
|
|
|
main:
|
|
|
|
// send init token to CPU
|
|
|
|
si @DMBH, #0xdcd1
|
|
si @DMBL, #0x0000
|
|
si @DIRQ, #1
|
|
|
|
recv_cmd:
|
|
// check if previous mail is received from the CPU
|
|
|
|
call wait_for_dsp_mail
|
|
|
|
// wait a mail from CPU
|
|
|
|
call wait_for_cpu_mail
|
|
|
|
si @DMBH, #0xdcd1
|
|
|
|
clr $ACC0
|
|
lri $ACM0,#0xcdd1
|
|
cmp
|
|
jz sys_command
|
|
|
|
clr $ACC1
|
|
lrs $ACM1, @CMBL
|
|
|
|
cmpi $ACM1, #0x111 // fill the internal sample buffer and process the voice internally
|
|
jz input_samples
|
|
|
|
cmpi $ACM1, #0x112 // get samples from the external buffer to the internal buffer and process the voice mixing the samples internally
|
|
jz input_samples2
|
|
|
|
cmpi $ACM1, #0x123 // get the address of the voice datas buffer (CHANNEL DATAS)
|
|
jz get_data_addr
|
|
|
|
cmpi $ACM1, #0x222 // process the voice mixing the samples internally
|
|
jz input_next_samples
|
|
|
|
cmpi $ACM1, #0x666 // send the samples for the internal buffer to the external buffer
|
|
jz send_samples
|
|
|
|
cmpi $ACM1, #0x777 // special: to dump the IROM Datas (remember disable others functions from the interrupt vector to use)
|
|
jz rom_dump_word // (CMBH+0x8000) countain the address of IROM
|
|
|
|
cmpi $ACM1, #0x888 // Used for test
|
|
jz polla_loca
|
|
|
|
cmpi $ACM1, #0x999
|
|
jz task_terminate
|
|
|
|
si @DMBL, #0x0004 // return 0 as ignore command
|
|
si @DIRQ, #0x1 // set the interrupt
|
|
jmp recv_cmd
|
|
|
|
task_terminate:
|
|
si @DMBL, #0x0003
|
|
si @DIRQ, #0x1
|
|
jmp recv_cmd
|
|
|
|
sys_command:
|
|
clr $ACC1
|
|
lrs $ACM1, @CMBL
|
|
|
|
cmpi $ACM1,#0x0001
|
|
jz run_nexttask
|
|
|
|
cmpi $ACM1,#0x0002
|
|
jz 0x8000
|
|
|
|
jmp recv_cmd
|
|
|
|
run_nexttask:
|
|
s16
|
|
call wait_for_cpu_mail
|
|
lrs $29,@CMBL
|
|
call wait_for_cpu_mail
|
|
lrs $29,@CMBL
|
|
call wait_for_cpu_mail
|
|
lrs $29,@CMBL
|
|
call wait_for_cpu_mail
|
|
lr $5,@CMBL
|
|
andi $31,#0x0fff
|
|
mrr $4,$31
|
|
call wait_for_cpu_mail
|
|
lr $7,@CMBL
|
|
call wait_for_cpu_mail
|
|
lr $6,@CMBL
|
|
call wait_for_cpu_mail
|
|
lr $0,@CMBL
|
|
call wait_for_cpu_mail
|
|
lrs $24,@CMBL
|
|
andi $31,#0x0fff
|
|
mrr $26,$31
|
|
call wait_for_cpu_mail
|
|
lrs $25,@CMBL
|
|
call wait_for_cpu_mail
|
|
lrs $27,@CMBL
|
|
sbclr #0x05
|
|
sbclr #0x06
|
|
jmp 0x80b5
|
|
halt
|
|
|
|
/**************************************************************************************************************************************/
|
|
// send the samples for the internal buffer to the external buffer
|
|
|
|
send_samples:
|
|
|
|
lri $AR0, #MEM_SND
|
|
lris $AXL1, #DMA_TO_CPU;
|
|
lri $AXL0, #NUM_SAMPLES*4 ; len
|
|
lr $ACM0, @ADDRH_SND
|
|
lr $ACL0, @ADDRL_SND
|
|
|
|
call do_dma
|
|
si @DMBL, #0x0004
|
|
si @DIRQ, #0x1 // set the interrupt
|
|
jmp recv_cmd
|
|
|
|
/**************************************************************************************************************************************/
|
|
// get the address of the voice datas buffer (CHANNEL DATAS)
|
|
|
|
get_data_addr:
|
|
call wait_for_cpu_mail
|
|
|
|
lrs $ACM0, @CMBH
|
|
lr $ACL0, @CMBL
|
|
|
|
sr @MEM_VECTH, $ACM0
|
|
sr @MEM_VECTL, $ACL0
|
|
|
|
si @DIRQ, #0x0 // clear the interrupt
|
|
jmp recv_cmd
|
|
|
|
/**************************************************************************************************************************************/
|
|
// fill the internal sample buffer and process the voice internally
|
|
|
|
input_samples:
|
|
|
|
clr $ACC0
|
|
lr $ACM0, @MEM_VECTH
|
|
lr $ACL0, @MEM_VECTL
|
|
|
|
lris $AXL0, #0x0004
|
|
sr @RETURN, $AXL0
|
|
si @DIRQ, #0x0000
|
|
|
|
// program DMA to get datas
|
|
|
|
lri $AR0, #MEM_REG
|
|
lris $AXL1, #DMA_TO_DSP
|
|
lris $AXL0, #64 ; len
|
|
|
|
call do_dma
|
|
|
|
lri $AR1, #MEM_SND
|
|
lri $ACL1, #0;
|
|
|
|
lri $AXL0, #NUM_SAMPLES
|
|
bloop $AXL0, loop_get1
|
|
|
|
srri @$AR1, $ACL1
|
|
srri @$AR1, $ACL1
|
|
|
|
loop_get1:
|
|
nop
|
|
|
|
lr $ACM0, @ADDRH_SND
|
|
lr $ACL0, @ADDRL_SND
|
|
jmp start_main
|
|
|
|
/**************************************************************************************************************************************/
|
|
// get samples from the external buffer to the internal buffer and process the voice mixing the samples internally
|
|
|
|
input_samples2:
|
|
|
|
clr $ACC0
|
|
lr $ACM0, @MEM_VECTH
|
|
lr $ACL0, @MEM_VECTL
|
|
|
|
lris $AXL0, #0x0004
|
|
sr @RETURN, $AXL0
|
|
si @DIRQ, #0x0000
|
|
|
|
// program DMA to get datas
|
|
|
|
lri $AR0, #MEM_REG
|
|
lri $AXL1, #DMA_TO_DSP
|
|
lris $AXL0, #64 ; len
|
|
|
|
call do_dma
|
|
|
|
lr $ACM0, @ADDRH_SND
|
|
lr $ACL0, @ADDRL_SND
|
|
|
|
lri $AR0, #MEM_SND
|
|
lris $AXL1, #DMA_TO_DSP;
|
|
lri $AXL0, #NUM_SAMPLES*4; len
|
|
|
|
call do_dma
|
|
|
|
jmp start_main
|
|
|
|
/**************************************************************************************************************************************/
|
|
// process the voice mixing the samples internally
|
|
|
|
input_next_samples:
|
|
|
|
clr $ACC0
|
|
lr $ACM0, @MEM_VECTH
|
|
lr $ACL0, @MEM_VECTL
|
|
|
|
lris $AXL0, #0x0004
|
|
sr @RETURN, $AXL0
|
|
si @DIRQ, #0x0000
|
|
|
|
// program DMA to get datas
|
|
|
|
lri $AR0, #MEM_REG
|
|
lris $AXL1, #DMA_TO_DSP
|
|
lris $AXL0, #64 ; len
|
|
|
|
call do_dma
|
|
|
|
/**************************************************************************************************************************************/
|
|
// mixing and control pitch to create 1024 Stereo Samples at 16 bits from here
|
|
|
|
start_main:
|
|
|
|
lri $R08, #48000
|
|
|
|
// load the previous samples used
|
|
|
|
lr $AXH0, @SMP_R
|
|
lr $AXH1, @SMP_L
|
|
|
|
// optimize the jump function to get MONO/STEREO 8/16 bits samples
|
|
|
|
lr $ACM1, @FLAGSL_SMP
|
|
andi $ACM1, #0x3
|
|
addi $ACM1, #sample_selector
|
|
mrr $AR3, $ACM1
|
|
ilrr $ACM1, @$AR3
|
|
mrr $AR3, $ACM1 // AR3 countain the jump loaded from sample selector
|
|
|
|
clr $ACC0
|
|
|
|
// test for channel paused
|
|
|
|
lr $ACM0, @FLAGSL_SMP
|
|
andcf $ACM0, #0x20
|
|
jlz end_main
|
|
|
|
// load the sample address
|
|
|
|
lr $ACM0, @ADDRH_SMP
|
|
lr $ACL0, @ADDRL_SMP
|
|
|
|
// test if ADDR_SMP & ADDR2H_SMP are zero
|
|
|
|
tst $ACC0
|
|
jnz do_not_change1
|
|
|
|
// set return as "change of buffer"
|
|
|
|
lris $AXL0, #0x0004
|
|
sr @RETURN, $AXL0
|
|
|
|
// change to buffer 2 if it is possible
|
|
|
|
call change_buffer
|
|
|
|
// stops if again 0 address
|
|
|
|
tst $ACC0
|
|
jz save_datas_end
|
|
|
|
do_not_change1:
|
|
|
|
|
|
// backup the external sample address
|
|
|
|
mrr $IX2, $ACM0
|
|
mrr $IX3, $ACL0
|
|
|
|
|
|
// load the counter pitch
|
|
|
|
//lr $r08, @COUNTERH_SMP
|
|
//lr $r09, @COUNTERL_SMP
|
|
|
|
// load the end address of the samples
|
|
|
|
lr $r0a, @ADDREH_SMP
|
|
lr $r0b, @ADDREL_SMP
|
|
|
|
// load AR1 with internal buffer address
|
|
|
|
lri $AR1, #MEM_SND
|
|
|
|
/////////////////////////////////////
|
|
// delay time section
|
|
/////////////////////////////////////
|
|
|
|
// load AXL0 with the samples to be processed
|
|
|
|
lri $AXL0, #NUM_SAMPLES
|
|
|
|
// test if DELAY == 0 and skip or not
|
|
|
|
clr $ACC0
|
|
clr $ACC1
|
|
lr $ACH0, @DELAYH_SND
|
|
lr $ACM0, @DELAYL_SND
|
|
tst $ACC0
|
|
jz no_delay
|
|
|
|
// samples left and right to 0
|
|
|
|
lris $AXH0, #0
|
|
lris $AXH1, #0
|
|
|
|
// load the samples to be processed in ACM1
|
|
|
|
mrr $ACM1, $AXL0
|
|
l_delay:
|
|
iar $AR1 // skip two samples
|
|
iar $AR1
|
|
decm $ACM1
|
|
jz exit_delay1 // exit1 if samples to be processed == 0
|
|
|
|
decm $ACM0
|
|
jz exit_delay2 // exit2 if delay time == 0
|
|
jmp l_delay
|
|
|
|
// store the remanent delay and ends
|
|
|
|
exit_delay1:
|
|
decm $ACM0
|
|
|
|
sr @DELAYH_SND, $ACH0
|
|
sr @DELAYL_SND, $ACM0
|
|
|
|
lris $AXL0,#0 ; exit from loop
|
|
|
|
jmp no_delay
|
|
|
|
|
|
exit_delay2:
|
|
|
|
// store delay=0 and continue
|
|
|
|
sr @DELAYH_SND, $ACH0
|
|
sr @DELAYL_SND, $ACM0
|
|
mrr $AXL0, $ACL1 // load remanent samples to be processed in AXL0
|
|
|
|
no_delay:
|
|
|
|
/////////////////////////////////////
|
|
// end of delay time section
|
|
/////////////////////////////////////
|
|
)" // Work around C2026 on MSVC, which allows at most 16380 single-byte characters in a single
|
|
// non-concatenated string literal (but you can concatenate multiple shorter string literals to
|
|
// produce a longer string just fine). (This comment is not part of the actual test program,
|
|
// and instead there is a single blank line at this location.)
|
|
R"(
|
|
/* bucle de generacion de samples */
|
|
|
|
|
|
// load the sample buffer with address aligned to 32 bytes blocks (first time)
|
|
|
|
si @DSCR, #DMA_TO_DSP // very important!: load_smp_addr_align and jump_load_smp_addr need fix this DMA Register (I gain some cycles so)
|
|
|
|
// load_smp_addr_align input: $IX2:$IX3
|
|
|
|
call load_smp_addr_align
|
|
|
|
// load the volume registers
|
|
|
|
lr $IX0, @LEFT_VOLUME
|
|
lr $IX1, @RIGHT_VOLUME
|
|
|
|
// test the freq value
|
|
|
|
clr $ACC0
|
|
lr $ACH0, @FREQH_SMP
|
|
lr $ACM0, @FREQL_SMP
|
|
|
|
clr $ACC1
|
|
;lri $ACM1,#48000
|
|
mrr $ACM1, $R08
|
|
cmp
|
|
|
|
// select the output of the routine to process stereo-mono 8/16bits samples
|
|
|
|
lri $AR0, #get_sample // fast method <=48000
|
|
|
|
// if number is greater freq>48000 fix different routine
|
|
|
|
ifg
|
|
lri $AR0, #get_sample2 // slow method >48000
|
|
|
|
// loops for samples to be processed
|
|
|
|
bloop $AXL0, loop_end
|
|
|
|
//srri @$AR1, $AXH0 // put sample R
|
|
//srri @$AR1, $AXH1 // put sample L
|
|
|
|
// Mix right sample section
|
|
|
|
lrr $ACL0, @$AR1 // load in ACL0 the right sample from the internal buffer
|
|
movax $ACC1, $AXL1 // big trick :) load the current sample <<16 and sign extended
|
|
|
|
asl $ACC0,#24 // convert sample from buffer to 24 bit number with sign extended (ACH0:ACM0)
|
|
asr $ACC0,#-8
|
|
|
|
add $ACC0,$ACC1 // current_sample+buffer sample
|
|
|
|
cmpi $ACM0,#32767 // limit to 32767
|
|
jle right_skip
|
|
|
|
lri $ACM0, #32767
|
|
jmp right_skip2
|
|
|
|
right_skip:
|
|
|
|
cmpi $ACM0,#-32768 // limit to -32768
|
|
ifle
|
|
lri $ACM0, #-32768
|
|
|
|
right_skip2:
|
|
|
|
srri @$AR1, $ACM0 // store the right sample mixed to the internal buffer and increment AR1
|
|
|
|
// Mix left sample section
|
|
|
|
lrr $ACL0, @$AR1 // load in ACL0 the left sample from the internal buffer
|
|
|
|
movax $ACC1, $AXL0 // big trick :) load the current sample <<16 and sign extended
|
|
|
|
asl $ACC0, #24 // convert sample from buffer to 24 bit number with sign extended (ACH0:ACM0)
|
|
asr $ACC0, #-8
|
|
|
|
add $ACC0, $ACC1 // current_sample+buffer sample
|
|
|
|
cmpi $ACM0,#32767 // limit to 32767
|
|
jle left_skip
|
|
|
|
lri $ACM0, #32767
|
|
jmp left_skip2
|
|
|
|
left_skip:
|
|
|
|
cmpi $ACM0,#-32768 // limit to -32768
|
|
ifle
|
|
lri $ACM0, #-32768
|
|
|
|
left_skip2:
|
|
|
|
srri @$AR1, $ACM0 // store the left sample mixed to the internal buffer and increment AR1
|
|
|
|
// adds the counter with the voice frequency and test if it >=48000 to get the next sample
|
|
|
|
clr $ACC1
|
|
lr $ACH1, @COUNTERH_SMP
|
|
lr $ACM1, @COUNTERL_SMP
|
|
clr $ACC0
|
|
lr $ACH0, @FREQH_SMP
|
|
lr $ACM0, @FREQL_SMP
|
|
|
|
add $ACC1,$ACC0
|
|
clr $ACC0
|
|
//lri $ACM0,#48000
|
|
mrr $ACM0, $R08
|
|
|
|
cmp
|
|
|
|
jrnc $AR0 //get_sample or get_sample2 method
|
|
|
|
sr @COUNTERH_SMP, $ACH1
|
|
sr @COUNTERL_SMP, $ACM1
|
|
|
|
jmp loop_end
|
|
|
|
// get a new sample for freq > 48000 Hz
|
|
|
|
get_sample2: // slow method
|
|
|
|
sub $ACC1,$ACC0 // restore the counter
|
|
|
|
// restore the external sample buffer address
|
|
|
|
clr $ACC0
|
|
mrr $ACM0, $IX2 // load ADDRH_SMP
|
|
mrr $ACL0, $IX3 // load ADDRL_SMP
|
|
|
|
lr $AXL1, @FLAGSH_SMP // add the step to get the next samples
|
|
addaxl $ACC0, $AXL1
|
|
|
|
mrr $IX2, $ACM0 // store ADDRH_SMP
|
|
mrr $IX3, $ACL0 // store ADDRL_SMP
|
|
|
|
mrr $ACM0, $ACL0
|
|
andf $ACM0, #0x1f
|
|
|
|
// load_smp_addr_align input: $IX2:$IX3 call if (ACM0 & 0x1f)==0
|
|
|
|
calllz load_smp_addr_align
|
|
|
|
clr $ACC0
|
|
//lri $ACM0,#48000
|
|
mrr $ACM0, $R08
|
|
|
|
cmp
|
|
|
|
jle get_sample2
|
|
|
|
sr @COUNTERH_SMP, $ACH1
|
|
sr @COUNTERL_SMP, $ACM1
|
|
|
|
mrr $ACM0, $IX2 // load ADDRH_SMP
|
|
mrr $ACL0, $IX3 // load ADDRL_SMP
|
|
|
|
clr $ACC1
|
|
mrr $ACM1, $r0a // load ADDREH_SMP
|
|
mrr $ACL1, $r0b // load ADDREL_SMP
|
|
|
|
// compares if the current address is >= end address to change the buffer or stops
|
|
|
|
cmp
|
|
|
|
// if addr>addr end get a new buffer (if you uses double buffer)
|
|
|
|
jc get_new_buffer
|
|
|
|
// load samples from dma, return $ar2 with the addr to get the samples and return using $ar0 to the routine to process 8-16bits Mono/Stereo
|
|
|
|
jmp jump_load_smp_addr
|
|
|
|
// get a new sample for freq <= 48000 Hz
|
|
|
|
get_sample: // fast method
|
|
|
|
sub $ACC1,$ACC0 // restore the counter
|
|
sr @COUNTERH_SMP, $ACH1
|
|
sr @COUNTERL_SMP, $ACM1
|
|
|
|
// restore the external sample buffer address
|
|
|
|
clr $ACC0
|
|
mrr $ACM0, $IX2 // load ADDRH_SMP
|
|
mrr $ACL0, $IX3 // load ADDRL_SMP
|
|
|
|
lr $AXL1, @FLAGSH_SMP // add the step to get the next samples
|
|
addaxl $ACC0, $AXL1
|
|
|
|
clr $ACC1
|
|
mrr $ACM1, $r0a // load ADDREH_SMP
|
|
mrr $ACL1, $r0b // load ADDREL_SMP
|
|
|
|
// compares if the current address is >= end address to change the buffer or stops
|
|
|
|
cmp
|
|
jc get_new_buffer
|
|
|
|
// load the new sample from the buffer
|
|
|
|
mrr $IX2, $ACM0 // store ADDRH_SMP
|
|
mrr $IX3, $ACL0 // store ADDRL_SMP
|
|
|
|
// load samples from dma, return $ar2 with the addr and return using $ar0 to the routine to process 8-16bits Mono/Stereo or addr_get_sample_again
|
|
|
|
jmp jump_load_smp_addr
|
|
|
|
sample_selector:
|
|
cw mono_8bits
|
|
cw mono_16bits
|
|
cw stereo_8bits
|
|
cw stereo_16bits
|
|
|
|
get_new_buffer:
|
|
|
|
// set return as "change of buffer": it need to change the sample address
|
|
|
|
lris $AXL0, #0x0004
|
|
sr @RETURN, $AXL0
|
|
|
|
call change_buffer // load add from addr2
|
|
|
|
// addr is 0 ? go to zero_samples and exit
|
|
|
|
tst $acc0
|
|
jz zero_samples
|
|
|
|
// load_smp_addr_align input: $IX2:$IX3
|
|
|
|
call load_smp_addr_align // force the load the samples cached (address aligned)
|
|
|
|
// jump_load_smp_addr: $IX2:$IX3
|
|
// load samples from dma, return $ar2 with the addr to get the samples and return using $ar0 to the routine to process 8-16bits Mono/Stereo
|
|
|
|
jmp jump_load_smp_addr
|
|
|
|
// set to 0 the current samples
|
|
|
|
zero_samples:
|
|
|
|
lris $AXH0, #0
|
|
lris $AXH1, #0
|
|
jmp out_samp
|
|
|
|
mono_8bits:
|
|
|
|
// 8 bits mono
|
|
mrr $ACM1, $IX3
|
|
lrri $ACL0, @$AR2
|
|
andf $ACM1, #0x1
|
|
|
|
iflz // obtain sample0-sample1 from 8bits packet
|
|
asr $ACC0, #-8
|
|
asl $ACC0, #8
|
|
|
|
mrr $AXH1,$ACL0
|
|
mrr $AXH0,$ACL0
|
|
jmp out_samp
|
|
|
|
stereo_8bits:
|
|
|
|
// 8 bits stereo
|
|
|
|
lrri $ACL0, @$AR2
|
|
mrr $ACM0, $ACL0
|
|
andi $ACM0, #0xff00
|
|
mrr $AXH1, $ACM0
|
|
lsl $ACC0, #8
|
|
mrr $AXH0, $ACL0
|
|
|
|
jmp out_samp
|
|
|
|
mono_16bits:
|
|
|
|
// 16 bits mono
|
|
|
|
lrri $AXH1, @$AR2
|
|
mrr $AXH0,$AXH1
|
|
jmp out_samp
|
|
|
|
stereo_16bits:
|
|
|
|
// 16 bits stereo
|
|
|
|
lrri $AXH1, @$AR2
|
|
lrri $AXH0, @$AR2
|
|
|
|
out_samp:
|
|
|
|
// multiply sample x volume
|
|
|
|
// LEFT_VOLUME
|
|
mrr $AXL0,$IX0
|
|
mul $AXL0,$AXH0
|
|
movp $ACC0
|
|
asr $ACC0,#-8
|
|
mrr $AXH0, $ACL0
|
|
|
|
// RIGHT VOLUME
|
|
mrr $AXL1,$IX1
|
|
mul $AXL1,$AXH1
|
|
movp $ACC0
|
|
asr $ACC0,#-8
|
|
mrr $AXH1, $ACL0
|
|
|
|
loop_end:
|
|
nop
|
|
|
|
end_process:
|
|
|
|
// load the sample address
|
|
|
|
clr $ACC0
|
|
mrr $ACM0, $IX2
|
|
mrr $ACL0, $IX3
|
|
|
|
tst $ACC0
|
|
jnz save_datas_end
|
|
|
|
// set return as "change of buffer"
|
|
|
|
lris $AXL0, #0x0004
|
|
sr @RETURN, $AXL0
|
|
|
|
// change to buffer 2 if it is possible
|
|
|
|
call change_buffer
|
|
|
|
save_datas_end:
|
|
|
|
sr @ADDRH_SMP, $IX2
|
|
sr @ADDRL_SMP, $IX3
|
|
sr @SMP_R, $AXH0
|
|
sr @SMP_L, $AXH1
|
|
|
|
end_main:
|
|
|
|
// program DMA to send the CHANNEL DATAS changed
|
|
|
|
clr $ACC0
|
|
lr $ACM0, @MEM_VECTH
|
|
lr $ACL0, @MEM_VECTL
|
|
|
|
lri $AR0, #MEM_REG
|
|
lris $AXL1, #DMA_TO_CPU
|
|
lris $AXL0, #64 ; len
|
|
|
|
call do_dma
|
|
|
|
si @DMBH, #0xdcd1
|
|
lr $ACL0, @RETURN
|
|
|
|
sr @DMBL, $ACL0
|
|
si @DIRQ, #0x1 // set the interrupt
|
|
|
|
jmp recv_cmd
|
|
|
|
change_buffer:
|
|
|
|
clr $ACC0
|
|
lr $ACM0, @LEFT_VOLUME2
|
|
lr $ACL0, @RIGHT_VOLUME2
|
|
sr @LEFT_VOLUME, $ACM0
|
|
sr @RIGHT_VOLUME, $ACL0
|
|
mrr $IX0, $ACM0
|
|
mrr $IX1, $ACL0
|
|
|
|
lr $ACM0, @ADDR2EH_SMP
|
|
lr $ACL0, @ADDR2EL_SMP
|
|
sr @ADDREH_SMP, $ACM0
|
|
sr @ADDREL_SMP, $ACL0
|
|
mrr $r0a, $ACM0
|
|
mrr $r0b, $ACL0
|
|
|
|
lr $ACM0, @ADDR2H_SMP
|
|
lr $ACL0, @ADDR2L_SMP
|
|
sr @ADDRH_SMP, $ACM0
|
|
sr @ADDRL_SMP, $ACL0
|
|
sr @BACKUPH_SMP, $ACM0
|
|
sr @BACKUPL_SMP, $ACL0
|
|
mrr $IX2, $ACM0
|
|
mrr $IX3, $ACL0
|
|
|
|
lr $ACM1, @FLAGSL_SMP
|
|
andcf $ACM1, #0x4
|
|
retlz
|
|
|
|
sr @ADDR2H_SMP, $ACH0
|
|
sr @ADDR2L_SMP, $ACH0
|
|
sr @ADDR2EH_SMP, $ACH0
|
|
sr @ADDR2EL_SMP, $ACH0
|
|
ret
|
|
|
|
/**************************************************************/
|
|
/* DMA ROUTINE */
|
|
/**************************************************************/
|
|
|
|
do_dma:
|
|
|
|
sr @DSMAH, $ACM0
|
|
sr @DSMAL, $ACL0
|
|
sr @DSPA, $AR0
|
|
sr @DSCR, $AXL1
|
|
sr @DSBL, $AXL0
|
|
|
|
wait_dma:
|
|
|
|
lrs $ACM1, @DSCR
|
|
andcf $ACM1, #0x4
|
|
jlz wait_dma
|
|
ret
|
|
|
|
|
|
wait_for_dsp_mail:
|
|
|
|
lrs $ACM1, @DMBH
|
|
andcf $ACM1, #0x8000
|
|
jlz wait_for_dsp_mail
|
|
ret
|
|
|
|
wait_for_cpu_mail:
|
|
|
|
lrs $ACM1, @cmbh
|
|
andcf $ACM1, #0x8000
|
|
jlnz wait_for_cpu_mail
|
|
ret
|
|
|
|
load_smp_addr_align:
|
|
|
|
mrr $ACL0, $IX3 // load ADDRL_SMP
|
|
|
|
lsr $ACC0, #-5
|
|
lsl $ACC0, #5
|
|
sr @DSMAH, $IX2
|
|
sr @DSMAL, $ACL0
|
|
si @DSPA, #MEM_SAMP
|
|
;si @DSCR, #DMA_TO_DSP
|
|
si @DSBL, #0x20
|
|
|
|
wait_dma1:
|
|
lrs $ACM0, @DSCR
|
|
andcf $ACM0, #0x4
|
|
jlz wait_dma1
|
|
|
|
lri $AR2, #MEM_SAMP
|
|
ret
|
|
|
|
|
|
//////////////////////////////////////////
|
|
|
|
jump_load_smp_addr:
|
|
|
|
mrr $ACM0, $IX3 // load ADDRL_SMP
|
|
asr $ACC0, #-1
|
|
andi $ACM0, #0xf
|
|
jz jump_load_smp_dma
|
|
|
|
addi $ACM0, #MEM_SAMP
|
|
mrr $AR2, $ACM0
|
|
jmpr $AR3
|
|
|
|
jump_load_smp_dma:
|
|
|
|
sr @DSMAH, $IX2
|
|
sr @DSMAL, $IX3
|
|
si @DSPA, #MEM_SAMP
|
|
;si @DSCR, #DMA_TO_DSP // to gain some cycles
|
|
si @DSBL, #0x20
|
|
|
|
wait_dma2:
|
|
lrs $ACM0, @DSCR
|
|
andcf $ACM0, #0x4
|
|
jlz wait_dma2
|
|
|
|
lri $AR2, #MEM_SAMP
|
|
jmpr $AR3
|
|
|
|
// exception table
|
|
|
|
exception0: // RESET
|
|
rti
|
|
|
|
exception1: // STACK OVERFLOW
|
|
rti
|
|
|
|
exception2:
|
|
rti
|
|
|
|
exception3:
|
|
rti
|
|
|
|
exception4:
|
|
rti
|
|
|
|
exception5: // ACCELERATOR ADDRESS OVERFLOW
|
|
rti
|
|
|
|
exception6:
|
|
rti
|
|
|
|
exception7:
|
|
rti
|
|
|
|
// routine to read a word of the IROM space
|
|
|
|
rom_dump_word:
|
|
|
|
clr $ACC0
|
|
|
|
lr $ACM0, @CMBH
|
|
ori $ACM0, #0x8000
|
|
mrr $AR0, $ACM0
|
|
clr $ACC0
|
|
ilrr $ACM0, @$AR0
|
|
sr @DMBH, $ACL0
|
|
sr @DMBL, $ACM0
|
|
;si @DIRQ, #0x1 // set the interrupt
|
|
clr $ACC0
|
|
jmp recv_cmd
|
|
|
|
polla_loca:
|
|
|
|
clr $ACC0
|
|
lri $acm0, #0x0
|
|
andf $acm0,#0x1
|
|
|
|
sr @DMBH, $sr
|
|
sr @DMBL, $acm0
|
|
;si @DIRQ, #0x1 // set the interrupt
|
|
clr $ACC0
|
|
jmp recv_cmd
|
|
|
|
)";
|