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