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