emulate pending irq bit somewhat
[pcsx_rearmed.git] / plugins / dfsound / registers.c
CommitLineData
ef79bbde
P
1/***************************************************************************\r
2 registers.c - description\r
3 -------------------\r
4 begin : Wed May 15 2002\r
5 copyright : (C) 2002 by Pete Bernert\r
6 email : BlackDove@addcom.de\r
7 ***************************************************************************/\r
8/***************************************************************************\r
9 * *\r
10 * This program is free software; you can redistribute it and/or modify *\r
11 * it under the terms of the GNU General Public License as published by *\r
12 * the Free Software Foundation; either version 2 of the License, or *\r
13 * (at your option) any later version. See also the license.txt file for *\r
14 * additional informations. *\r
15 * *\r
16 ***************************************************************************/\r
17\r
18#include "stdafx.h"\r
19\r
20#define _IN_REGISTERS\r
21\r
22#include "externals.h"\r
23#include "registers.h"\r
3154bfab 24#include "spu_config.h"\r
a4621d43 25#include "spu.h"\r
ef79bbde 26\r
7e44d49d 27static void SoundOn(int start,int end,unsigned short val);\r
28static void SoundOff(int start,int end,unsigned short val);\r
29static void FModOn(int start,int end,unsigned short val);\r
30static void NoiseOn(int start,int end,unsigned short val);\r
31static void SetVolumeL(unsigned char ch,short vol);\r
32static void SetVolumeR(unsigned char ch,short vol);\r
33static void SetPitch(int ch,unsigned short val);\r
34static void ReverbOn(int start,int end,unsigned short val);\r
35\r
ef79bbde
P
36////////////////////////////////////////////////////////////////////////\r
37// WRITE REGISTERS: called by main emu\r
38////////////////////////////////////////////////////////////////////////\r
39\r
650adfd2 40static const uint32_t ignore_dupe[8] = {\r
41 // ch 0-15 c40 c80 cc0\r
42 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,\r
43 // ch 16-24 d40 control reverb\r
44 0x7f7f7f7f, 0x7f7f7f7f, 0xff05ff0f, 0xffffffff\r
45};\r
46\r
47void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,\r
48 unsigned int cycles)\r
ef79bbde 49{\r
650adfd2 50 int r = reg & 0xfff;\r
51 int rofs = (r - 0xc00) >> 1;\r
3154bfab 52 int changed = spu.regArea[rofs] != val;\r
53 spu.regArea[rofs] = val;\r
650adfd2 54\r
55 if (!changed && (ignore_dupe[rofs >> 5] & (1 << (rofs & 0x1f))))\r
56 return;\r
57 // zero keyon/keyoff?\r
58 if (val == 0 && (r & 0xff8) == 0xd88)\r
59 return;\r
60\r
63a4f6b6 61 do_samples_if_needed(cycles, 0);\r
ef79bbde
P
62\r
63 if(r>=0x0c00 && r<0x0d80) // some channel info?\r
64 {\r
65 int ch=(r>>4)-0xc0; // calc channel\r
66 switch(r&0x0f)\r
67 {\r
68 //------------------------------------------------// r volume\r
69 case 0: \r
70 SetVolumeL((unsigned char)ch,val);\r
71 break;\r
72 //------------------------------------------------// l volume\r
73 case 2: \r
74 SetVolumeR((unsigned char)ch,val);\r
75 break;\r
76 //------------------------------------------------// pitch\r
77 case 4: \r
78 SetPitch(ch,val);\r
650adfd2 79 goto upd_irq;\r
ef79bbde
P
80 //------------------------------------------------// start\r
81 case 6: \r
7e44d49d 82 // taken from regArea later\r
ef79bbde
P
83 break;\r
84 //------------------------------------------------// level with pre-calcs\r
85 case 8:\r
86 {\r
6d866bb7 87 const unsigned long lval=val;\r
ef79bbde 88 //---------------------------------------------//\r
5514a050 89 spu.s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0;\r
90 spu.s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;\r
91 spu.s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;\r
92 spu.s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;\r
ef79bbde 93 //---------------------------------------------//\r
ef79bbde
P
94 }\r
95 break;\r
96 //------------------------------------------------// adsr times with pre-calcs\r
97 case 10:\r
98 {\r
6d866bb7 99 const unsigned long lval=val;\r
ef79bbde
P
100\r
101 //----------------------------------------------//\r
5514a050 102 spu.s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;\r
103 spu.s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;\r
104 spu.s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;\r
105 spu.s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;\r
106 spu.s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;\r
ef79bbde 107 //----------------------------------------------//\r
ef79bbde
P
108 }\r
109 break;\r
110 //------------------------------------------------// adsr volume... mmm have to investigate this\r
111 case 12:\r
112 break;\r
113 //------------------------------------------------//\r
114 case 14: // loop?\r
5514a050 115 spu.s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3);\r
16f3ca66 116 spu.s_chan[ch].bIgnoreLoop = 1;\r
650adfd2 117 goto upd_irq;\r
ef79bbde
P
118 //------------------------------------------------//\r
119 }\r
ef79bbde
P
120 return;\r
121 }\r
122\r
123 switch(r)\r
124 {\r
125 //-------------------------------------------------//\r
126 case H_SPUaddr:\r
3154bfab 127 spu.spuAddr = (unsigned long) val<<3;\r
ef79bbde
P
128 break;\r
129 //-------------------------------------------------//\r
130 case H_SPUdata:\r
a4621d43 131 *(unsigned short *)(spu.spuMemC + spu.spuAddr) = HTOLE16(val);\r
5514a050 132 spu.spuAddr += 2;\r
133 spu.spuAddr &= 0x7fffe;\r
ef79bbde
P
134 break;\r
135 //-------------------------------------------------//\r
136 case H_SPUctrl:\r
3154bfab 137 if (!(spu.spuCtrl & CTRL_IRQ)) {\r
138 spu.spuStat&=~STAT_IRQ;\r
650adfd2 139 if (val & CTRL_IRQ)\r
140 schedule_next_irq();\r
141 }\r
3154bfab 142 spu.spuCtrl=val;\r
ef79bbde
P
143 break;\r
144 //-------------------------------------------------//\r
145 case H_SPUstat:\r
3154bfab 146 spu.spuStat=val&0xf800;\r
ef79bbde
P
147 break;\r
148 //-------------------------------------------------//\r
149 case H_SPUReverbAddr:\r
650adfd2 150 goto rvbd;\r
ef79bbde
P
151 //-------------------------------------------------//\r
152 case H_SPUirqAddr:\r
a5ff8be2 153 //if (val & 1)\r
154 // log_unhandled("w irq with lsb: %08lx %04x\n", reg, val);\r
3154bfab 155 spu.pSpuIrq=spu.spuMemC+(((unsigned long) val<<3)&~0xf);\r
650adfd2 156 goto upd_irq;\r
ef79bbde
P
157 //-------------------------------------------------//\r
158 case H_SPUrvolL:\r
05c7cec7 159 spu.rvb->VolLeft=val;\r
ef79bbde
P
160 break;\r
161 //-------------------------------------------------//\r
162 case H_SPUrvolR:\r
05c7cec7 163 spu.rvb->VolRight=val;\r
ef79bbde
P
164 break;\r
165 //-------------------------------------------------//\r
166\r
6c9db47c 167 case H_SPUmvolL:\r
168 case H_SPUmvolR:\r
169 if (val & 0x8000)\r
170 log_unhandled("w master sweep: %08lx %04x\n", reg, val);\r
171 break;\r
172\r
173 case 0x0dac:\r
174 if (val != 4)\r
175 log_unhandled("1f801dac %04x\n", val);\r
176 break;\r
177\r
ef79bbde
P
178/*\r
179 case H_ExtLeft:\r
180 //auxprintf("EL %d\n",val);\r
181 break;\r
182 //-------------------------------------------------//\r
183 case H_ExtRight:\r
184 //auxprintf("ER %d\n",val);\r
185 break;\r
186 //-------------------------------------------------//\r
187 case H_SPUmvolL:\r
188 //auxprintf("ML %d\n",val);\r
189 break;\r
190 //-------------------------------------------------//\r
191 case H_SPUmvolR:\r
192 //auxprintf("MR %d\n",val);\r
193 break;\r
194 //-------------------------------------------------//\r
195 case H_SPUMute1:\r
196 //auxprintf("M0 %04x\n",val);\r
197 break;\r
198 //-------------------------------------------------//\r
199 case H_SPUMute2:\r
200 //auxprintf("M1 %04x\n",val);\r
201 break;\r
202*/\r
203 //-------------------------------------------------//\r
204 case H_SPUon1:\r
205 SoundOn(0,16,val);\r
206 break;\r
207 //-------------------------------------------------//\r
208 case H_SPUon2:\r
209 SoundOn(16,24,val);\r
210 break;\r
211 //-------------------------------------------------//\r
212 case H_SPUoff1:\r
213 SoundOff(0,16,val);\r
214 break;\r
215 //-------------------------------------------------//\r
216 case H_SPUoff2:\r
217 SoundOff(16,24,val);\r
218 break;\r
219 //-------------------------------------------------//\r
220 case H_CDLeft:\r
b64fb891 221 spu.iLeftXAVol=(int16_t)val;\r
222 if(spu.cddavCallback) spu.cddavCallback(0,(int16_t)val);\r
ef79bbde
P
223 break;\r
224 case H_CDRight:\r
b64fb891 225 spu.iRightXAVol=(int16_t)val;\r
226 if(spu.cddavCallback) spu.cddavCallback(1,(int16_t)val);\r
ef79bbde
P
227 break;\r
228 //-------------------------------------------------//\r
229 case H_FMod1:\r
230 FModOn(0,16,val);\r
231 break;\r
232 //-------------------------------------------------//\r
233 case H_FMod2:\r
234 FModOn(16,24,val);\r
235 break;\r
236 //-------------------------------------------------//\r
237 case H_Noise1:\r
238 NoiseOn(0,16,val);\r
239 break;\r
240 //-------------------------------------------------//\r
241 case H_Noise2:\r
242 NoiseOn(16,24,val);\r
243 break;\r
244 //-------------------------------------------------//\r
245 case H_RVBon1:\r
246 ReverbOn(0,16,val);\r
247 break;\r
248 //-------------------------------------------------//\r
249 case H_RVBon2:\r
250 ReverbOn(16,24,val);\r
251 break;\r
252 //-------------------------------------------------//\r
7b2c4897 253 case H_Reverb+0 : goto rvbd;\r
254 case H_Reverb+2 : goto rvbd;\r
255 case H_Reverb+4 : spu.rvb->IIR_ALPHA=(short)val; break;\r
256 case H_Reverb+6 : spu.rvb->ACC_COEF_A=(short)val; break;\r
257 case H_Reverb+8 : spu.rvb->ACC_COEF_B=(short)val; break;\r
258 case H_Reverb+10 : spu.rvb->ACC_COEF_C=(short)val; break;\r
259 case H_Reverb+12 : spu.rvb->ACC_COEF_D=(short)val; break;\r
260 case H_Reverb+14 : spu.rvb->IIR_COEF=(short)val; break;\r
261 case H_Reverb+16 : spu.rvb->FB_ALPHA=(short)val; break;\r
262 case H_Reverb+18 : spu.rvb->FB_X=(short)val; break;\r
263 case H_Reverb+20 : goto rvbd;\r
264 case H_Reverb+22 : goto rvbd;\r
265 case H_Reverb+24 : goto rvbd;\r
266 case H_Reverb+26 : goto rvbd;\r
267 case H_Reverb+28 : goto rvbd;\r
268 case H_Reverb+30 : goto rvbd;\r
269 case H_Reverb+32 : goto rvbd;\r
270 case H_Reverb+34 : goto rvbd;\r
271 case H_Reverb+36 : goto rvbd;\r
272 case H_Reverb+38 : goto rvbd;\r
273 case H_Reverb+40 : goto rvbd;\r
274 case H_Reverb+42 : goto rvbd;\r
275 case H_Reverb+44 : goto rvbd;\r
276 case H_Reverb+46 : goto rvbd;\r
277 case H_Reverb+48 : goto rvbd;\r
278 case H_Reverb+50 : goto rvbd;\r
279 case H_Reverb+52 : goto rvbd;\r
280 case H_Reverb+54 : goto rvbd;\r
281 case H_Reverb+56 : goto rvbd;\r
282 case H_Reverb+58 : goto rvbd;\r
283 case H_Reverb+60 : spu.rvb->IN_COEF_L=(short)val; break;\r
284 case H_Reverb+62 : spu.rvb->IN_COEF_R=(short)val; break;\r
ef79bbde 285 }\r
650adfd2 286 return;\r
287\r
288upd_irq:\r
3154bfab 289 if (spu.spuCtrl & CTRL_IRQ)\r
650adfd2 290 schedule_next_irq();\r
291 return;\r
ef79bbde 292\r
650adfd2 293rvbd:\r
05c7cec7 294 spu.rvb->dirty = 1; // recalculate on next update\r
ef79bbde
P
295}\r
296\r
297////////////////////////////////////////////////////////////////////////\r
298// READ REGISTER: called by main emu\r
299////////////////////////////////////////////////////////////////////////\r
300\r
301unsigned short CALLBACK SPUreadRegister(unsigned long reg)\r
302{\r
303 const unsigned long r=reg&0xfff;\r
304 \r
ef79bbde
P
305 if(r>=0x0c00 && r<0x0d80)\r
306 {\r
307 switch(r&0x0f)\r
308 {\r
309 case 12: // get adsr vol\r
310 {\r
311 const int ch=(r>>4)-0xc0;\r
3154bfab 312 if(spu.dwNewChannel&(1<<ch)) return 1; // we are started, but not processed? return 1\r
5aa94fa0 313 if((spu.dwChannelsAudible&(1<<ch)) && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well\r
5514a050 314 !spu.s_chan[ch].ADSRX.EnvelopeVol)\r
ef79bbde 315 return 1;\r
5514a050 316 return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol>>16);\r
ef79bbde
P
317 }\r
318\r
319 case 14: // get loop address\r
320 {\r
321 const int ch=(r>>4)-0xc0;\r
5514a050 322 return (unsigned short)((spu.s_chan[ch].pLoop-spu.spuMemC)>>3);\r
ef79bbde
P
323 }\r
324 }\r
325 }\r
326\r
327 switch(r)\r
328 {\r
329 case H_SPUctrl:\r
3154bfab 330 return spu.spuCtrl;\r
ef79bbde
P
331\r
332 case H_SPUstat:\r
d056f51b 333 return (spu.spuStat & ~0x3F) | (spu.spuCtrl & 0x3F);\r
ef79bbde
P
334 \r
335 case H_SPUaddr:\r
3154bfab 336 return (unsigned short)(spu.spuAddr>>3);\r
ef79bbde
P
337\r
338 case H_SPUdata:\r
339 {\r
a4621d43 340 unsigned short s = LE16TOH(*(unsigned short *)(spu.spuMemC + spu.spuAddr));\r
5514a050 341 spu.spuAddr += 2;\r
342 spu.spuAddr &= 0x7fffe;\r
ef79bbde
P
343 return s;\r
344 }\r
345\r
ef79bbde
P
346 //case H_SPUIsOn1:\r
347 // return IsSoundOn(0,16);\r
348\r
349 //case H_SPUIsOn2:\r
350 // return IsSoundOn(16,24);\r
351 \r
6c9db47c 352 case H_SPUMute1:\r
353 case H_SPUMute2:\r
354 log_unhandled("r isOn: %08lx\n", reg);\r
355 break;\r
ef79bbde
P
356 }\r
357\r
3154bfab 358 return spu.regArea[(r-0xc00)>>1];\r
ef79bbde
P
359}\r
360 \r
361////////////////////////////////////////////////////////////////////////\r
362// SOUND ON register write\r
363////////////////////////////////////////////////////////////////////////\r
364\r
7e44d49d 365static void SoundOn(int start,int end,unsigned short val)\r
ef79bbde
P
366{\r
367 int ch;\r
368\r
369 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
370 {\r
5fdcf5cd 371 if((val&1) && regAreaGetCh(ch, 6)) // mmm... start has to be set before key on !?!\r
ef79bbde 372 {\r
16f3ca66 373 spu.s_chan[ch].bIgnoreLoop = 0;\r
3154bfab 374 spu.dwNewChannel|=(1<<ch);\r
ef79bbde
P
375 }\r
376 }\r
377}\r
378\r
379////////////////////////////////////////////////////////////////////////\r
380// SOUND OFF register write\r
381////////////////////////////////////////////////////////////////////////\r
382\r
7e44d49d 383static void SoundOff(int start,int end,unsigned short val)\r
ef79bbde
P
384{\r
385 int ch;\r
386 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
387 {\r
9ad8abfa 388 if(val&1)\r
ef79bbde 389 {\r
5514a050 390 spu.s_chan[ch].ADSRX.State = ADSR_RELEASE;\r
b00afb77 391\r
392 // Jungle Book - Rhythm 'n Groove\r
393 // - turns off buzzing sound (loop hangs)\r
3154bfab 394 spu.dwNewChannel &= ~(1<<ch);\r
ef79bbde
P
395 } \r
396 }\r
397}\r
398\r
399////////////////////////////////////////////////////////////////////////\r
400// FMOD register write\r
401////////////////////////////////////////////////////////////////////////\r
402\r
7e44d49d 403static void FModOn(int start,int end,unsigned short val)\r
ef79bbde
P
404{\r
405 int ch;\r
406\r
407 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
408 {\r
409 if(val&1) // -> fmod on/off\r
410 {\r
411 if(ch>0) \r
412 {\r
5514a050 413 spu.s_chan[ch].bFMod=1; // --> sound channel\r
414 spu.s_chan[ch-1].bFMod=2; // --> freq channel\r
ef79bbde
P
415 }\r
416 }\r
417 else\r
418 {\r
5514a050 419 spu.s_chan[ch].bFMod=0; // --> turn off fmod\r
420 if(ch>0&&spu.s_chan[ch-1].bFMod==2)\r
421 spu.s_chan[ch-1].bFMod=0;\r
ef79bbde
P
422 }\r
423 }\r
424}\r
425\r
426////////////////////////////////////////////////////////////////////////\r
427// NOISE register write\r
428////////////////////////////////////////////////////////////////////////\r
429\r
7e44d49d 430static void NoiseOn(int start,int end,unsigned short val)\r
ef79bbde
P
431{\r
432 int ch;\r
433\r
434 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
435 {\r
5514a050 436 spu.s_chan[ch].bNoise=val&1; // -> noise on/off\r
ef79bbde
P
437 }\r
438}\r
439\r
440////////////////////////////////////////////////////////////////////////\r
441// LEFT VOLUME register write\r
442////////////////////////////////////////////////////////////////////////\r
443\r
444// please note: sweep and phase invert are wrong... but I've never seen\r
445// them used\r
446\r
7e44d49d 447static void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME\r
ef79bbde 448{\r
ef79bbde
P
449 if(vol&0x8000) // sweep?\r
450 {\r
451 short sInc=1; // -> sweep up?\r
6c9db47c 452 log_unhandled("ch%d sweepl %04x\n", ch, vol);\r
ef79bbde
P
453 if(vol&0x2000) sInc=-1; // -> or down?\r
454 if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this\r
455 vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64\r
456 vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!\r
457 vol*=128;\r
458 }\r
459 else // no sweep:\r
460 {\r
461 if(vol&0x4000) // -> mmm... phase inverted? have to investigate this\r
462 //vol^=0xffff;\r
463 vol=0x3fff-(vol&0x3fff);\r
464 }\r
465\r
466 vol&=0x3fff;\r
5514a050 467 spu.s_chan[ch].iLeftVolume=vol; // store volume\r
ef79bbde
P
468}\r
469\r
470////////////////////////////////////////////////////////////////////////\r
471// RIGHT VOLUME register write\r
472////////////////////////////////////////////////////////////////////////\r
473\r
7e44d49d 474static void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME\r
ef79bbde 475{\r
ef79bbde
P
476 if(vol&0x8000) // comments... see above :)\r
477 {\r
478 short sInc=1;\r
6c9db47c 479 log_unhandled("ch%d sweepr %04x\n", ch, vol);\r
ef79bbde
P
480 if(vol&0x2000) sInc=-1;\r
481 if(vol&0x1000) vol^=0xffff;\r
482 vol=((vol&0x7f)+1)/2; \r
483 vol+=vol/(2*sInc);\r
484 vol*=128;\r
485 }\r
486 else \r
487 {\r
488 if(vol&0x4000) //vol=vol^=0xffff;\r
489 vol=0x3fff-(vol&0x3fff);\r
490 }\r
491\r
492 vol&=0x3fff;\r
493\r
5514a050 494 spu.s_chan[ch].iRightVolume=vol;\r
ef79bbde
P
495}\r
496\r
497////////////////////////////////////////////////////////////////////////\r
498// PITCH register write\r
499////////////////////////////////////////////////////////////////////////\r
500\r
7e44d49d 501static void SetPitch(int ch,unsigned short val) // SET PITCH\r
ef79bbde
P
502{\r
503 int NP;\r
504 if(val>0x3fff) NP=0x3fff; // get pitch val\r
505 else NP=val;\r
506\r
f3fa20c2 507 spu.s_chan[ch].iRawPitch = NP;\r
508 spu.s_chan[ch].sinc = NP << 4;\r
509 spu.s_chan[ch].sinc_inv = 0;\r
53d4b74d 510 spu.s_chan[ch].bNewPitch = 1;\r
1d5d35bc 511\r
512 // don't mess spu.dwChannelsAudible as adsr runs independently\r
ef79bbde
P
513}\r
514\r
515////////////////////////////////////////////////////////////////////////\r
516// REVERB register write\r
517////////////////////////////////////////////////////////////////////////\r
518\r
7e44d49d 519static void ReverbOn(int start,int end,unsigned short val)\r
ef79bbde
P
520{\r
521 int ch;\r
522\r
523 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
524 {\r
5514a050 525 spu.s_chan[ch].bReverb=val&1; // -> reverb on/off\r
ef79bbde
P
526 }\r
527}\r