1 //---------------------------------------------------------------------------
2 // NEOPOP : Emulator as in Dreamland
3 //
4 // Copyright (c) 2001-2002 by neopop_uk
5 //---------------------------------------------------------------------------
6
7 //---------------------------------------------------------------------------
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version. See also the license.txt file for
12 // additional informations.
13 //---------------------------------------------------------------------------
14
15 #include "neopop.h"
16 #include "TLCS-900h/TLCS900h_registers.h"
17 #include "Z80_interface.h"
18 #include "bios.h"
19 #include "gfx.h"
20 #include "mem.h"
21 #include "interrupt.h"
22 #include "sound.h"
23 #include "flash.h"
24 #include "rom.h"
25 #include "rtc.h"
26
27 #ifdef MSB_FIRST
28 #include "../masmem.h"
29 #endif
30
31 #include "../settings.h"
32
33 /* Hack way of returning good Flash status. */
34 bool FlashStatusEnable = false;
35 static uint32 FlashStatus;
36
37 uint8_t CPUExRAM[16384];
38
39 bool debug_abort_memory = false;
40 bool debug_mask_memory_error_messages = false;
41
42 bool memory_unlock_flash_write = false;
43 bool memory_flash_error = false;
44 bool memory_flash_command = false;
45
46
47 uint8_t SC0BUF; /* Serial channel 0 buffer. */
48 uint8_t COMMStatus;
49
50 /* In very very very rare conditions(like on embedded platforms with
51 * no virtual memory and very limited RAM and malloc happens to
52 * return a pointer aligned to a 64KiB boundary), a FastReadMap entry
53 * may be NULL even if it points to valid data when it's added to
54 * the address of the read, but if this happens, it will only
55 * make the emulator slightly slower. */
56 static uint8_t *FastReadMap[256], *FastReadMapReal[256];
57
58 /* Call this function after ROM is loaded */
SetFRM(void)59 void SetFRM(void)
60 {
61 unsigned int x;
62
63 for(x = 0; x < 256; x++)
64 FastReadMapReal[x] = NULL;
65
66 for(x = 0x20; x <= 0x3f; x++)
67 {
68 if(ngpc_rom.length > (x * 65536 + 65535 - 0x20000))
69 FastReadMapReal[x] = &ngpc_rom.data[x * 65536 - 0x200000] - x * 65536;
70 }
71
72 for(x = 0x80; x <= 0x9f; x++)
73 {
74 if(ngpc_rom.length > (x * 65536 + 65535 - 0x80000))
75 FastReadMapReal[x] = &ngpc_rom.data[x * 65536 - 0x800000] - x * 65536;
76 }
77 }
78
RecacheFRM(void)79 void RecacheFRM(void)
80 {
81 int x;
82 for (x = 0; x < 256; x++)
83 FastReadMap[x] = FlashStatusEnable ? NULL : FastReadMapReal[x];
84 }
85
translate_address_read(uint32 address)86 static void* translate_address_read(uint32 address)
87 {
88 address &= 0xFFFFFF;
89
90 if (FlashStatusEnable)
91 {
92 /*Get Flash status? */
93 if (
94 (address >= ROM_START && address <= ROM_END) ||
95 (address >= HIROM_START && address <= HIROM_END))
96 {
97 FlashStatusEnable = false;
98 RecacheFRM();
99 if (address == 0x220000 || address == 0x230000)
100 {
101 FlashStatus = 0xFFFFFFFF;
102 return &FlashStatus;
103 }
104 }
105 }
106
107 if (address >= ROM_START && address <= ROM_END)
108 {
109 /* ROM (LOW) */
110 if (address < ROM_START + ngpc_rom.length)
111 return ngpc_rom.data + (address - ROM_START);
112 return NULL;
113 }
114
115 if (address >= HIROM_START && address <= HIROM_END)
116 {
117 /* ROM (HIGH) */
118 if (address < HIROM_START + (ngpc_rom.length - 0x200000))
119 return ngpc_rom.data + 0x200000 + (address - HIROM_START);
120 return NULL;
121 }
122
123 /*BIOS Access? */
124 if ((address & 0xFF0000) == 0xFF0000)
125 return ngpc_bios + (address & 0xFFFF); /* BIOS ROM */
126 return NULL;
127 }
128
translate_address_write(uint32 address)129 static void *translate_address_write(uint32 address)
130 {
131 address &= 0xFFFFFF;
132
133 if (memory_unlock_flash_write)
134 {
135 /* ROM (LOW) */
136 if (address >= ROM_START && address <= ROM_END)
137 {
138 if (address < ROM_START + ngpc_rom.length)
139 return ngpc_rom.data + (address - ROM_START);
140 return NULL;
141 }
142
143 /* ROM (HIGH) */
144 if (address >= HIROM_START && address <= HIROM_END)
145 {
146 if (address < HIROM_START + (ngpc_rom.length - 0x200000))
147 return ngpc_rom.data + 0x200000 + (address - HIROM_START);
148 return NULL;
149 }
150 }
151 else
152 {
153 /*ROM (LOW) */
154
155 if (address >= ROM_START && address <= ROM_END)
156 {
157 //Ignore Flash commands
158 if (address == 0x202AAA || address == 0x205555)
159 {
160 // system_debug_message("%06X: Enable Flash command from %06X", pc, address);
161 memory_flash_command = true;
162 return NULL;
163 }
164
165 //Set Flash status reading?
166 if (address == 0x220000 || address == 0x230000)
167 {
168 // system_debug_message("%06X: Flash status read from %06X", pc, address);
169 FlashStatusEnable = true;
170 RecacheFRM();
171 return NULL;
172 }
173
174 if (memory_flash_command)
175 {
176 //Write the 256byte block around the flash data
177 flash_write(address & 0xFFFF00, 256);
178
179 //Need to issue a new command before writing will work again.
180 memory_flash_command = false;
181
182 // system_debug_message("%06X: Direct Flash write to %06X", pc, address & 0xFFFF00);
183 // system_debug_stop();
184
185 //Write to the rom itself.
186 if (address < ROM_START + ngpc_rom.length)
187 return ngpc_rom.data + (address - ROM_START);
188 }
189 }
190 }
191
192 return NULL;
193 }
194
195 /* WARNING: 32-bit loads and stores apparently DON'T have to be 4-byte-aligned(so we must +2 instead of |2). */
196 /* Treat all 32-bit operations as two 16-bit operations */
197 extern uint32 pc;
198
199 uint8_t lastpoof = 0;
200
loadB(uint32 address)201 uint8_t loadB(uint32 address)
202 {
203 uint8_t *ptr;
204 address &= 0xFFFFFF;
205
206 if(FastReadMap[address >> 16])
207 return(FastReadMap[address >> 16][address]);
208
209 ptr = (uint8_t*)translate_address_read(address);
210
211 if (ptr)
212 return *ptr;
213
214 if(address >= 0x8000 && address <= 0xbfff)
215 return(ngpgfx_read8(NGPGfx, address));
216
217 if(address >= 0x4000 && address <= 0x7fff)
218 return(*(uint8_t *)(CPUExRAM + address - 0x4000));
219
220 if(address >= 0x70 && address <= 0x7F)
221 return(int_read8(address));
222
223 if(address >= 0x90 && address <= 0x97)
224 return(rtc_read8(address));
225
226 if(address >= 0x20 && address <= 0x29)
227 return(timer_read8(address));
228
229 switch (address)
230 {
231 case 0x50:
232 return(SC0BUF);
233 case 0xBC:
234 return Z80_ReadComm();
235 }
236
237 //printf("UNK B R: %08x\n", address);
238
239 return 0;
240 }
241
loadW(uint32 address)242 uint16_t loadW(uint32 address)
243 {
244 uint16_t* ptr;
245 address &= 0xFFFFFF;
246
247 if(address & 1)
248 {
249 uint16 ret = loadB(address);
250 ret |= loadB(address + 1) << 8;
251
252 return(ret);
253 }
254
255 if(FastReadMap[address >> 16])
256 {
257 uint16_t *ptr16 = (uint16_t*)&FastReadMap[address >> 16][address];
258 #ifdef MSB_FIRST
259 return LoadU16_RBO(ptr16);
260 #else
261 return *ptr16;
262 #endif
263 }
264
265 ptr = (uint16_t*)translate_address_read(address);
266 if(ptr)
267 {
268 #ifdef MSB_FIRST
269 return LoadU16_RBO(ptr);
270 #else
271 return *ptr;
272 #endif
273 }
274
275 if(address >= 0x8000 && address <= 0xbfff)
276 return(ngpgfx_read16(NGPGfx, address));
277
278 if(address >= 0x4000 && address <= 0x7fff)
279 {
280 uint16_t *ptr16 = (uint16_t *)(CPUExRAM + address - 0x4000);
281 #ifdef MSB_FIRST
282 return LoadU16_RBO(ptr16);
283 #else
284 return *ptr16;
285 #endif
286 }
287
288 if(address == 0x50)
289 return(SC0BUF);
290
291 if(address >= 0x70 && address <= 0x7F)
292 {
293 uint16 ret = int_read8(address);
294 ret |= int_read8(address + 1) << 8;
295
296 return(ret);
297 }
298
299 if(address >= 0x90 && address <= 0x97)
300 {
301 uint16 ret = rtc_read8(address);
302 ret |= rtc_read8(address + 1) << 8;
303
304 return(ret);
305 }
306
307 if(address >= 0x20 && address <= 0x29)
308 {
309 uint16 ret = timer_read8(address);
310 ret |= timer_read8(address + 1) << 8;
311 return(ret);
312 }
313
314 if(address == 0xBC)
315 return Z80_ReadComm();
316
317 //printf("UNK W R: %08x\n", address);
318
319 return(0);
320 }
321
loadL(uint32 address)322 uint32 loadL(uint32 address)
323 {
324 uint32 ret = loadW(address);
325 ret |= loadW(address + 2) << 16;
326
327 return(ret);
328 }
329
storeB(uint32 address,uint8_t data)330 void storeB(uint32 address, uint8_t data)
331 {
332 uint8_t* ptr;
333 address &= 0xFFFFFF;
334
335 if(address < 0x80)
336 lastpoof = data;
337
338 if(address >= 0x8000 && address <= 0xbfff)
339 {
340 ngpgfx_write8(NGPGfx, address, data);
341 return;
342 }
343
344 if(address >= 0x4000 && address <= 0x7fff)
345 {
346 *(uint8_t *)(CPUExRAM + address - 0x4000) = data;
347 return;
348 }
349 if(address >= 0x70 && address <= 0x7F)
350 {
351 int_write8(address, data);
352 return;
353 }
354 if(address >= 0x20 && address <= 0x29)
355 {
356 timer_write8(address, data);
357 return;
358 }
359
360 switch (address)
361 {
362 case 0x50:
363 SC0BUF = data;
364 return;
365 case 0x6f: /* Watchdog timer */
366 return;
367 case 0xb2: /* Comm */
368 COMMStatus = data & 1;
369 return;
370 case 0xb9:
371 if(data == 0x55)
372 Z80_SetEnable(1);
373 else if(data == 0xAA)
374 Z80_SetEnable(0);
375 return;
376 case 0xb8:
377 if(data == 0x55)
378 MDFNNGPCSOUND_SetEnable(1);
379 else if(data == 0xAA)
380 MDFNNGPCSOUND_SetEnable(0);
381 return;
382 case 0xBA:
383 Z80_nmi();
384 return;
385 case 0xBC:
386 Z80_WriteComm(data);
387 return;
388 }
389
390 if(address >= 0xa0 && address <= 0xA3)
391 {
392 if(!Z80_IsEnabled())
393 {
394 if (address == 0xA1)
395 Write_SoundChipLeft(data);
396 else if (address == 0xA0)
397 Write_SoundChipRight(data);
398 }
399 //DAC Write
400 if (address == 0xA2)
401 dac_write_left(data);
402 else if (address == 0xA3)
403 dac_write_right(data);
404 return;
405 }
406
407 ptr = (uint8_t*)translate_address_write(address);
408
409 /* Write */
410 if (ptr)
411 *ptr = data;
412 }
413
storeW(uint32 address,uint16_t data)414 void storeW(uint32 address, uint16_t data)
415 {
416 uint16_t* ptr;
417 address &= 0xFFFFFF;
418
419 if(address & 1)
420 {
421 storeB(address + 0, data & 0xFF);
422 storeB(address + 1, data >> 8);
423 return;
424 }
425
426 if(address < 0x80)
427 lastpoof = data >> 8;
428
429 if(address >= 0x8000 && address <= 0xbfff)
430 {
431 ngpgfx_write16(NGPGfx, address, data);
432 return;
433 }
434 if(address >= 0x4000 && address <= 0x7fff)
435 {
436 uint16_t *ptr16 = (uint16_t *)(CPUExRAM + address - 0x4000);
437 #ifdef MSB_FIRST
438 StoreU16_RBO(ptr16, data);
439 #else
440 *ptr16 = data;
441 #endif
442 return;
443 }
444 if(address >= 0x70 && address <= 0x7F)
445 {
446 int_write8(address, data & 0xFF);
447 int_write8(address + 1, data >> 8);
448 return;
449 }
450
451 if(address >= 0x20 && address <= 0x29)
452 {
453 timer_write8(address, data & 0xFF);
454 timer_write8(address + 1, data >> 8);
455 }
456
457 switch (address)
458 {
459 case 0x50:
460 SC0BUF = data & 0xFF;
461 return;
462 case 0x6e: /* Watchdog timer(technically 0x6f) */
463 return;
464 case 0xB2: /* Comm */
465 COMMStatus = data & 1;
466 return;
467 case 0xb8:
468 if((data & 0xFF00) == 0x5500)
469 Z80_SetEnable(1);
470 else if((data & 0xFF00) == 0xAA00)
471 Z80_SetEnable(0);
472
473 if((data & 0xFF) == 0x55)
474 MDFNNGPCSOUND_SetEnable(1);
475 else if((data & 0xFF) == 0xAA)
476 MDFNNGPCSOUND_SetEnable(0);
477 return;
478 case 0xBA:
479 Z80_nmi();
480 return;
481 case 0xBC:
482 Z80_WriteComm(data);
483 return;
484 }
485
486 if(address >= 0xa0 && address <= 0xA3)
487 {
488 storeB(address, data & 0xFF);
489 storeB(address + 1, data >> 8);
490 return;
491 }
492
493 ptr = (uint16_t*)translate_address_write(address);
494
495 /* Write */
496 if (ptr)
497 {
498 #ifdef MSB_FIRST
499 StoreU16_RBO(ptr, data);
500 #else
501 *ptr = data;
502 #endif
503 }
504 }
505
storeL(uint32 address,uint32 data)506 void storeL(uint32 address, uint32 data)
507 {
508 storeW(address, data & 0xFFFF);
509 storeW(address + 2, data >> 16);
510 }
511
512 static const uint8_t systemMemory[] =
513 {
514 // 0x00 // 0x08
515 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0xFF, 0xFF,
516 // 0x10 // 0x18
517 0x34, 0x3C, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x3F, 0xFF, 0x2D, 0x01, 0xFF, 0xFF, 0x03, 0xB2,
518 // 0x20 // 0x28
519 0x80, 0x00, 0x01, 0x90, 0x03, 0xB0, 0x90, 0x62, 0x05, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x4C, 0x4C,
520 // 0x30 // 0x38
521 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0xFF, 0x80, 0x7F,
522 // 0x40 // 0x48
523 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524 // 0x50 // 0x58
525 0x00, 0x20, 0x69, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
526 // 0x60 // 0x68
527 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x03, 0x03, 0x02, 0x00, 0x00, 0x4E,
528 // 0x70 // 0x78
529 0x02, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
530 // 0x80 // 0x88
531 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
532 // 0x90 // 0x98
533 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
534 // 0xA0 // 0xA8
535 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
536 // 0xB0 // 0xB8
537 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 // 0xC0 // 0xC8
539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 // 0xD0 // 0xD8
541 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542 // 0xE0 // 0xE8
543 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544 // 0xF0 // 0xF8
545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
546 };
547
reset_memory(void)548 void reset_memory(void)
549 {
550 unsigned int i;
551
552 FlashStatusEnable = false;
553 RecacheFRM();
554
555 memory_flash_command = false;
556
557 /* 000000 -> 000100 CPU Internal RAM (Timers/DMA/Z80) */
558
559 for (i = 0; i < sizeof(systemMemory); i++)
560 storeB(i, systemMemory[i]);
561
562 /* 006C00 -> 006FFF BIOS Workspace */
563
564 storeL(0x6C00, rom_header->startPC); //Start
565
566 storeW(0x6C04, rom_header->catalog);
567 storeW(0x6E82, rom_header->catalog);
568
569 storeB(0x6C06, rom_header->subCatalog);
570 storeB(0x6E84, rom_header->subCatalog);
571
572 for(i = 0; i < 12; i++)
573 storeB(0x6c08 + i, ngpc_rom.data[0x24 + i]);
574
575 storeB(0x6C58, 0x01);
576
577 /* 32MBit cart? */
578 if (ngpc_rom.length > 0x200000)
579 storeB(0x6C59, 0x01);
580 else
581 storeB(0x6C59, 0x00);
582
583 storeB(0x6C55, 1); /* Commercial game */
584
585 storeB(0x6F80, 0xFF); /* Lots of battery power! */
586 storeB(0x6F81, 0x03);
587
588 storeB(0x6F84, 0x40); /* "Power On" startup */
589 storeB(0x6F85, 0x00); /* No shutdown request */
590 storeB(0x6F86, 0x00); /* No user answer (?) */
591
592 /* Language: 0 = Japanese, 1 = English */
593 storeB(0x6F87, MDFN_GetSettingB("ngp.language"));
594
595 /* Color Mode Selection: 0x00 = B&W, 0x10 = Colour */
596 storeB(0x6F91, rom_header->mode);
597 storeB(0x6F95, rom_header->mode);
598
599 /* Interrupt table */
600 for (i = 0; i < 0x12; i++)
601 storeL(0x6FB8 + i * 4, 0x00FF23DF);
602
603
604 /* 008000 -> 00BFFF Video RAM */
605 storeB(0x8000, 0xC0); // Both interrupts allowed
606
607 /* Hardware window */
608 storeB(0x8002, 0x00);
609 storeB(0x8003, 0x00);
610 storeB(0x8004, 0xFF);
611 storeB(0x8005, 0xFF);
612
613 storeB(0x8006, 0xc6); // Frame Rate Register
614
615 storeB(0x8012, 0x00); // NEG / OOWC setting.
616
617 storeB(0x8118, 0x80); // BGC on!
618
619 storeB(0x83E0, 0xFF); // Default background colour
620 storeB(0x83E1, 0x0F);
621
622 storeB(0x83F0, 0xFF); // Default window colour
623 storeB(0x83F1, 0x0F);
624
625 storeB(0x8400, 0xFF); // LED on
626 storeB(0x8402, 0x80); // Flash cycle = 1.3s
627
628 storeB(0x87E2, loadB(0x6F95) ? 0x00 : 0x80);
629
630 //
631 // Metal Slug - 2nd Mission oddly relies on a specific character RAM pattern.
632 //
633 {
634 static const uint8 char_data[64] = {
635 255, 63, 255, 255, 0, 252, 255, 255, 255, 63, 3, 0, 255, 255, 255, 255,
636 240, 243, 252, 243, 255, 3, 255, 195, 255, 243, 243, 243, 240, 243, 240, 195,
637 207, 15, 207, 15, 207, 15, 207, 207, 207, 255, 207, 255, 207, 255, 207, 63,
638 255, 192, 252, 195, 240, 207, 192, 255, 192, 255, 240, 207, 252, 195, 255, 192 };
639
640 for(i = 0; i < 64; i++)
641 storeB(0xA1C0 + i, char_data[i]);
642 }
643 }
644