1/* DSP_MIXER -> PCM VOICE SOFTWARE PROCESSOR (8-16 Bits Mono/Stereo Voices)
2
3// Thanks to Duddie for you hard work and documentation
4
5Copyright (c) 2008 Hermes <www.entuwii.net>
6All rights reserved.
7
8Redistribution and use in source and binary forms, with or without modification, are
9permitted provided that the following conditions are met:
10
11- Redistributions of source code must retain the above copyright notice, this list of
12  conditions and the following disclaimer.
13- Redistributions in binary form must reproduce the above copyright notice, this list
14  of conditions and the following disclaimer in the documentation and/or other
15  materials provided with the distribution.
16- The names of the contributors may not be used to endorse or promote products derived
17  from this software without specific prior written permission.
18
19THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29*/
30
31
32/********************************/
33/**      REGISTER NAMES        **/
34/********************************/
35
36AR0:	equ	0x00	; address registers
37AR1:	equ	0x01
38AR2:	equ	0x02
39AR3:	equ	0x03	// used as jump function selector
40
41IX0:	equ	0x04	// LEFT_VOLUME accel
42IX1:	equ	0x05	// RIGHT_VOLUME accel
43IX2:	equ	0x06	// ADDRH_SMP accel
44IX3:	equ	0x07	// ADDRL_SMP accel
45
46R08:	equ	0x08	// fixed to 48000 value
47R09:	equ	0x09	// problems using this
48R0A:	equ	0x0a	// ADDREH_SMP accel
49R0B:	equ	0x0b	// ADDREL_SMP accel
50
51ST0:	equ	0x0c
52ST1:	equ	0x0d
53ST2:	equ	0x0e
54ST3:	equ	0x0f
55
56CONFIG:	equ	0x12
57SR:	equ	0x13
58
59PRODL: equ	0x14
60PRODM: equ	0x15
61PRODH: equ	0x16
62PRODM2: equ	0x17
63
64AXL0:  equ	0x18
65AXL1:  equ	0x19
66AXH0:  equ	0x1A	// SMP_R accel
67AXH1:  equ	0x1b	// SMP_L accel
68
69ACC0:  equ	0x1c	// accumulator (global)
70ACC1:  equ	0x1d
71
72ACL0:  equ	0x1c	// Low accumulator
73ACL1:  equ	0x1d
74ACM0:  equ	0x1e	// Mid accumulator
75ACM1:  equ	0x1f
76ACH0:  equ	0x10	// Sign extended 8 bit register 0
77ACH1:  equ	0x11	// Sign extended 8 bit register 1
78
79/********************************/
80/**  HARDWARE REGISTER ADDRESS **/
81/********************************/
82
83DSCR:	equ	0xffc9	; DSP DMA Control Reg
84DSBL:	equ	0xffcb	; DSP DMA Block Length
85DSPA:	equ	0xffcd	; DSP DMA DMEM Address
86DSMAH:	equ	0xffce	; DSP DMA Mem Address H
87DSMAL:	equ	0xffcf	; DSP DMA Mem Address L
88
89DIRQ:	equ	0xfffb	; DSP Irq Request
90DMBH:	equ	0xfffc	; DSP Mailbox H
91DMBL:	equ	0xfffd	; DSP Mailbox L
92CMBH:	equ	0xfffe	; CPU Mailbox H
93CMBL:	equ	0xffff	; CPU Mailbox L
94
95DMA_TO_DSP:	equ	0
96DMA_TO_CPU:	equ	1
97
98/**************************************************************/
99/*                     NUM_SAMPLES SLICE                      */
100/**************************************************************/
101
102NUM_SAMPLES:	equ	1024	; 1024 stereo samples 16 bits
103
104
105/**************************************************************/
106/*                SOUND CHANNEL REGS                          */
107/**************************************************************/
108
109MEM_REG2:	equ	0x0
110MEM_VECTH:	equ	MEM_REG2
111MEM_VECTL:	equ	MEM_REG2+1
112RETURN:		equ	MEM_REG2+2
113
114/**************************************************************/
115/*                      CHANNEL DATAS                         */
116/**************************************************************/
117
118MEM_REG:	equ	MEM_REG2+0x10
119
120ADDRH_SND:	equ	MEM_REG		// Output buffer
121ADDRL_SND:	equ	MEM_REG+1
122
123DELAYH_SND:	equ	MEM_REG+2	// Delay samples High word
124DELAYL_SND:	equ	MEM_REG+3	// Delay samples Low word
125
126CHAN_REGS:	equ	MEM_REG+4	// specific regs for the channel
127
128FLAGSH_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)
129FLAGSL_SMP:	equ	CHAN_REGS+1	// 0->Mono 8 bits, 1->Stereo 8 bits, 2->Mono 16 bits 3 -> Stereo 16 bits
130
131ADDRH_SMP:	equ	CHAN_REGS+2	// start address
132ADDRL_SMP:	equ	CHAN_REGS+3
133
134ADDREH_SMP:	equ	CHAN_REGS+4	// end address
135ADDREL_SMP:	equ	CHAN_REGS+5
136
137FREQH_SMP:	equ	CHAN_REGS+6	// Freq in Hz to play
138FREQL_SMP:	equ	CHAN_REGS+7
139
140SMP_L:		equ	CHAN_REGS+8	// last sample for left (used to joint various buffers)
141SMP_R:		equ	CHAN_REGS+9	// last sample for right (used to joint various buffers)
142
143COUNTERH_SMP:	equ	CHAN_REGS+10	// pitch counter
144COUNTERL_SMP:	equ	CHAN_REGS+11
145
146LEFT_VOLUME:	equ	CHAN_REGS+12	// volume (0 to 255)
147RIGHT_VOLUME:	equ	CHAN_REGS+13
148
149ADDR2H_SMP:	equ	CHAN_REGS+14	// start address of buffer two (to joint)
150ADDR2L_SMP:	equ	CHAN_REGS+15
151
152ADDR2EH_SMP:	equ	CHAN_REGS+16	// end address of buffer two (to joint)
153ADDR2EL_SMP:	equ	CHAN_REGS+17
154
155LEFT_VOLUME2:	equ	CHAN_REGS+18	// volume (0 to 255) for buffer two
156RIGHT_VOLUME2:	equ	CHAN_REGS+19
157
158BACKUPH_SMP:	equ	CHAN_REGS+20	// start address backup
159BACKUPL_SMP:	equ	CHAN_REGS+21
160
161/**************************************************************/
162/*               VOICE SAMPLE BUFFER DATAS                    */
163/**************************************************************/
164
165MEM_SAMP:	equ	CHAN_REGS+0x20
166
167
168data_end:	equ	MEM_SAMP+0x20
169
170/**************************************************************/
171/*                     SND OUTPUT DATAS                       */
172/**************************************************************/
173
174MEM_SND:	equ	data_end ; it need 2048 words (4096 bytes)
175
176
177
178/***  START CODE ***/
179
180/**************************************************************/
181/*			EXCEPTION TABLE			      */
182/**************************************************************/
183
184	jmp	exception0
185	jmp	exception1
186	jmp	exception2
187	jmp	exception3
188	jmp	exception4
189	jmp	exception5
190	jmp	exception6
191	jmp	exception7
192
193	lri     $CONFIG, #0xff
194	lri	$SR,#0
195	s40
196	clr15
197	m0
198
199/**************************************************************/
200/*                            main                            */
201/**************************************************************/
202
203main:
204
205// send init token to CPU
206
207	si		@DMBH, #0xdcd1
208	si		@DMBL, #0x0000
209	si		@DIRQ, #1
210
211recv_cmd:
212// check if previous mail is received from the CPU
213
214	call	wait_for_dsp_mail
215
216// wait a mail from CPU
217
218	call	wait_for_cpu_mail
219
220	si		@DMBH, #0xdcd1
221
222	clr		$ACC0
223	lri		$ACM0,#0xcdd1
224	cmp
225	jz		sys_command
226
227	clr	$ACC1
228	lrs	$ACM1, @CMBL
229
230	cmpi    $ACM1, #0x111  // fill the internal sample buffer and process the voice internally
231	jz	input_samples
232
233	cmpi    $ACM1, #0x112  // get samples from the external buffer to the internal buffer and process the voice mixing the samples internally
234	jz	input_samples2
235
236	cmpi    $ACM1, #0x123  // get the address of the voice datas buffer (CHANNEL DATAS)
237	jz	get_data_addr
238
239	cmpi    $ACM1, #0x222  // process the voice mixing the samples internally
240	jz	input_next_samples
241
242	cmpi    $ACM1, #0x666  // send the samples for the internal buffer to the external buffer
243	jz	send_samples
244
245	cmpi    $ACM1, #0x777   // special: to dump the IROM Datas (remember disable others functions from the interrupt vector to use)
246	jz	rom_dump_word   // (CMBH+0x8000) countain the address of IROM
247
248	cmpi    $ACM1, #0x888	// Used for test
249	jz	polla_loca
250
251	cmpi	$ACM1, #0x999
252	jz	task_terminate
253
254	si	@DMBL, #0x0004	// return 0 as ignore command
255	si	@DIRQ, #0x1 // set the interrupt
256	jmp	recv_cmd
257
258task_terminate:
259	si	@DMBL, #0x0003
260	si	@DIRQ, #0x1
261	jmp	recv_cmd
262
263sys_command:
264	clr	$ACC1
265	lrs	$ACM1, @CMBL
266
267	cmpi	$ACM1,#0x0001
268	jz		run_nexttask
269
270	cmpi	$ACM1,#0x0002
271	jz		0x8000
272
273	jmp		recv_cmd
274
275run_nexttask:
276	s40
277	call		wait_for_cpu_mail
278	lrs			$29,@CMBL
279	call		wait_for_cpu_mail
280	lrs			$29,@CMBL
281	call		wait_for_cpu_mail
282	lrs			$29,@CMBL
283	call		wait_for_cpu_mail
284	lr			$5,@CMBL
285	andi		$31,#0x0fff
286	mrr			$4,$31
287	call		wait_for_cpu_mail
288	lr			$7,@CMBL
289	call		wait_for_cpu_mail
290	lr			$6,@CMBL
291	call		wait_for_cpu_mail
292	lr			$0,@CMBL
293	call		wait_for_cpu_mail
294	lrs			$24,@CMBL
295	andi		$31,#0x0fff
296	mrr			$26,$31
297	call		wait_for_cpu_mail
298	lrs			$25,@CMBL
299	call		wait_for_cpu_mail
300	lrs			$27,@CMBL
301	sbclr		#0x05
302	sbclr		#0x06
303	jmp			0x80b5
304	halt
305
306/**************************************************************************************************************************************/
307// send the samples for the internal buffer to the external buffer
308
309send_samples:
310
311	lri	$AR0, #MEM_SND
312	lris	$AXL1, #DMA_TO_CPU;
313	lri	$AXL0, #NUM_SAMPLES*4 ; len
314	lr	$ACM0, @ADDRH_SND
315    lr	$ACL0, @ADDRL_SND
316
317	call	do_dma
318	si	@DMBL, #0x0004
319	si	@DIRQ, #0x1 // set the interrupt
320	jmp	recv_cmd
321
322/**************************************************************************************************************************************/
323// get the address of the voice datas buffer (CHANNEL DATAS)
324
325get_data_addr:
326	call	wait_for_cpu_mail
327
328	lrs	$ACM0, @CMBH
329	lr	$ACL0, @CMBL
330
331	sr	@MEM_VECTH, $ACM0
332	sr	@MEM_VECTL, $ACL0
333
334	si	@DIRQ, #0x0 // clear the interrupt
335	jmp	recv_cmd
336
337/**************************************************************************************************************************************/
338// fill the internal sample buffer and process the voice internally
339
340input_samples:
341
342	clr	$ACC0
343	lr	$ACM0, @MEM_VECTH
344	lr	$ACL0, @MEM_VECTL
345
346	lris	$AXL0, #0x0004
347	sr	@RETURN, $AXL0
348	si	@DIRQ, #0x0000
349
350        // program DMA to get datas
351
352	lri	$AR0, #MEM_REG
353	lris	$AXL1, #DMA_TO_DSP
354	lris	$AXL0, #64 ; len
355
356	call	do_dma
357
358	lri	$AR1, #MEM_SND
359	lri	$ACL1, #0;
360
361	lri	$AXL0, #NUM_SAMPLES
362	bloop	$AXL0, loop_get1
363
364	srri	@$AR1, $ACL1
365	srri	@$AR1, $ACL1
366
367loop_get1:
368	nop
369
370	lr	$ACM0, @ADDRH_SND
371        lr	$ACL0, @ADDRL_SND
372	jmp	start_main
373
374/**************************************************************************************************************************************/
375// get samples from the external buffer to the internal buffer and process the voice mixing the samples internally
376
377input_samples2:
378
379	clr	$ACC0
380	lr	$ACM0, @MEM_VECTH
381	lr	$ACL0, @MEM_VECTL
382
383	lris	$AXL0, #0x0004
384	sr	@RETURN, $AXL0
385	si	@DIRQ, #0x0000
386
387        // program DMA to get datas
388
389	lri	$AR0, #MEM_REG
390	lri	$AXL1, #DMA_TO_DSP
391	lris	$AXL0, #64 ; len
392
393	call	do_dma
394
395	lr	$ACM0, @ADDRH_SND
396        lr	$ACL0, @ADDRL_SND
397
398	lri	$AR0, #MEM_SND
399	lris	$AXL1, #DMA_TO_DSP;
400	lri	$AXL0, #NUM_SAMPLES*4; len
401
402	call	do_dma
403
404	jmp	start_main
405
406/**************************************************************************************************************************************/
407// process the voice mixing the samples internally
408
409input_next_samples:
410
411	clr	$ACC0
412	lr	$ACM0, @MEM_VECTH
413	lr	$ACL0, @MEM_VECTL
414
415	lris	$AXL0, #0x0004
416	sr	@RETURN, $AXL0
417	si	@DIRQ, #0x0000
418
419        // program DMA to get datas
420
421	lri	$AR0, #MEM_REG
422	lris	$AXL1, #DMA_TO_DSP
423	lris	$AXL0, #64 ; len
424
425	call	do_dma
426
427/**************************************************************************************************************************************/
428// mixing and control pitch to create 1024 Stereo Samples at 16 bits from here
429
430start_main:
431
432	lri	$R08, #48000
433
434	// load the previous samples used
435
436	lr	$AXH0, @SMP_R
437        lr	$AXH1, @SMP_L
438
439// optimize the jump function to get MONO/STEREO 8/16 bits samples
440
441	lr	$ACM1, @FLAGSL_SMP
442	andi	$ACM1, #0x3
443	addi	$ACM1, #sample_selector
444	mrr	$AR3, $ACM1
445	ilrr	$ACM1, @$AR3
446	mrr	$AR3, $ACM1 // AR3 countain the jump loaded from sample selector
447
448	clr	$ACC0
449
450// test for channel paused
451
452	lr	$ACM0, @FLAGSL_SMP
453	andcf	$ACM0, #0x20
454	jlz	end_main
455
456// load the sample address
457
458	lr	$ACM0, @ADDRH_SMP
459        lr	$ACL0, @ADDRL_SMP
460
461// test if ADDR_SMP & ADDR2H_SMP are zero
462
463	tst	$ACC0
464	jnz	do_not_change1
465
466// set return as "change of buffer"
467
468	lris	$AXL0, #0x0004
469	sr	@RETURN, $AXL0
470
471// change to buffer 2 if it is possible
472
473	call	change_buffer
474
475// stops if again 0 address
476
477	tst	$ACC0
478	jz	save_datas_end
479
480do_not_change1:
481
482
483// backup the external sample address
484
485	mrr	$IX2, $ACM0
486	mrr	$IX3, $ACL0
487
488
489// load the counter pitch
490
491	//lr	$r08, @COUNTERH_SMP
492	//lr	$r09, @COUNTERL_SMP
493
494// load the end address of the samples
495
496	lr	$r0a, @ADDREH_SMP
497        lr	$r0b, @ADDREL_SMP
498
499// load AR1 with internal buffer address
500
501	lri	$AR1, #MEM_SND
502
503/////////////////////////////////////
504// delay time section
505/////////////////////////////////////
506
507// load AXL0 with the samples to be processed
508
509	lri	$AXL0, #NUM_SAMPLES
510
511// test if DELAY == 0 and skip or not
512
513	clr	$ACC0
514	clr	$ACC1
515	lr	$ACH0, @DELAYH_SND
516        lr	$ACM0, @DELAYL_SND
517	tst	$ACC0
518	jz	no_delay
519
520// samples left and right to 0
521
522	lris	$AXH0, #0
523	lris	$AXH1, #0
524
525// load the samples to be processed in ACM1
526
527	mrr	$ACM1, $AXL0
528l_delay:
529	iar	$AR1 // skip two samples
530	iar	$AR1
531	decm	$ACM1
532	jz	exit_delay1 // exit1 if samples to be processed == 0
533
534	decm	$ACM0
535	jz	exit_delay2 // exit2 if delay time == 0
536	jmp	l_delay
537
538// store the remanent delay and ends
539
540exit_delay1:
541	decm	$ACM0
542
543	sr	@DELAYH_SND, $ACH0
544        sr	@DELAYL_SND, $ACM0
545
546	lris	$AXL0,#0 ; exit from loop
547
548	jmp	no_delay
549
550
551exit_delay2:
552
553	// store delay=0 and continue
554
555	sr	@DELAYH_SND, $ACH0
556        sr	@DELAYL_SND, $ACM0
557	mrr	$AXL0, $ACL1 // load remanent samples to be processed in AXL0
558
559no_delay:
560
561/////////////////////////////////////
562// end of delay time section
563/////////////////////////////////////
564
565/* bucle de generacion de samples */
566
567
568// load the sample buffer with address aligned to 32 bytes blocks (first time)
569
570	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)
571
572// load_smp_addr_align input:  $IX2:$IX3
573
574	call	load_smp_addr_align
575
576// load the volume registers
577
578	lr	$IX0, @LEFT_VOLUME
579	lr	$IX1, @RIGHT_VOLUME
580
581// test the freq value
582
583	clr	$ACL0
584	lr	$ACH0, @FREQH_SMP
585	lr	$ACM0, @FREQL_SMP
586
587	clr	$ACC1
588	;lri	$ACM1,#48000
589	mrr	$ACM1, $R08
590	cmp
591
592// select the output of the routine to process stereo-mono 8/16bits samples
593
594	lri	$AR0, #get_sample // fast method <=48000
595
596// if  number is greater freq>48000 fix different routine
597
598	ifg
599	lri	$AR0, #get_sample2 // slow method >48000
600
601// loops for samples to be processed
602
603	bloop	$AXL0, loop_end
604
605	//srri	@$AR1, $AXH0 // put sample R
606	//srri	@$AR1, $AXH1 // put sample L
607
608// Mix right sample section
609
610	lrr	$ACL0, @$AR1 // load in ACL0 the  right sample from the internal buffer
611	movax	$ACC1, $AXL1 // big trick :)  load the current sample <<16 and sign extended
612
613	asl	$ACC0,#24    // convert sample from buffer to 24 bit number with sign extended (ACH0:ACM0)
614	asr	$ACC0,#-8
615
616	add	$ACC0,$ACC1  // current_sample+buffer sample
617
618	cmpi	$ACM0,#32767 // limit to 32767
619	jle	right_skip
620
621	lri	$ACM0, #32767
622	jmp	right_skip2
623
624right_skip:
625
626	cmpi	$ACM0,#-32768 // limit to -32768
627	ifle
628	lri	$ACM0, #-32768
629
630right_skip2:
631
632	srri	@$AR1, $ACM0 // store the right sample mixed to the internal buffer and increment AR1
633
634// Mix left sample section
635
636	lrr	$ACL0, @$AR1 // load in ACL0 the left sample from the internal buffer
637
638	movax	$ACC1, $AXL0 // big trick :)  load the current sample <<16 and sign extended
639
640	asl	$ACC0, #24   // convert sample from buffer to 24 bit number with sign extended (ACH0:ACM0)
641	asr	$ACC0, #-8
642
643	add	$ACC0, $ACC1 // current_sample+buffer sample
644
645	cmpi	$ACM0,#32767 // limit to 32767
646	jle	left_skip
647
648	lri	$ACM0, #32767
649	jmp	left_skip2
650
651left_skip:
652
653	cmpi	$ACM0,#-32768 // limit to -32768
654	ifle
655	lri	$ACM0, #-32768
656
657left_skip2:
658
659	srri	@$AR1, $ACM0 // store the left sample mixed to the internal buffer and increment AR1
660
661// adds the counter with the voice frequency and test if it >=48000 to get the next sample
662
663	clr	$ACL1
664	lr	$ACH1, @COUNTERH_SMP
665	lr	$ACM1, @COUNTERL_SMP
666	clr	$ACL0
667	lr	$ACH0, @FREQH_SMP
668	lr	$ACM0, @FREQL_SMP
669
670	add	$ACC1,$ACC0
671	clr	$ACC0
672	//lri	$ACM0,#48000
673	mrr	$ACM0, $R08
674
675	cmp
676
677	jrl	$AR0 //get_sample or get_sample2 method
678
679	sr	@COUNTERH_SMP, $ACH1
680        sr	@COUNTERL_SMP, $ACM1
681
682	jmp	loop_end
683
684// get a new sample for freq > 48000 Hz
685
686get_sample2: // slow method
687
688	sub	$ACC1,$ACC0 // restore the counter
689
690// restore the external sample buffer address
691
692	clr	$ACC0
693	mrr	$ACM0, $IX2 // load ADDRH_SMP
694	mrr	$ACL0, $IX3 // load ADDRL_SMP
695
696	lr	$AXL1, @FLAGSH_SMP // add the step to get the next samples
697	addaxl  $ACC0, $AXL1
698
699	mrr	$IX2, $ACM0 // store ADDRH_SMP
700	mrr	$IX3, $ACL0 // store ADDRL_SMP
701
702	mrr	$ACM0, $ACL0
703	andf	$ACM0, #0x1f
704
705// load_smp_addr_align input:  $IX2:$IX3 call if (ACM0 & 0x1f)==0
706
707	calllz	load_smp_addr_align
708
709	clr	$ACC0
710	//lri	$ACM0,#48000
711	mrr	$ACM0, $R08
712
713	cmp
714
715	jle	get_sample2
716
717	sr	@COUNTERH_SMP, $ACH1
718        sr	@COUNTERL_SMP, $ACM1
719
720	mrr	$ACM0, $IX2 // load ADDRH_SMP
721	mrr	$ACL0, $IX3 // load ADDRL_SMP
722
723	clr	$ACC1
724	mrr	$ACM1, $r0a // load ADDREH_SMP
725	mrr	$ACL1, $r0b // load ADDREL_SMP
726
727// compares if the current address is >= end address to change the buffer or stops
728
729	cmp
730
731// if addr>addr end get a new buffer (if you uses double buffer)
732
733	jge	get_new_buffer
734
735// 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
736
737	jmp	jump_load_smp_addr
738
739// get a new sample for freq <= 48000 Hz
740
741get_sample: // fast method
742
743	sub	$ACC1,$ACC0 // restore the counter
744	sr	@COUNTERH_SMP, $ACH1
745        sr	@COUNTERL_SMP, $ACM1
746
747// restore the external sample buffer address
748
749	clr	$ACC0
750	mrr	$ACM0, $IX2 // load ADDRH_SMP
751	mrr	$ACL0, $IX3 // load ADDRL_SMP
752
753	lr	$AXL1, @FLAGSH_SMP // add the step to get the next samples
754	addaxl  $ACC0, $AXL1
755
756	clr	$ACC1
757	mrr	$ACM1, $r0a // load ADDREH_SMP
758	mrr	$ACL1, $r0b // load ADDREL_SMP
759
760// compares if the current address is >= end address to change the buffer or stops
761
762	cmp
763	jge	get_new_buffer
764
765// load the new sample from the buffer
766
767	mrr	$IX2, $ACM0 // store ADDRH_SMP
768	mrr	$IX3, $ACL0 // store ADDRL_SMP
769
770// 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
771
772	jmp	jump_load_smp_addr
773
774sample_selector:
775	cw	mono_8bits
776	cw	mono_16bits
777	cw	stereo_8bits
778	cw	stereo_16bits
779
780get_new_buffer:
781
782// set return as "change of buffer": it need to change the sample address
783
784	lris	$AXL0, #0x0004
785	sr	@RETURN, $AXL0
786
787	call	change_buffer // load add from addr2
788
789// addr is 0 ? go to zero_samples and exit
790
791	tst	$acc0
792	jz	zero_samples
793
794// load_smp_addr_align input:  $IX2:$IX3
795
796	call	load_smp_addr_align // force the load the samples cached (address aligned)
797
798// jump_load_smp_addr:  $IX2:$IX3
799// 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
800
801	jmp	jump_load_smp_addr
802
803// set to 0 the current samples
804
805zero_samples:
806
807	lris	$AXH0, #0
808	lris	$AXH1, #0
809	jmp	out_samp
810
811mono_8bits:
812
813//  8 bits mono
814	mrr	$ACM1, $IX3
815	lrri	$ACL0, @$AR2
816	andf	$ACM1, #0x1
817
818	iflz	// obtain sample0-sample1 from 8bits packet
819	asr	$ACL0, #-8
820	asl	$ACL0, #8
821
822	mrr	$AXH1,$ACL0
823	mrr	$AXH0,$ACL0
824	jmp	out_samp
825
826stereo_8bits:
827
828// 8 bits stereo
829
830	lrri	$ACL0, @$AR2
831	mrr	$ACM0, $ACL0
832	andi	$ACM0, #0xff00
833	mrr	$AXH1, $ACM0
834	lsl	$ACL0, #8
835	mrr	$AXH0, $ACL0
836
837	jmp	out_samp
838
839mono_16bits:
840
841// 16 bits mono
842
843	lrri	$AXH1, @$AR2
844        mrr	$AXH0,$AXH1
845	jmp	out_samp
846
847stereo_16bits:
848
849// 16 bits stereo
850
851	lrri	$AXH1, @$AR2
852	lrri	$AXH0, @$AR2
853
854out_samp:
855
856// multiply sample x volume
857
858	//   LEFT_VOLUME
859	mrr	$AXL0,$IX0
860	mul	$AXL0,$AXH0
861	movp	$ACL0
862	asr	$ACL0,#-8
863	mrr	$AXH0, $ACL0
864
865        // RIGHT VOLUME
866	mrr	$AXL1,$IX1
867	mul	$AXL1,$AXH1
868	movp	$ACL0
869	asr	$ACL0,#-8
870	mrr	$AXH1, $ACL0
871
872loop_end:
873	nop
874
875end_process:
876
877	// load the sample address
878
879	clr	$ACC0
880	mrr	$ACM0, $IX2
881        mrr	$ACL0, $IX3
882
883	tst	$ACC0
884	jnz	save_datas_end
885
886// set return as "change of buffer"
887
888	lris	$AXL0, #0x0004
889	sr	@RETURN, $AXL0
890
891// change to buffer 2 if it is possible
892
893	call	change_buffer
894
895save_datas_end:
896
897	sr	@ADDRH_SMP, $IX2
898        sr	@ADDRL_SMP, $IX3
899	sr	@SMP_R, $AXH0
900        sr	@SMP_L, $AXH1
901
902end_main:
903
904// program DMA to send the CHANNEL DATAS changed
905
906	clr	$ACC0
907	lr	$ACM0, @MEM_VECTH
908	lr	$ACL0, @MEM_VECTL
909
910	lri	$AR0, #MEM_REG
911	lris	$AXL1, #DMA_TO_CPU
912	lris	$AXL0, #64 ; len
913
914	call	do_dma
915
916	si	@DMBH, #0xdcd1
917	lr	$ACL0, @RETURN
918
919	sr	@DMBL, $ACL0
920	si	@DIRQ, #0x1 // set the interrupt
921
922	jmp	recv_cmd
923
924change_buffer:
925
926	clr	$ACC0
927	lr	$ACM0, @LEFT_VOLUME2
928        lr	$ACL0, @RIGHT_VOLUME2
929	sr	@LEFT_VOLUME, $ACM0
930        sr	@RIGHT_VOLUME, $ACL0
931	mrr	$IX0, $ACM0
932	mrr	$IX1, $ACL0
933
934	lr	$ACM0, @ADDR2EH_SMP
935        lr	$ACL0, @ADDR2EL_SMP
936	sr	@ADDREH_SMP, $ACM0
937        sr	@ADDREL_SMP, $ACL0
938	mrr	$r0a, $ACM0
939	mrr	$r0b, $ACL0
940
941	lr	$ACM0, @ADDR2H_SMP
942        lr	$ACL0, @ADDR2L_SMP
943	sr	@ADDRH_SMP, $ACM0
944        sr	@ADDRL_SMP, $ACL0
945	sr	@BACKUPH_SMP, $ACM0
946        sr	@BACKUPL_SMP, $ACL0
947	mrr	$IX2, $ACM0
948	mrr	$IX3, $ACL0
949
950	lr	$ACM1, @FLAGSL_SMP
951	andcf	$ACM1, #0x4
952	retlz
953
954	sr	@ADDR2H_SMP, $ACH0
955	sr	@ADDR2L_SMP, $ACH0
956	sr	@ADDR2EH_SMP, $ACH0
957	sr	@ADDR2EL_SMP, $ACH0
958	ret
959
960/**************************************************************/
961/*                        DMA ROUTINE                         */
962/**************************************************************/
963
964do_dma:
965
966	sr	@DSMAH, $ACM0
967	sr	@DSMAL, $ACL0
968	sr	@DSPA, $AR0
969	sr	@DSCR, $AXL1
970	sr	@DSBL, $AXL0
971
972wait_dma:
973
974	lrs	$ACM1, @DSCR
975	andcf	$ACM1, #0x4
976	jlz	wait_dma
977	ret
978
979
980wait_for_dsp_mail:
981
982	lrs	$ACM1, @DMBH
983	andf	$ACM1, #0x8000
984	jnz	wait_for_dsp_mail
985	ret
986
987wait_for_cpu_mail:
988
989	lrs	$ACM1, @cmbh
990	andcf	$ACM1, #0x8000
991	jlnz	wait_for_cpu_mail
992	ret
993
994load_smp_addr_align:
995
996	mrr	$ACL0, $IX3  // load ADDRL_SMP
997
998	lsr	$ACC0, #-5
999	lsl	$ACC0, #5
1000	sr	@DSMAH, $IX2
1001	sr	@DSMAL, $ACL0
1002	si	@DSPA, #MEM_SAMP
1003	;si	@DSCR, #DMA_TO_DSP
1004	si	@DSBL, #0x20
1005
1006wait_dma1:
1007	lrs	$ACM0, @DSCR
1008	andcf	$ACM0, #0x4
1009	jlz	wait_dma1
1010
1011	lri	$AR2, #MEM_SAMP
1012	ret
1013
1014
1015//////////////////////////////////////////
1016
1017jump_load_smp_addr:
1018
1019	mrr	$ACM0, $IX3  // load ADDRL_SMP
1020	asr	$ACC0, #-1
1021	andi	$ACM0, #0xf
1022	jz	jump_load_smp_dma
1023
1024	addi	$ACM0, #MEM_SAMP
1025	mrr	$AR2, $ACM0
1026	jmpr	$AR3
1027
1028jump_load_smp_dma:
1029
1030	sr	@DSMAH, $IX2
1031	sr	@DSMAL, $IX3
1032	si	@DSPA, #MEM_SAMP
1033	;si	@DSCR, #DMA_TO_DSP // to gain some cycles
1034	si	@DSBL, #0x20
1035
1036wait_dma2:
1037	lrs	$ACM0, @DSCR
1038	andcf	$ACM0, #0x4
1039	jlz	wait_dma2
1040
1041	lri	$AR2, #MEM_SAMP
1042	jmpr	$AR3
1043
1044// exception table
1045
1046exception0:	// RESET
1047	rti
1048
1049exception1:	// STACK OVERFLOW
1050	rti
1051
1052exception2:
1053	rti
1054
1055exception3:
1056	rti
1057
1058exception4:
1059	rti
1060
1061exception5:	// ACCELERATOR ADDRESS OVERFLOW
1062	rti
1063
1064exception6:
1065	rti
1066
1067exception7:
1068	rti
1069
1070// routine to read a word of the IROM space
1071
1072rom_dump_word:
1073
1074	clr $ACC0
1075
1076	lr	$ACM0, @CMBH
1077	ori	$ACM0, #0x8000
1078	mrr	$AR0, $ACM0
1079	clr	$ACC0
1080	ilrr	$ACM0, @$AR0
1081	sr	@DMBH, $ACL0
1082	sr	@DMBL, $ACM0
1083	;si	@DIRQ, #0x1 // set the interrupt
1084	clr	$ACC0
1085	jmp	recv_cmd
1086
1087polla_loca:
1088
1089	clr $ACC0
1090	lri $acm0, #0x0
1091	andf $acm0,#0x1
1092
1093	sr	@DMBH, $sr
1094	sr	@DMBL, $acm0
1095	;si	@DIRQ, #0x1 // set the interrupt
1096	clr	$ACC0
1097	jmp	recv_cmd
1098
1099
1100