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