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