1 /* $NetBSD: aica_arm.c,v 1.9 2024/02/07 04:20:27 msaitoh Exp $ */
2
3 /*
4 * Copyright (c) 2003 Ryo Shimizu
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 typedef unsigned char uint8_t;
30 typedef unsigned short uint16_t;
31 typedef unsigned long uint32_t;
32
33 #include <arch/dreamcast/dev/g2/aicavar.h>
34
35 #define DC_REG_ADDR 0x00800000
36
37 #define REG_READ_1(off) \
38 (*(volatile uint8_t *)(DC_REG_ADDR + (off)))
39 #define REG_READ_2(off) \
40 (*(volatile uint16_t *)(DC_REG_ADDR + (off)))
41 #define REG_READ_4(off) \
42 (*(volatile uint32_t *)(DC_REG_ADDR + (off)))
43 #define REG_WRITE_1(off,val) \
44 ((*(volatile uint8_t *)(DC_REG_ADDR + (off))) = (val))
45 #define REG_WRITE_2(off,val) \
46 ((*(volatile uint16_t *)(DC_REG_ADDR + (off))) = (val))
47 #define REG_WRITE_4(off,val) \
48 ((*(volatile uint32_t *)((DC_REG_ADDR)+(off))) = (val))
49
50 #define CH_READ_1(ch,off) REG_READ_1(((ch) << 7) + (off))
51 #define CH_READ_2(ch,off) REG_READ_2(((ch) << 7) + (off))
52 #define CH_READ_4(ch,off) REG_READ_4(((ch) << 7) + (off))
53 #define CH_WRITE_1(ch,off,val) REG_WRITE_1(((ch) << 7) + (off), val)
54 #define CH_WRITE_2(ch,off,val) REG_WRITE_2(((ch) << 7) + (off), val)
55 #define CH_WRITE_4(ch,off,val) REG_WRITE_4(((ch) << 7) + (off), val)
56
57 void *memset(void *, int, unsigned long);
58
59 void aica_init(void);
60 inline int in_first_half(unsigned int);
61 inline int in_second_half(unsigned int);
62 uint32_t rate2reg(unsigned int);
63 void aica_stop(void);
64 void aica_main(void);
65
66 void
aica_init(void)67 aica_init(void)
68 {
69 int ch, off;
70
71 /* Initialize AICA channels */
72 REG_WRITE_4(0x2800, 0x0000); /* Master volume: Min */
73
74 for (ch = 0; ch < 64; ch++) {
75 CH_WRITE_4(ch, 0x00, 0x8000); /* Key off */
76 CH_WRITE_4(ch, 0x04, 0x0000); /* DataAddress (low) */
77 CH_WRITE_4(ch, 0x08, 0x0000); /* LoopStartPosition */
78 CH_WRITE_4(ch, 0x0c, 0x0000); /* LoopEndPosition */
79 CH_WRITE_4(ch, 0x10, 0x001f); /* AR = 0x1f = 0 msec */
80 CH_WRITE_4(ch, 0x14, 0x001f); /* RR = 0x1f = 0 msec */
81 CH_WRITE_4(ch, 0x18, 0x0000); /* Pitch */
82 CH_WRITE_4(ch, 0x1c, 0x0000); /* LFO Control */
83 CH_WRITE_4(ch, 0x20, 0x0000); /* DSP Channel to send */
84 CH_WRITE_4(ch, 0x24, 0x0000); /* Pan & Volume */
85 CH_WRITE_4(ch, 0x28, 0x0024); /* Volume & LowPassFilter */
86 CH_WRITE_4(ch, 0x2c, 0x0000); /* LowPassFilter for Attack */
87 CH_WRITE_4(ch, 0x30, 0x0000); /* LowPassFilter for Decay */
88 CH_WRITE_4(ch, 0x34, 0x0000); /* LowPassFilter for Sustain */
89 CH_WRITE_4(ch, 0x38, 0x0000); /* LowPassFilter for Keyoff */
90 CH_WRITE_4(ch, 0x3c, 0x0000); /* LowPassFilter for Release */
91 CH_WRITE_4(ch, 0x40, 0x0000); /* LowPassFilter transition
92 for Attack, Decay */
93 CH_WRITE_4(ch, 0x44, 0x0000); /* LowPassFilter transition
94 for Decay, Release */
95
96 for (off = 0x48; off < 0x80; off+=4) {
97 CH_WRITE_4(ch, off, 0x0000); /* other = 0 */
98 }
99 }
100
101 REG_WRITE_4(0x2800, 0x000f); /* Master volume: Max */
102 }
103
104
105 inline int
in_first_half(unsigned int loophalf)106 in_first_half(unsigned int loophalf)
107 {
108
109 REG_WRITE_1(0x280d, 0); /* select channel 0 */
110 return REG_READ_4(0x2814) < loophalf;
111 }
112
113 inline int
in_second_half(unsigned int loophalf)114 in_second_half(unsigned int loophalf)
115 {
116
117 REG_WRITE_1(0x280d, 0); /* select channel 0 */
118 return REG_READ_4(0x2814) >= loophalf;
119 }
120
121 uint32_t
rate2reg(unsigned int rate)122 rate2reg(unsigned int rate)
123 {
124 uint32_t base, fns;
125 int oct;
126
127 base = 44100 << 7;
128 for (oct = 7; oct >= -8 && rate < base; oct--)
129 base >>= 1;
130
131 if (rate < base)
132 return (oct << 11) & 0xf800;
133
134 rate -= base;
135
136 #if 0
137 /* (base / 2) : round off */
138 fns = (rate * 1024 + (base / 2)) / base;
139 #else
140 /* avoid using udivsi3() */
141 {
142 uint32_t tmp = (rate * 1024 + (base / 2));
143 for (fns = 0; tmp >= base; tmp -= base, fns++)
144 ;
145 }
146 #endif
147
148 /* adjustment */
149 if (fns == 1024) {
150 oct++;
151 fns = 0;
152 } else {
153 if ((rate > base * fns / 1024) &&
154 (fns < 1023) &&
155 (rate == base * (fns + 1) / 1024)) {
156 fns++;
157 } else if ((rate < base * fns / 1024) &&
158 (fns > 0) &&
159 (rate == base * (fns - 1)/ 1024)) {
160 fns--;
161 }
162 }
163
164 return ((oct << 11) & 0xf800) + fns;
165 }
166
167
168
169 void
aica_stop(void)170 aica_stop(void)
171 {
172
173 CH_WRITE_4(0, 0x00, 0x8000);
174 CH_WRITE_4(1, 0x00, 0x8000);
175 memset((void *)AICA_DMABUF_LEFT, 0, AICA_DMABUF_SIZE);
176 memset((void *)AICA_DMABUF_RIGHT, 0, AICA_DMABUF_SIZE);
177 }
178
179 void
aica_main(void)180 aica_main(void)
181 {
182 volatile aica_cmd_t *aicacmd = (volatile aica_cmd_t *)AICA_ARM_CMD;
183 int play_state;
184 unsigned int loopend = 0,loophalf = 0;
185 unsigned int blksize = 0, ratepitch;
186 uint32_t cmd, serial;
187
188 aica_init();
189
190 REG_WRITE_4(0x28b4, 0x0020); /* INT Enable to SH4 */
191
192 memset((void *)AICA_DMABUF_LEFT, 0, AICA_DMABUF_SIZE);
193 memset((void *)AICA_DMABUF_RIGHT, 0, AICA_DMABUF_SIZE);
194
195 play_state = 0;
196 serial = aicacmd->serial = 0;
197
198 for (;;) {
199 if (serial != aicacmd->serial) {
200 serial = aicacmd->serial;
201 cmd = aicacmd->command;
202 aicacmd->command = AICA_COMMAND_NOP;
203 } else {
204 cmd = AICA_COMMAND_NOP;
205 }
206
207 switch (cmd) {
208 case AICA_COMMAND_NOP:
209 /*
210 * AICA_COMMAND_NOP - Idle process
211 */
212 switch (play_state) {
213 case 0: /* not playing */
214 break;
215 case 1: /* first half */
216 if (in_second_half(loophalf)) {
217 /* Send INT to SH4 */
218 REG_WRITE_4(0x28b8, 0x0020);
219 play_state = 2;
220 }
221 break;
222 case 2: /* second half */
223 if (in_first_half(loophalf)) {
224 /* Send INT to SH4 */
225 REG_WRITE_4(0x28b8, 0x0020);
226 play_state = 1;
227 }
228 break;
229 case 3:
230 if (in_second_half(loophalf)) {
231 aica_stop();
232 play_state = 0;
233 }
234 break;
235 case 4:
236 if (in_first_half(loophalf)) {
237 aica_stop();
238 play_state = 0;
239 }
240 break;
241 }
242 break;
243
244 case AICA_COMMAND_PLAY:
245 aica_stop();
246 play_state = 0;
247
248 blksize = aicacmd->blocksize;
249
250 REG_WRITE_4(0x28b4, 0x0020); /* INT Enable to SH4 */
251
252 CH_WRITE_4(0, 0x00, 0x8000);
253 CH_WRITE_4(1, 0x00, 0x8000);
254
255 switch (aicacmd->precision) {
256 case 16:
257 loopend = blksize;
258 break;
259 case 8:
260 loopend = blksize * 2;
261 break;
262 case 4:
263 loopend = blksize * 4;
264 break;
265 }
266 loophalf = loopend / 2;
267
268 ratepitch = rate2reg(aicacmd->rate);
269
270 /* setup left */
271 CH_WRITE_4(0, 0x08, 0); /* loop start */
272 CH_WRITE_4(0, 0x0c, loopend); /* loop end */
273 CH_WRITE_4(0, 0x18, ratepitch); /* SamplingRate */
274 CH_WRITE_4(0, 0x24, 0x0f1f); /* volume MAX,
275 right PAN */
276
277 /* setup right */
278 CH_WRITE_4(1, 0x08,0); /* loop start */
279 CH_WRITE_4(1, 0x0c, loopend); /* loop end */
280 CH_WRITE_4(1, 0x18, ratepitch); /* SamplingRate */
281 CH_WRITE_4(1, 0x24, 0x0f0f); /* volume MAX,
282 right PAN */
283
284 {
285 uint32_t mode, lparam, rparam;
286
287 if (aicacmd->precision == 4)
288 mode = 3 << 7; /* 4bit ADPCM */
289 else if (aicacmd->precision == 8)
290 mode = 1 << 7; /* 8bit */
291 else
292 mode = 0; /* 16bit */
293
294 switch (aicacmd->channel) {
295 case 2:
296 CH_WRITE_4(0, 0x04,
297 AICA_DMABUF_LEFT & 0xffff);
298 CH_WRITE_4(1, 0x04,
299 AICA_DMABUF_RIGHT & 0xffff);
300 lparam = 0xc000 /*PLAY*/ |
301 0x0200 /*LOOP*/ | mode |
302 (AICA_DMABUF_LEFT >> 16);
303 rparam = 0xc000 /*PLAY*/ |
304 0x0200 /*LOOP*/ | mode |
305 (AICA_DMABUF_RIGHT >> 16);
306 CH_WRITE_4(0, 0x00, lparam);
307 CH_WRITE_4(1, 0x00, rparam);
308 break;
309 case 1:
310 CH_WRITE_1(0, 0x24, 0); /* middle
311 balance */
312 CH_WRITE_4(0, 0x04,
313 AICA_DMABUF_LEFT & 0xffff);
314 CH_WRITE_4(0, 0x00, 0xc000 /*PLAY*/ |
315 0x0200 /*LOOP*/ | mode |
316 (AICA_DMABUF_LEFT >> 16));
317 break;
318 }
319 }
320 play_state = 1;
321 break;
322
323 case AICA_COMMAND_STOP:
324 switch (play_state) {
325 case 1:
326 memset((void *)(AICA_DMABUF_LEFT + blksize), 0,
327 blksize);
328 memset((void *)(AICA_DMABUF_RIGHT + blksize), 0,
329 blksize);
330 play_state = 3;
331 break;
332 case 2:
333 memset((void *)AICA_DMABUF_LEFT, 0, blksize);
334 memset((void *)AICA_DMABUF_RIGHT, 0, blksize);
335 play_state = 4;
336 break;
337 default:
338 aica_stop();
339 play_state = 0;
340 break;
341 }
342 break;
343
344 case AICA_COMMAND_INIT:
345 aica_stop();
346 play_state = 0;
347 break;
348
349 case AICA_COMMAND_MVOL:
350 REG_WRITE_4(0x2800, L256TO16(aicacmd->l_param));
351 break;
352
353 case AICA_COMMAND_VOL:
354 CH_WRITE_1(0, 0x29, 0xff - (aicacmd->l_param & 0xff));
355 CH_WRITE_1(1, 0x29, 0xff - (aicacmd->r_param & 0xff));
356 break;
357
358 }
359 }
360 }
361