reduce some code duplication
[pcsx_rearmed.git] / libpcsxcore / psxhw.c
1 /***************************************************************************
2  *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
18  ***************************************************************************/
19
20 /*
21 * Functions for PSX hardware control.
22 */
23
24 #include "psxhw.h"
25 #include "mdec.h"
26 #include "cdrom.h"
27 #include "gpu.h"
28
29 //#undef PSXHW_LOG
30 //#define PSXHW_LOG printf
31 #ifndef PAD_LOG
32 #define PAD_LOG(...)
33 #endif
34
35 void psxHwReset() {
36         memset(psxH, 0, 0x10000);
37
38         mdecInit(); // initialize mdec decoder
39         cdrReset();
40         psxRcntInit();
41         HW_GPU_STATUS = SWAP32(0x14802000);
42 }
43
44 void psxHwWriteIstat(u32 value)
45 {
46         u32 stat = psxHu16(0x1070) & SWAPu16(value);
47         psxHu16ref(0x1070) = SWAPu16(stat);
48
49         psxRegs.CP0.n.Cause &= ~0x400;
50         if (stat & psxHu16(0x1074))
51                 psxRegs.CP0.n.Cause |= 0x400;
52 }
53
54 void psxHwWriteImask(u32 value)
55 {
56         u32 stat = psxHu16(0x1070);
57         psxHu16ref(0x1074) = SWAPu16(value);
58         if (stat & SWAPu16(value)) {
59                 //if ((psxRegs.CP0.n.SR & 0x401) == 0x401)
60                 //      log_unhandled("irq on unmask @%08x\n", psxRegs.pc);
61                 new_dyna_set_event(PSXINT_NEWDRC_CHECK, 1);
62         }
63         psxRegs.CP0.n.Cause &= ~0x400;
64         if (stat & value)
65                 psxRegs.CP0.n.Cause |= 0x400;
66 }
67
68 void psxHwWriteDmaIcr32(u32 value)
69 {
70         u32 tmp = value & 0x00ff803f;
71         tmp |= (SWAPu32(HW_DMA_ICR) & ~value) & 0x7f000000;
72         if ((tmp & HW_DMA_ICR_GLOBAL_ENABLE && tmp & 0x7f000000)
73             || tmp & HW_DMA_ICR_BUS_ERROR) {
74                 if (!(SWAPu32(HW_DMA_ICR) & HW_DMA_ICR_IRQ_SENT))
75                         psxHu32ref(0x1070) |= SWAP32(8);
76                 tmp |= HW_DMA_ICR_IRQ_SENT;
77         }
78         HW_DMA_ICR = SWAPu32(tmp);
79 }
80
81 u8 psxHwRead8(u32 add) {
82         unsigned char hard;
83
84         switch (add & 0x1fffffff) {
85                 case 0x1f801040: hard = sioRead8(); break;
86                 case 0x1f801800: hard = cdrRead0(); break;
87                 case 0x1f801801: hard = cdrRead1(); break;
88                 case 0x1f801802: hard = cdrRead2(); break;
89                 case 0x1f801803: hard = cdrRead3(); break;
90
91                 case 0x1f801041: case 0x1f801042: case 0x1f801043:
92                 case 0x1f801044: case 0x1f801045:
93                 case 0x1f801046: case 0x1f801047:
94                 case 0x1f801048: case 0x1f801049:
95                 case 0x1f80104a: case 0x1f80104b:
96                 case 0x1f80104c: case 0x1f80104d:
97                 case 0x1f80104e: case 0x1f80104f:
98                 case 0x1f801050: case 0x1f801051:
99                 case 0x1f801054: case 0x1f801055:
100                 case 0x1f801058: case 0x1f801059:
101                 case 0x1f80105a: case 0x1f80105b:
102                 case 0x1f80105c: case 0x1f80105d:
103                 case 0x1f801100: case 0x1f801101:
104                 case 0x1f801104: case 0x1f801105:
105                 case 0x1f801108: case 0x1f801109:
106                 case 0x1f801110: case 0x1f801111:
107                 case 0x1f801114: case 0x1f801115:
108                 case 0x1f801118: case 0x1f801119:
109                 case 0x1f801120: case 0x1f801121:
110                 case 0x1f801124: case 0x1f801125:
111                 case 0x1f801128: case 0x1f801129:
112                 case 0x1f801810: case 0x1f801811:
113                 case 0x1f801812: case 0x1f801813:
114                 case 0x1f801814: case 0x1f801815:
115                 case 0x1f801816: case 0x1f801817:
116                 case 0x1f801820: case 0x1f801821:
117                 case 0x1f801822: case 0x1f801823:
118                 case 0x1f801824: case 0x1f801825:
119                 case 0x1f801826: case 0x1f801827:
120                         log_unhandled("unhandled r8  %08x @%08x\n", add, psxRegs.pc);
121                         // falthrough
122                 default:
123                         if (0x1f801c00 <= add && add < 0x1f802000)
124                                 log_unhandled("spu r8 %02x @%08x\n", add, psxRegs.pc);
125                         hard = psxHu8(add); 
126 #ifdef PSXHW_LOG
127                         PSXHW_LOG("*Unkwnown 8bit read at address %x\n", add);
128 #endif
129                         return hard;
130         }
131
132 #ifdef PSXHW_LOG
133         PSXHW_LOG("*Known 8bit read at address %x value %x\n", add, hard);
134 #endif
135         return hard;
136 }
137
138 u16 psxHwRead16(u32 add) {
139         unsigned short hard;
140
141         switch (add & 0x1fffffff) {
142 #ifdef PSXHW_LOG
143                 case 0x1f801070: PSXHW_LOG("IREG 16bit read %x\n", psxHu16(0x1070));
144                         return psxHu16(0x1070);
145                 case 0x1f801074: PSXHW_LOG("IMASK 16bit read %x\n", psxHu16(0x1074));
146                         return psxHu16(0x1074);
147 #endif
148                 case 0x1f801040:
149                         hard = sioRead8();
150                         hard|= sioRead8() << 8;
151                         PAD_LOG("sio read16 %x; ret = %x\n", add&0xf, hard);
152                         return hard;
153                 case 0x1f801044:
154                         hard = sioReadStat16();
155                         PAD_LOG("sio read16 %x; ret = %x\n", add&0xf, hard);
156                         return hard;
157                 case 0x1f801048:
158                         hard = sioReadMode16();
159                         PAD_LOG("sio read16 %x; ret = %x\n", add&0xf, hard);
160                         return hard;
161                 case 0x1f80104a:
162                         hard = sioReadCtrl16();
163                         PAD_LOG("sio read16 %x; ret = %x\n", add&0xf, hard);
164                         return hard;
165                 case 0x1f80104e:
166                         hard = sioReadBaud16();
167                         PAD_LOG("sio read16 %x; ret = %x\n", add&0xf, hard);
168                         return hard;
169
170                 /* Fixes Armored Core misdetecting the Link cable being detected.
171                  * We want to turn that thing off and force it to do local multiplayer instead.
172                  * Thanks Sony for the fix, they fixed it in their PS Classic fork.
173                  */
174                 case 0x1f801054:
175                         return 0x80;\r
176
177                 case 0x1f801100:
178                         hard = psxRcntRcount(0);
179 #ifdef PSXHW_LOG
180                         PSXHW_LOG("T0 count read16: %x\n", hard);
181 #endif
182                         return hard;
183                 case 0x1f801104:
184                         hard = psxRcntRmode(0);
185 #ifdef PSXHW_LOG
186                         PSXHW_LOG("T0 mode read16: %x\n", hard);
187 #endif
188                         return hard;
189                 case 0x1f801108:
190                         hard = psxRcntRtarget(0);
191 #ifdef PSXHW_LOG
192                         PSXHW_LOG("T0 target read16: %x\n", hard);
193 #endif
194                         return hard;
195                 case 0x1f801110:
196                         hard = psxRcntRcount(1);
197 #ifdef PSXHW_LOG
198                         PSXHW_LOG("T1 count read16: %x\n", hard);
199 #endif
200                         return hard;
201                 case 0x1f801114:
202                         hard = psxRcntRmode(1);
203 #ifdef PSXHW_LOG
204                         PSXHW_LOG("T1 mode read16: %x\n", hard);
205 #endif
206                         return hard;
207                 case 0x1f801118:
208                         hard = psxRcntRtarget(1);
209 #ifdef PSXHW_LOG
210                         PSXHW_LOG("T1 target read16: %x\n", hard);
211 #endif
212                         return hard;
213                 case 0x1f801120:
214                         hard = psxRcntRcount(2);
215 #ifdef PSXHW_LOG
216                         PSXHW_LOG("T2 count read16: %x\n", hard);
217 #endif
218                         return hard;
219                 case 0x1f801124:
220                         hard = psxRcntRmode(2);
221 #ifdef PSXHW_LOG
222                         PSXHW_LOG("T2 mode read16: %x\n", hard);
223 #endif
224                         return hard;
225                 case 0x1f801128:
226                         hard = psxRcntRtarget(2);
227 #ifdef PSXHW_LOG
228                         PSXHW_LOG("T2 target read16: %x\n", hard);
229 #endif
230                         return hard;
231
232                 //case 0x1f802030: hard =   //int_2000????
233                 //case 0x1f802040: hard =//dip switches...??
234
235                 case 0x1f801042:
236                 case 0x1f801046:
237                 case 0x1f80104c:
238                 case 0x1f801050:
239                 case 0x1f801058:
240                 case 0x1f80105a:
241                 case 0x1f80105c:
242                 case 0x1f801800:
243                 case 0x1f801802:
244                 case 0x1f801810:
245                 case 0x1f801812:
246                 case 0x1f801814:
247                 case 0x1f801816:
248                 case 0x1f801820:
249                 case 0x1f801822:
250                 case 0x1f801824:
251                 case 0x1f801826:
252                         log_unhandled("unhandled r16 %08x @%08x\n", add, psxRegs.pc);
253                         // falthrough
254                 default:
255                         if (0x1f801c00 <= add && add < 0x1f802000)
256                                 return SPU_readRegister(add);
257                         hard = psxHu16(add);
258 #ifdef PSXHW_LOG
259                         PSXHW_LOG("*Unkwnown 16bit read at address %x\n", add);
260 #endif
261                         return hard;
262         }
263         
264 #ifdef PSXHW_LOG
265         PSXHW_LOG("*Known 16bit read at address %x value %x\n", add, hard);
266 #endif
267         return hard;
268 }
269
270 u32 psxHwRead32(u32 add) {
271         u32 hard;
272
273         switch (add & 0x1fffffff) {
274                 case 0x1f801040:
275                         hard = sioRead8();
276                         hard |= sioRead8() << 8;
277                         hard |= sioRead8() << 16;
278                         hard |= sioRead8() << 24;
279                         PAD_LOG("sio read32 ;ret = %x\n", hard);
280                         return hard;
281                 case 0x1f801044:
282                         hard = sioReadStat16();
283                         PAD_LOG("sio read32 %x; ret = %x\n", add&0xf, hard);
284                         return hard;
285 #ifdef PSXHW_LOG
286                 case 0x1f801060:
287                         PSXHW_LOG("RAM size read %x\n", psxHu32(0x1060));
288                         return psxHu32(0x1060);
289                 case 0x1f801070: PSXHW_LOG("IREG 32bit read %x\n", psxHu32(0x1070));
290                         return psxHu32(0x1070);
291                 case 0x1f801074: PSXHW_LOG("IMASK 32bit read %x\n", psxHu32(0x1074));
292                         return psxHu32(0x1074);
293 #endif
294
295                 case 0x1f801810:
296                         hard = GPU_readData();
297 #ifdef PSXHW_LOG
298                         PSXHW_LOG("GPU DATA 32bit read %x\n", hard);
299 #endif
300                         return hard;
301                 case 0x1f801814:
302                         gpuSyncPluginSR();
303                         hard = SWAP32(HW_GPU_STATUS);
304                         if (hSyncCount < 240 && (hard & PSXGPU_ILACE_BITS) != PSXGPU_ILACE_BITS)
305                                 hard |= PSXGPU_LCF & (psxRegs.cycle << 20);
306 #ifdef PSXHW_LOG
307                         PSXHW_LOG("GPU STATUS 32bit read %x\n", hard);
308 #endif
309                         return hard;
310
311                 case 0x1f801820: hard = mdecRead0(); break;
312                 case 0x1f801824: hard = mdecRead1(); break;
313
314 #ifdef PSXHW_LOG
315                 case 0x1f8010a0:
316                         PSXHW_LOG("DMA2 MADR 32bit read %x\n", psxHu32(0x10a0));
317                         return SWAPu32(HW_DMA2_MADR);
318                 case 0x1f8010a4:
319                         PSXHW_LOG("DMA2 BCR 32bit read %x\n", psxHu32(0x10a4));
320                         return SWAPu32(HW_DMA2_BCR);
321                 case 0x1f8010a8:
322                         PSXHW_LOG("DMA2 CHCR 32bit read %x\n", psxHu32(0x10a8));
323                         return SWAPu32(HW_DMA2_CHCR);
324 #endif
325
326 #ifdef PSXHW_LOG
327                 case 0x1f8010b0:
328                         PSXHW_LOG("DMA3 MADR 32bit read %x\n", psxHu32(0x10b0));
329                         return SWAPu32(HW_DMA3_MADR);
330                 case 0x1f8010b4:
331                         PSXHW_LOG("DMA3 BCR 32bit read %x\n", psxHu32(0x10b4));
332                         return SWAPu32(HW_DMA3_BCR);
333                 case 0x1f8010b8:
334                         PSXHW_LOG("DMA3 CHCR 32bit read %x\n", psxHu32(0x10b8));
335                         return SWAPu32(HW_DMA3_CHCR);
336 #endif
337
338 #ifdef PSXHW_LOG
339 /*              case 0x1f8010f0:
340                         PSXHW_LOG("DMA PCR 32bit read %x\n", psxHu32(0x10f0));
341                         return SWAPu32(HW_DMA_PCR); // dma rest channel
342                 case 0x1f8010f4:
343                         PSXHW_LOG("DMA ICR 32bit read %x\n", psxHu32(0x10f4));
344                         return SWAPu32(HW_DMA_ICR); // interrupt enabler?*/
345 #endif
346
347                 // time for rootcounters :)
348                 case 0x1f801100:
349                         hard = psxRcntRcount(0);
350 #ifdef PSXHW_LOG
351                         PSXHW_LOG("T0 count read32: %x\n", hard);
352 #endif
353                         return hard;
354                 case 0x1f801104:
355                         hard = psxRcntRmode(0);
356 #ifdef PSXHW_LOG
357                         PSXHW_LOG("T0 mode read32: %x\n", hard);
358 #endif
359                         return hard;
360                 case 0x1f801108:
361                         hard = psxRcntRtarget(0);
362 #ifdef PSXHW_LOG
363                         PSXHW_LOG("T0 target read32: %x\n", hard);
364 #endif
365                         return hard;
366                 case 0x1f801110:
367                         hard = psxRcntRcount(1);
368 #ifdef PSXHW_LOG
369                         PSXHW_LOG("T1 count read32: %x\n", hard);
370 #endif
371                         return hard;
372                 case 0x1f801114:
373                         hard = psxRcntRmode(1);
374 #ifdef PSXHW_LOG
375                         PSXHW_LOG("T1 mode read32: %x\n", hard);
376 #endif
377                         return hard;
378                 case 0x1f801118:
379                         hard = psxRcntRtarget(1);
380 #ifdef PSXHW_LOG
381                         PSXHW_LOG("T1 target read32: %x\n", hard);
382 #endif
383                         return hard;
384                 case 0x1f801120:
385                         hard = psxRcntRcount(2);
386 #ifdef PSXHW_LOG
387                         PSXHW_LOG("T2 count read32: %x\n", hard);
388 #endif
389                         return hard;
390                 case 0x1f801124:
391                         hard = psxRcntRmode(2);
392 #ifdef PSXHW_LOG
393                         PSXHW_LOG("T2 mode read32: %x\n", hard);
394 #endif
395                         return hard;
396                 case 0x1f801128:
397                         hard = psxRcntRtarget(2);
398 #ifdef PSXHW_LOG
399                         PSXHW_LOG("T2 target read32: %x\n", hard);
400 #endif
401                         return hard;
402
403                 case 0x1f801048:
404                 case 0x1f80104c:
405                 case 0x1f801050:
406                 case 0x1f801054:
407                 case 0x1f801058:
408                 case 0x1f80105c:
409                 case 0x1f801800:
410                         log_unhandled("unhandled r32 %08x @%08x\n", add, psxRegs.pc);
411                         // falthrough
412                 default:
413                         if (0x1f801c00 <= add && add < 0x1f802000) {
414                                 hard = SPU_readRegister(add);
415                                 hard |= SPU_readRegister(add + 2) << 16;
416                                 return hard;
417                         }
418                         hard = psxHu32(add);
419 #ifdef PSXHW_LOG
420                         PSXHW_LOG("*Unkwnown 32bit read at address %x\n", add);
421 #endif
422                         return hard;
423         }
424 #ifdef PSXHW_LOG
425         PSXHW_LOG("*Known 32bit read at address %x\n", add);
426 #endif
427         return hard;
428 }
429
430 void psxHwWrite8(u32 add, u8 value) {
431         switch (add & 0x1fffffff) {
432                 case 0x1f801040: sioWrite8(value); break;\r
433                 case 0x1f801800: cdrWrite0(value); break;
434                 case 0x1f801801: cdrWrite1(value); break;
435                 case 0x1f801802: cdrWrite2(value); break;
436                 case 0x1f801803: cdrWrite3(value); break;
437
438                 case 0x1f801041: case 0x1f801042: case 0x1f801043:
439                 case 0x1f801044: case 0x1f801045:
440                 case 0x1f801046: case 0x1f801047:
441                 case 0x1f801048: case 0x1f801049:
442                 case 0x1f80104a: case 0x1f80104b:
443                 case 0x1f80104c: case 0x1f80104d:
444                 case 0x1f80104e: case 0x1f80104f:
445                 case 0x1f801050: case 0x1f801051:
446                 case 0x1f801054: case 0x1f801055:
447                 case 0x1f801058: case 0x1f801059:
448                 case 0x1f80105a: case 0x1f80105b:
449                 case 0x1f80105c: case 0x1f80105d:
450                 case 0x1f801100: case 0x1f801101:
451                 case 0x1f801104: case 0x1f801105:
452                 case 0x1f801108: case 0x1f801109:
453                 case 0x1f801110: case 0x1f801111:
454                 case 0x1f801114: case 0x1f801115:
455                 case 0x1f801118: case 0x1f801119:
456                 case 0x1f801120: case 0x1f801121:
457                 case 0x1f801124: case 0x1f801125:
458                 case 0x1f801128: case 0x1f801129:
459                 case 0x1f801810: case 0x1f801811:
460                 case 0x1f801812: case 0x1f801813:
461                 case 0x1f801814: case 0x1f801815:
462                 case 0x1f801816: case 0x1f801817:
463                 case 0x1f801820: case 0x1f801821:
464                 case 0x1f801822: case 0x1f801823:
465                 case 0x1f801824: case 0x1f801825:
466                 case 0x1f801826: case 0x1f801827:
467                         log_unhandled("unhandled w8  %08x @%08x\n", add, psxRegs.pc);
468                         // falthrough
469                 default:
470                         if (0x1f801c00 <= add && add < 0x1f802000) {
471                                 log_unhandled("spu w8 %02x @%08x\n", value, psxRegs.pc);
472                                 if (!(add & 1))
473                                         SPU_writeRegister(add, value, psxRegs.cycle);
474                                 return;
475                         }
476
477                         psxHu8(add) = value;
478 #ifdef PSXHW_LOG
479                         PSXHW_LOG("*Unknown 8bit write at address %x value %x\n", add, value);
480 #endif
481                         return;
482         }
483         psxHu8(add) = value;
484 #ifdef PSXHW_LOG
485         PSXHW_LOG("*Known 8bit write at address %x value %x\n", add, value);
486 #endif
487 }
488
489 void psxHwWrite16(u32 add, u16 value) {
490         switch (add & 0x1fffffff) {
491                 case 0x1f801040:
492                         sioWrite8((unsigned char)value);
493                         sioWrite8((unsigned char)(value>>8));
494                         PAD_LOG ("sio write16 %x, %x\n", add&0xf, value);
495                         return;
496                 case 0x1f801044:
497                         sioWriteStat16(value);
498                         PAD_LOG ("sio write16 %x, %x\n", add&0xf, value);
499                         return;
500                 case 0x1f801048:
501                         sioWriteMode16(value);
502                         PAD_LOG ("sio write16 %x, %x\n", add&0xf, value);
503                         return;
504                 case 0x1f80104a: // control register
505                         sioWriteCtrl16(value);
506                         PAD_LOG ("sio write16 %x, %x\n", add&0xf, value);
507                         return;
508                 case 0x1f80104e: // baudrate register
509                         sioWriteBaud16(value);
510                         PAD_LOG ("sio write16 %x, %x\n", add&0xf, value);
511                         return;
512                 case 0x1f801070: 
513 #ifdef PSXHW_LOG
514                         PSXHW_LOG("IREG 16bit write %x\n", value);
515 #endif
516                         psxHwWriteIstat(value);
517                         return;
518
519                 case 0x1f801074:
520 #ifdef PSXHW_LOG
521                         PSXHW_LOG("IMASK 16bit write %x\n", value);
522 #endif
523                         psxHwWriteImask(value);
524                         return;
525
526                 case 0x1f801100:
527 #ifdef PSXHW_LOG
528                         PSXHW_LOG("COUNTER 0 COUNT 16bit write %x\n", value);
529 #endif
530                         psxRcntWcount(0, value); return;
531                 case 0x1f801104:
532 #ifdef PSXHW_LOG
533                         PSXHW_LOG("COUNTER 0 MODE 16bit write %x\n", value);
534 #endif
535                         psxRcntWmode(0, value); return;
536                 case 0x1f801108:
537 #ifdef PSXHW_LOG
538                         PSXHW_LOG("COUNTER 0 TARGET 16bit write %x\n", value);
539 #endif
540                         psxRcntWtarget(0, value); return;
541
542                 case 0x1f801110:
543 #ifdef PSXHW_LOG
544                         PSXHW_LOG("COUNTER 1 COUNT 16bit write %x\n", value);
545 #endif
546                         psxRcntWcount(1, value); return;
547                 case 0x1f801114:
548 #ifdef PSXHW_LOG
549                         PSXHW_LOG("COUNTER 1 MODE 16bit write %x\n", value);
550 #endif
551                         psxRcntWmode(1, value); return;
552                 case 0x1f801118:
553 #ifdef PSXHW_LOG
554                         PSXHW_LOG("COUNTER 1 TARGET 16bit write %x\n", value);
555 #endif
556                         psxRcntWtarget(1, value); return;
557
558                 case 0x1f801120:
559 #ifdef PSXHW_LOG
560                         PSXHW_LOG("COUNTER 2 COUNT 16bit write %x\n", value);
561 #endif
562                         psxRcntWcount(2, value); return;
563                 case 0x1f801124:
564 #ifdef PSXHW_LOG
565                         PSXHW_LOG("COUNTER 2 MODE 16bit write %x\n", value);
566 #endif
567                         psxRcntWmode(2, value); return;
568                 case 0x1f801128:
569 #ifdef PSXHW_LOG
570                         PSXHW_LOG("COUNTER 2 TARGET 16bit write %x\n", value);
571 #endif
572                         psxRcntWtarget(2, value); return;
573
574                 case 0x1f801042:
575                 case 0x1f801046:
576                 case 0x1f80104c:
577                 case 0x1f801050:
578                 case 0x1f801054:
579                 case 0x1f801058:
580                 case 0x1f80105a:
581                 case 0x1f80105c:
582                 case 0x1f801800:
583                 case 0x1f801802:
584                 case 0x1f801810:
585                 case 0x1f801812:
586                 case 0x1f801814:
587                 case 0x1f801816:
588                 case 0x1f801820:
589                 case 0x1f801822:
590                 case 0x1f801824:
591                 case 0x1f801826:
592                         log_unhandled("unhandled w16 %08x @%08x\n", add, psxRegs.pc);
593                         // falthrough
594                 default:
595                         if (0x1f801c00 <= add && add < 0x1f802000) {
596                                 SPU_writeRegister(add, value, psxRegs.cycle);
597                                 return;
598                         }
599
600                         psxHu16ref(add) = SWAPu16(value);
601 #ifdef PSXHW_LOG
602                         PSXHW_LOG("*Unknown 16bit write at address %x value %x\n", add, value);
603 #endif
604                         return;
605         }
606         psxHu16ref(add) = SWAPu16(value);
607 #ifdef PSXHW_LOG
608         PSXHW_LOG("*Known 16bit write at address %x value %x\n", add, value);
609 #endif
610 }
611
612 #define DmaExec(n) { \
613         if (value & SWAPu32(HW_DMA##n##_CHCR) & 0x01000000) \
614                 log_unhandled("dma" #n " %08x -> %08x\n", HW_DMA##n##_CHCR, value); \
615         HW_DMA##n##_CHCR = SWAPu32(value); \
616 \
617         if (SWAPu32(HW_DMA##n##_CHCR) & 0x01000000 && SWAPu32(HW_DMA_PCR) & (8 << (n * 4))) { \
618                 psxDma##n(SWAPu32(HW_DMA##n##_MADR), SWAPu32(HW_DMA##n##_BCR), SWAPu32(HW_DMA##n##_CHCR)); \
619         } \
620 }
621
622 void psxHwWrite32(u32 add, u32 value) {
623         switch (add & 0x1fffffff) {
624             case 0x1f801040:
625                         sioWrite8((unsigned char)value);
626                         sioWrite8((unsigned char)((value&0xff) >>  8));
627                         sioWrite8((unsigned char)((value&0xff) >> 16));
628                         sioWrite8((unsigned char)((value&0xff) >> 24));
629                         PAD_LOG("sio write32 %x\n", value);
630                         return;
631 #ifdef PSXHW_LOG
632                 case 0x1f801060:
633                         PSXHW_LOG("RAM size write %x\n", value);
634                         psxHu32ref(add) = SWAPu32(value);
635                         return; // Ram size
636 #endif
637
638                 case 0x1f801070: 
639 #ifdef PSXHW_LOG
640                         PSXHW_LOG("IREG 32bit write %x\n", value);
641 #endif
642                         psxHwWriteIstat(value);
643                         return;
644                 case 0x1f801074:
645 #ifdef PSXHW_LOG
646                         PSXHW_LOG("IMASK 32bit write %x\n", value);
647 #endif
648                         psxHwWriteImask(value);
649                         return;
650
651 #ifdef PSXHW_LOG
652                 case 0x1f801080:
653                         PSXHW_LOG("DMA0 MADR 32bit write %x\n", value);
654                         HW_DMA0_MADR = SWAPu32(value); return; // DMA0 madr
655                 case 0x1f801084:
656                         PSXHW_LOG("DMA0 BCR 32bit write %x\n", value);
657                         HW_DMA0_BCR  = SWAPu32(value); return; // DMA0 bcr
658 #endif
659                 case 0x1f801088:
660 #ifdef PSXHW_LOG
661                         PSXHW_LOG("DMA0 CHCR 32bit write %x\n", value);
662 #endif
663                         DmaExec(0);                      // DMA0 chcr (MDEC in DMA)
664                         return;
665
666 #ifdef PSXHW_LOG
667                 case 0x1f801090:
668                         PSXHW_LOG("DMA1 MADR 32bit write %x\n", value);
669                         HW_DMA1_MADR = SWAPu32(value); return; // DMA1 madr
670                 case 0x1f801094:
671                         PSXHW_LOG("DMA1 BCR 32bit write %x\n", value);
672                         HW_DMA1_BCR  = SWAPu32(value); return; // DMA1 bcr
673 #endif
674                 case 0x1f801098:
675 #ifdef PSXHW_LOG
676                         PSXHW_LOG("DMA1 CHCR 32bit write %x\n", value);
677 #endif
678                         DmaExec(1);                  // DMA1 chcr (MDEC out DMA)
679                         return;
680
681 #ifdef PSXHW_LOG
682                 case 0x1f8010a0:
683                         PSXHW_LOG("DMA2 MADR 32bit write %x\n", value);
684                         HW_DMA2_MADR = SWAPu32(value); return; // DMA2 madr
685                 case 0x1f8010a4:
686                         PSXHW_LOG("DMA2 BCR 32bit write %x\n", value);
687                         HW_DMA2_BCR  = SWAPu32(value); return; // DMA2 bcr
688 #endif
689                 case 0x1f8010a8:
690 #ifdef PSXHW_LOG
691                         PSXHW_LOG("DMA2 CHCR 32bit write %x\n", value);
692 #endif
693                         DmaExec(2);                  // DMA2 chcr (GPU DMA)
694                         return;
695
696 #ifdef PSXHW_LOG
697                 case 0x1f8010b0:
698                         PSXHW_LOG("DMA3 MADR 32bit write %x\n", value);
699                         HW_DMA3_MADR = SWAPu32(value); return; // DMA3 madr
700                 case 0x1f8010b4:
701                         PSXHW_LOG("DMA3 BCR 32bit write %x\n", value);
702                         HW_DMA3_BCR  = SWAPu32(value); return; // DMA3 bcr
703 #endif
704                 case 0x1f8010b8:
705 #ifdef PSXHW_LOG
706                         PSXHW_LOG("DMA3 CHCR 32bit write %x\n", value);
707 #endif
708                         DmaExec(3);                  // DMA3 chcr (CDROM DMA)
709                         
710                         return;
711
712 #ifdef PSXHW_LOG
713                 case 0x1f8010c0:
714                         PSXHW_LOG("DMA4 MADR 32bit write %x\n", value);
715                         HW_DMA4_MADR = SWAPu32(value); return; // DMA4 madr
716                 case 0x1f8010c4:
717                         PSXHW_LOG("DMA4 BCR 32bit write %x\n", value);
718                         HW_DMA4_BCR  = SWAPu32(value); return; // DMA4 bcr
719 #endif
720                 case 0x1f8010c8:
721 #ifdef PSXHW_LOG
722                         PSXHW_LOG("DMA4 CHCR 32bit write %x\n", value);
723 #endif
724                         DmaExec(4);                  // DMA4 chcr (SPU DMA)
725                         return;
726
727 #if 0
728                 case 0x1f8010d0: break; //DMA5write_madr();
729                 case 0x1f8010d4: break; //DMA5write_bcr();
730                 case 0x1f8010d8: break; //DMA5write_chcr(); // Not needed
731 #endif
732
733 #ifdef PSXHW_LOG
734                 case 0x1f8010e0:
735                         PSXHW_LOG("DMA6 MADR 32bit write %x\n", value);
736                         HW_DMA6_MADR = SWAPu32(value); return; // DMA6 bcr
737                 case 0x1f8010e4:
738                         PSXHW_LOG("DMA6 BCR 32bit write %x\n", value);
739                         HW_DMA6_BCR  = SWAPu32(value); return; // DMA6 bcr
740 #endif
741                 case 0x1f8010e8:
742 #ifdef PSXHW_LOG
743                         PSXHW_LOG("DMA6 CHCR 32bit write %x\n", value);
744 #endif
745                         DmaExec(6);                   // DMA6 chcr (OT clear)
746                         return;
747
748 #ifdef PSXHW_LOG
749                 case 0x1f8010f0:
750                         PSXHW_LOG("DMA PCR 32bit write %x\n", value);
751                         HW_DMA_PCR = SWAPu32(value);
752                         return;
753 #endif
754
755                 case 0x1f8010f4:
756 #ifdef PSXHW_LOG
757                         PSXHW_LOG("DMA ICR 32bit write %x\n", value);
758 #endif
759                         psxHwWriteDmaIcr32(value);
760                         return;
761
762                 case 0x1f801810:
763 #ifdef PSXHW_LOG
764                         PSXHW_LOG("GPU DATA 32bit write %x\n", value);
765 #endif
766                         GPU_writeData(value); return;
767                 case 0x1f801814:
768 #ifdef PSXHW_LOG
769                         PSXHW_LOG("GPU STATUS 32bit write %x\n", value);
770 #endif
771                         GPU_writeStatus(value);
772                         gpuSyncPluginSR();
773                         return;
774
775                 case 0x1f801820:
776                         mdecWrite0(value); break;
777                 case 0x1f801824:
778                         mdecWrite1(value); break;
779
780                 case 0x1f801100:
781 #ifdef PSXHW_LOG
782                         PSXHW_LOG("COUNTER 0 COUNT 32bit write %x\n", value);
783 #endif
784                         psxRcntWcount(0, value & 0xffff); return;
785                 case 0x1f801104:
786 #ifdef PSXHW_LOG
787                         PSXHW_LOG("COUNTER 0 MODE 32bit write %x\n", value);
788 #endif
789                         psxRcntWmode(0, value); return;
790                 case 0x1f801108:
791 #ifdef PSXHW_LOG
792                         PSXHW_LOG("COUNTER 0 TARGET 32bit write %x\n", value);
793 #endif
794                         psxRcntWtarget(0, value & 0xffff); return; //  HW_DMA_ICR&= SWAP32((~value)&0xff000000);
795
796                 case 0x1f801110:
797 #ifdef PSXHW_LOG
798                         PSXHW_LOG("COUNTER 1 COUNT 32bit write %x\n", value);
799 #endif
800                         psxRcntWcount(1, value & 0xffff); return;
801                 case 0x1f801114:
802 #ifdef PSXHW_LOG
803                         PSXHW_LOG("COUNTER 1 MODE 32bit write %x\n", value);
804 #endif
805                         psxRcntWmode(1, value); return;
806                 case 0x1f801118:
807 #ifdef PSXHW_LOG
808                         PSXHW_LOG("COUNTER 1 TARGET 32bit write %x\n", value);
809 #endif
810                         psxRcntWtarget(1, value & 0xffff); return;
811
812                 case 0x1f801120:
813 #ifdef PSXHW_LOG
814                         PSXHW_LOG("COUNTER 2 COUNT 32bit write %x\n", value);
815 #endif
816                         psxRcntWcount(2, value & 0xffff); return;
817                 case 0x1f801124:
818 #ifdef PSXHW_LOG
819                         PSXHW_LOG("COUNTER 2 MODE 32bit write %x\n", value);
820 #endif
821                         psxRcntWmode(2, value); return;
822                 case 0x1f801128:
823 #ifdef PSXHW_LOG
824                         PSXHW_LOG("COUNTER 2 TARGET 32bit write %x\n", value);
825 #endif
826                         psxRcntWtarget(2, value & 0xffff); return;
827
828                 case 0x1f801044:
829                 case 0x1f801048:
830                 case 0x1f80104c:
831                 case 0x1f801050:
832                 case 0x1f801054:
833                 case 0x1f801058:
834                 case 0x1f80105c:
835                 case 0x1f801800:
836                         log_unhandled("unhandled w32 %08x @%08x\n", add, psxRegs.pc);
837                         // falthrough
838                 default:
839                         // Dukes of Hazard 2 - car engine noise
840                         if (0x1f801c00 <= add && add < 0x1f802000) {
841                                 SPU_writeRegister(add, value&0xffff, psxRegs.cycle);
842                                 SPU_writeRegister(add + 2, value>>16, psxRegs.cycle);
843                                 return;
844                         }
845
846                         psxHu32ref(add) = SWAPu32(value);
847 #ifdef PSXHW_LOG
848                         PSXHW_LOG("*Unknown 32bit write at address %x value %x\n", add, value);
849 #endif
850                         return;
851         }
852         psxHu32ref(add) = SWAPu32(value);
853 #ifdef PSXHW_LOG
854         PSXHW_LOG("*Known 32bit write at address %x value %x\n", add, value);
855 #endif
856 }
857
858 int psxHwFreeze(void *f, int Mode) {
859         return 0;
860 }