summaryrefslogtreecommitdiff
path: root/Source/UnitTests/Core/DSP/HermesText.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/UnitTests/Core/DSP/HermesText.cpp')
-rw-r--r--Source/UnitTests/Core/DSP/HermesText.cpp1086
1 files changed, 1086 insertions, 0 deletions
diff --git a/Source/UnitTests/Core/DSP/HermesText.cpp b/Source/UnitTests/Core/DSP/HermesText.cpp
new file mode 100644
index 0000000000..f7f83a9737
--- /dev/null
+++ b/Source/UnitTests/Core/DSP/HermesText.cpp
@@ -0,0 +1,1086 @@
+/* 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 0x1c // accumulator (global)
+ACC1: equ 0x1d
+
+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 $ACL0
+ 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 $ACL1
+ lr $ACH1, @COUNTERH_SMP
+ lr $ACM1, @COUNTERL_SMP
+ clr $ACL0
+ 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 $ACL0, #-8
+ asl $ACL0, #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 $ACL0, #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 $ACL0
+ asr $ACL0,#-8
+ mrr $AXH0, $ACL0
+
+ // RIGHT VOLUME
+ mrr $AXL1,$IX1
+ mul $AXL1,$AXH1
+ movp $ACL0
+ asr $ACL0,#-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
+
+)";