OSDN Git Service

[VM] .
[csp-qt/common_source_project-fm7.git] / source / src / vm / familybasic / memory.cpp
1 /*
2         Nintendo Family BASIC Emulator 'eFamilyBASIC'
3
4         Origin : nester
5         Author : Takeda.Toshiya
6         Date   : 2010.08.11-
7
8         [ memory ]
9 */
10
11 #include "./memory.h"
12 #include "ppu.h"
13 #include "../datarec.h"
14 #include "../ym2413.h"
15
16 namespace FAMILYBASIC {
17
18 #define EVENT_DMA_DONE  0
19
20 void MEMORY::initialize()
21 {
22         key_stat = emu->get_key_buffer();
23         joy_stat = emu->get_joy_buffer();
24         
25         // register event
26         register_vline_event(this);
27 }
28
29 void MEMORY::load_rom_image(const _TCHAR *file_name)
30 {
31         FILEIO* fio = new FILEIO();
32         
33         memset(save_ram, 0, sizeof(save_ram));
34         
35         if(fio->Fopen(create_local_path(file_name), FILEIO_READ_BINARY)) {
36                 // create save file name
37                 _TCHAR tmp_file_name[_MAX_PATH];
38                 my_tcscpy_s(tmp_file_name, _MAX_PATH, file_name);
39                 _TCHAR *dot = _tcsstr(tmp_file_name, _T("."));
40                 if(dot != NULL) dot[0] = _T('\0');
41                 my_stprintf_s(save_file_name, _MAX_PATH, _T("%s.SAV"), tmp_file_name);
42         } else {
43                 // for compatibility
44                 fio->Fopen(create_local_path(_T("BASIC.NES")), FILEIO_READ_BINARY);
45                 my_tcscpy_s(save_file_name, _MAX_PATH, _T("BACKUP.BIN"));
46         }
47         if(fio->IsOpened()) {
48                 // read header
49                 fio->Fread(&header, sizeof(header), 1);
50                 // read program rom
51                 rom_size = 0x2000 * header.num_8k_rom_banks();
52                 for(uint32_t bit = 0x80000; bit != 0; bit >>= 1) {
53                         if(rom_size & bit) {
54                                 if(rom_size & (bit - 1)) {
55                                         rom_size = (rom_size | (bit - 1)) + 1;
56                                 }
57                                 break;
58                         }
59                 }
60                 rom = (uint8_t *)calloc(rom_size, 1);
61                 fio->Fread(rom, 0x2000 * header.num_8k_rom_banks(), 1);
62                 fio->Fclose();
63         } else {
64                 memset(&header, 0, sizeof(header));
65                 header.dummy = 2; // 32KB
66                 rom_size = 0x2000 * header.num_8k_rom_banks();
67                 rom = (uint8_t *)calloc(rom_size, 1);
68                 memset(rom, 0xff, 0x2000 * header.num_8k_rom_banks());
69         }
70         if(fio->Fopen(create_local_path(save_file_name), FILEIO_READ_BINARY)) {
71                 fio->Fread(save_ram, sizeof(save_ram), 1);
72                 fio->Fclose();
73         }
74         delete fio;
75         
76         rom_mask = (rom_size / 0x2000) - 1;
77         save_ram_crc32 = get_crc32(save_ram, sizeof(save_ram));
78 }
79
80 void MEMORY::save_backup()
81 {
82         if(save_ram_crc32 != get_crc32(save_ram, sizeof(save_ram))) {
83                 FILEIO* fio = new FILEIO();
84                 if(fio->Fopen(create_local_path(save_file_name), FILEIO_WRITE_BINARY)) {
85                         fio->Fwrite(save_ram, sizeof(save_ram), 1);
86                         fio->Fclose();
87                 }
88                 delete fio;
89         }
90 }
91
92 void MEMORY::release()
93 {
94         if(rom != NULL) {
95                 free(rom);
96                 rom = NULL;
97         }
98         save_backup();
99 }
100
101 void MEMORY::reset()
102 {
103         memset(ram, 0, sizeof(ram));
104         
105         for(int i = 4; i < 8; i++) {
106                 set_rom_bank(i, i);
107         }
108         bank_ptr[3] = save_ram;
109         
110         dma_addr = 0x80;
111         frame_irq_enabled = 0xff;
112         
113         pad_strobe = false;
114         pad1_bits = pad2_bits = 0xff;
115         
116         kb_out = false;
117         kb_scan = 0;
118         
119         mmc5_reset();
120         vrc7_reset();
121 }
122
123 void MEMORY::write_data8(uint32_t addr, uint32_t data)
124 {
125         addr &= 0xffff;
126         
127         if(addr < 0x2000) {
128                 ram[addr & 0x7ff] = data;
129         } else if(addr < 0x4000) {
130                 d_ppu->write_data8(addr, data);
131         } else if(addr == 0x4014) {
132                 // stop cpu
133                 d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
134                 register_event_by_clock(this, EVENT_DMA_DONE, 514, false, NULL);
135                 // start dma
136                 dma_addr = data << 8;
137                 for(int i = 0; i < 256; i++) {
138                         spr_ram[i] = read_data8(dma_addr | i);
139                 }
140         } else if(addr == 0x4016) {
141                 if(data & 1) {
142                         pad_strobe = true;
143                 } else if(pad_strobe) {
144                         pad_strobe = false;
145                         // joypad #1
146                         pad1_bits = 0;
147                         if(joy_stat[0] & 0x10) pad1_bits |= 0x01;       // A
148                         if(joy_stat[0] & 0x20) pad1_bits |= 0x02;       // B
149                         if(joy_stat[0] & 0x40) pad1_bits |= 0x04;       // SEL
150                         if(joy_stat[0] & 0x80) pad1_bits |= 0x08;       // START
151                         if(joy_stat[0] & 0x01) pad1_bits |= 0x10;       // UP
152                         if(joy_stat[0] & 0x02) pad1_bits |= 0x20;       // DOWN
153                         if(joy_stat[0] & 0x04) pad1_bits |= 0x40;       // LEFT
154                         if(joy_stat[0] & 0x08) pad1_bits |= 0x80;       // RIGHT
155                         // joypad #2
156                         pad2_bits = 0;
157                         if(joy_stat[1] & 0x10) pad2_bits |= 0x01;       // A
158                         if(joy_stat[1] & 0x20) pad2_bits |= 0x02;       // B
159                         if(joy_stat[1] & 0x01) pad2_bits |= 0x10;       // UP
160                         if(joy_stat[1] & 0x02) pad2_bits |= 0x20;       // DOWN
161                         if(joy_stat[1] & 0x04) pad2_bits |= 0x40;       // LEFT
162                         if(joy_stat[1] & 0x08) pad2_bits |= 0x80;       // RIGHT
163                 }
164                 // keyboard
165                 if((data & 0x07) == 0x04) {
166                         if(++kb_scan > 9) {
167                                 kb_scan = 0;
168                         }
169                         kb_out = !kb_out;
170                 } else if((data & 0x07) == 0x05) {
171                         kb_out = false;
172                         kb_scan = 0;
173                 } else if((data & 0x07) == 0x06) {
174                         kb_out = !kb_out;
175                 }
176                 // data recorder (thanks MESS)
177                 if((data & 0x07) == 0x07) {
178                         d_drec->write_signal(SIG_DATAREC_MIC, 1, 1);
179                 } else {
180                         d_drec->write_signal(SIG_DATAREC_MIC, 0, 0);
181                 }
182         } else if(addr < 0x4018) {
183                 if(addr == 0x4017) {
184                         frame_irq_enabled = data;
185                 }
186                 d_apu->write_data8(addr, data);
187         } else if(addr < 0x6000) {
188                 if(header.mapper() == 5) {
189                         mmc5_lo_write(addr, data);
190 //              } else if(header.mapper() == 85) {
191 //                      vrc7_lo_write(addr, data);
192                 }
193         } else if(addr < 0x8000) {
194                 if(header.mapper() == 5) {
195                         mmc5_save_write(addr, data);
196 //              } else if(header.mapper() == 85) {
197 //                      vrc7_save_write(addr, data);
198                 } else {
199                         bank_ptr[3][addr & 0x1fff] = data;
200                 }
201         } else {
202                 if(header.mapper() == 5) {
203                         mmc5_hi_write(addr, data);
204                 } else if(header.mapper() == 85) {
205                         vrc7_hi_write(addr, data);
206                 }
207         }
208 }
209
210 uint32_t MEMORY::read_data8(uint32_t addr)
211 {
212         addr &= 0xffff;
213         
214         if(addr < 0x2000) {
215                 return ram[addr & 0x7ff];
216         } else if(addr < 0x4000) {
217                 return d_ppu->read_data8(addr);
218         } else if(addr == 0x4014) {
219                 return dma_addr >> 8;
220         } else if(addr < 0x4016) {
221                 uint32_t val = d_apu->read_data8(addr);
222                 if(addr == 0x4015 && !(frame_irq_enabled & 0xc0)) {
223                         val |= 0x40;
224                 }
225                 return val;
226         } else if(addr == 0x4016) {
227                 // joypad #1
228                 uint32_t val = pad1_bits & 1;
229                 pad1_bits >>= 1;
230                 // data recorder
231                 val |= d_drec->read_signal(0) ? 2 : 0;
232                 // mic
233                 val |= key_stat[0x7b] ? 4 : 0;  // F12
234                 return val;
235         } else if(addr == 0x4017) {
236                 // joypad #2
237                 uint32_t val = 0xfe | (pad2_bits & 1);
238                 pad2_bits >>= 1;
239                 // keyboard
240                 if(kb_out) {
241                         switch(kb_scan) {
242                         case 1:
243                                 if(key_stat[0x77]) val &= ~0x02;        // F8
244                                 if(key_stat[0x0d]) val &= ~0x04;        // RETURN
245                                 if(key_stat[0xdb]) val &= ~0x08;        // [
246                                 if(key_stat[0xdd]) val &= ~0x10;        // ]
247                                 break;
248                         case 2:
249                                 if(key_stat[0x76]) val &= ~0x02;        // F7
250                                 if(key_stat[0xc0]) val &= ~0x04;        // @
251                                 if(key_stat[0xba]) val &= ~0x08;        // :
252                                 if(key_stat[0xbb]) val &= ~0x10;        // ;
253                                 break;
254                         case 3:
255                                 if(key_stat[0x75]) val &= ~0x02;        // F6
256                                 if(key_stat[0x4f]) val &= ~0x04;        // O
257                                 if(key_stat[0x4c]) val &= ~0x08;        // L
258                                 if(key_stat[0x4b]) val &= ~0x10;        // K
259                                 break;
260                         case 4:
261                                 if(key_stat[0x74]) val &= ~0x02;        // F5
262                                 if(key_stat[0x49]) val &= ~0x04;        // I
263                                 if(key_stat[0x55]) val &= ~0x08;        // U
264                                 if(key_stat[0x4a]) val &= ~0x10;        // J
265                                 break;
266                         case 5:
267                                 if(key_stat[0x73]) val &= ~0x02;        // F4
268                                 if(key_stat[0x59]) val &= ~0x04;        // Y
269                                 if(key_stat[0x47]) val &= ~0x08;        // G
270                                 if(key_stat[0x48]) val &= ~0x10;        // H
271                                 break;
272                         case 6:
273                                 if(key_stat[0x72]) val &= ~0x02;        // F3
274                                 if(key_stat[0x54]) val &= ~0x04;        // T
275                                 if(key_stat[0x52]) val &= ~0x08;        // R
276                                 if(key_stat[0x44]) val &= ~0x10;        // D
277                                 break;
278                         case 7:
279                                 if(key_stat[0x71]) val &= ~0x02;        // F2
280                                 if(key_stat[0x57]) val &= ~0x04;        // W
281                                 if(key_stat[0x53]) val &= ~0x08;        // S
282                                 if(key_stat[0x41]) val &= ~0x10;        // A
283                                 break;
284                         case 8:
285                                 if(key_stat[0x70]) val &= ~0x02;        // F1
286                                 if(key_stat[0x1b]) val &= ~0x04;        // ESC
287                                 if(key_stat[0x51]) val &= ~0x08;        // Q
288                                 if(key_stat[0x11]) val &= ~0x10;        // CTRL
289                                 break;
290                         case 9:
291                                 if(key_stat[0x24]) val &= ~0x02;        // CLS
292                                 if(key_stat[0x26]) val &= ~0x04;        // UP
293                                 if(key_stat[0x27]) val &= ~0x08;        // RIGHT
294                                 if(key_stat[0x25]) val &= ~0x10;        // LEFT
295                                 break;
296                         }
297                 } else {
298                         switch(kb_scan) {
299                         case 1:
300                                 if(key_stat[0x15]) val &= ~0x02;        // KANA
301 //                              if(key_stat[0x10]) val &= ~0x04;        // RSHIFT
302                                 if(key_stat[0xdc]) val &= ~0x08;        // '\\'
303                                 if(key_stat[0x23]) val &= ~0x10;        // STOP
304                                 break;
305                         case 2:
306                                 if(key_stat[0xe2]) val &= ~0x02;        // _
307                                 if(key_stat[0xbf]) val &= ~0x04;        // /
308                                 if(key_stat[0xbd]) val &= ~0x08;        // -
309                                 if(key_stat[0xde]) val &= ~0x10;        // ^
310                                 break;
311                         case 3:
312                                 if(key_stat[0xbe]) val &= ~0x02;        // .
313                                 if(key_stat[0xbc]) val &= ~0x04;        // ,
314                                 if(key_stat[0x50]) val &= ~0x08;        // P
315                                 if(key_stat[0x30]) val &= ~0x10;        // 0
316                                 break;
317                         case 4:
318                                 if(key_stat[0x4d]) val &= ~0x02;        // M
319                                 if(key_stat[0x4e]) val &= ~0x04;        // N
320                                 if(key_stat[0x39]) val &= ~0x08;        // 9
321                                 if(key_stat[0x38]) val &= ~0x10;        // 8
322                                 break;
323                         case 5:
324                                 if(key_stat[0x42]) val &= ~0x02;        // B
325                                 if(key_stat[0x56]) val &= ~0x04;        // V
326                                 if(key_stat[0x37]) val &= ~0x08;        // 7
327                                 if(key_stat[0x36]) val &= ~0x10;        // 6
328                                 break;
329                         case 6:
330                                 if(key_stat[0x46]) val &= ~0x02;        // F
331                                 if(key_stat[0x43]) val &= ~0x04;        // C
332                                 if(key_stat[0x35]) val &= ~0x08;        // 5
333                                 if(key_stat[0x34]) val &= ~0x10;        // 4
334                                 break;
335                         case 7:
336                                 if(key_stat[0x58]) val &= ~0x02;        // X
337                                 if(key_stat[0x5a]) val &= ~0x04;        // Z
338                                 if(key_stat[0x45]) val &= ~0x08;        // E
339                                 if(key_stat[0x33]) val &= ~0x10;        // 3
340                                 break;
341                         case 8:
342                                 if(key_stat[0x10]) val &= ~0x02;        // LSHIFT
343                                 if(key_stat[0x12]) val &= ~0x04;        // GRAPH
344                                 if(key_stat[0x31]) val &= ~0x08;        // 1
345                                 if(key_stat[0x32]) val &= ~0x10;        // 2
346                                 break;
347                         case 9:
348                                 if(key_stat[0x28]) val &= ~0x02;        // DOWN
349                                 if(key_stat[0x20]) val &= ~0x04;        // SPACE
350                                 if(key_stat[0x2e]) val &= ~0x08;        // DEL
351                                 if(key_stat[0x2d]) val &= ~0x10;        // INS
352                                 break;
353                         }
354                 }
355                 return val;
356         } else if(addr < 0x6000) {
357                 if(header.mapper() == 5) {
358                         return mmc5_lo_read(addr);
359 //              } else if(header.mapper() == 85) {
360 //                      return vrc7_lo_read(addr);
361                 } else {
362                         return 0xff;
363                 }
364         } else if(addr < 0x8000) {
365 //              if(header.mapper() == 5) {
366 //                      return mmc5_save_read(addr);
367 //              } else if(header.mapper() == 85) {
368 //                      return vrc7_save_read(addr);
369 //              } else {
370                         return bank_ptr[3][addr & 0x1fff];
371 //              }
372         } else if(addr < 0xa000) {
373                 return bank_ptr[4][addr & 0x1fff];
374         } else if(addr < 0xc000) {
375                 return bank_ptr[5][addr & 0x1fff];
376         } else if(addr < 0xe000) {
377                 return bank_ptr[6][addr & 0x1fff];
378         } else {
379                 return bank_ptr[7][addr & 0x1fff];
380         }
381 }
382
383 void MEMORY::event_vline(int v, int clock)
384 {
385         // 525 -> 262.5
386         if(v & 1) {
387                 return;
388         }
389         v >>= 1;
390         
391         // fram irq
392         if(v == 240 && !(frame_irq_enabled & 0xc0)) {
393                 // pending
394                 d_cpu->write_signal(SIG_CPU_IRQ, 1, 1);
395         }
396         
397         // mapper irq
398         if(header.mapper() == 5) {
399                 mmc5_hsync(v);
400         } else if(header.mapper() == 85) {
401                 vrc7_hsync(v);
402         }
403 }
404
405 void MEMORY::event_callback(int event_id, int err)
406 {
407         // dma done
408         d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
409 }
410
411 void MEMORY::set_rom_bank(uint8_t bank, uint32_t bank_num)
412 {
413         bank_ptr[bank] = rom + 0x2000 * (bank_num & rom_mask);
414         banks[bank] = bank_num;
415         
416         // mmc5
417         mmc5_wram_bank[bank] = 8;
418 }
419
420 // mmc5
421
422 void MEMORY::mmc5_reset()
423 {
424         if(header.mapper() == 5) {
425                 mmc5_set_wram_bank(3, 0);
426                 set_rom_bank(4, header.num_8k_rom_banks() - 1);
427                 set_rom_bank(5, header.num_8k_rom_banks() - 1);
428                 set_rom_bank(6, header.num_8k_rom_banks() - 1);
429                 set_rom_bank(7, header.num_8k_rom_banks() - 1);
430                 
431                 for(int i = 0; i < 8; i++) {
432                         mmc5_chr_reg[i][0] = i;
433                         mmc5_chr_reg[i][1] = (i & 0x03) + 4;
434                 }
435                 mmc5_wram_protect0 = 0x02;
436                 mmc5_wram_protect1 = 0x01;
437                 mmc5_prg_size = 3;
438                 mmc5_chr_size = 3;
439                 mmc5_gfx_mode = 0;
440 //              mmc5_split_control = 0;
441 //              mmc5_split_bank = 0;
442                 mmc5_irq_enabled = 0;
443                 mmc5_irq_status = 0;
444                 mmc5_irq_line = 0;
445         }
446 }
447
448 uint32_t MEMORY::mmc5_lo_read(uint32_t addr)
449 {
450         uint8_t data = (uint8_t)(addr >> 8);
451         
452         if(addr == 0x5204) {
453                 data = mmc5_irq_status;
454                 mmc5_irq_status &= ~0x80;
455         } else if(addr == 0x5205) {
456                 data = (uint8_t)(((mmc5_value0 * mmc5_value1) & 0x00ff) >> 0);
457         } else if(addr == 0x5206) {
458                 data = (uint8_t)(((mmc5_value0 * mmc5_value1) & 0xff00) >> 8);
459         } else if(addr >= 0x5c00 && addr < 0x6000) {
460                 if(mmc5_gfx_mode == 2 || mmc5_gfx_mode == 3) {
461                         data = (d_ppu->get_name_tables() + 0x800)[addr & 0x3ff];
462                 }
463         }
464         return data;
465 }
466
467 void MEMORY::mmc5_lo_write(uint32_t addr, uint32_t data)
468 {
469         switch(addr) {
470         case 0x5100:
471                 mmc5_prg_size = data & 0x03;
472                 break;
473         case 0x5101:
474                 mmc5_chr_size = data & 0x03;
475                 break;
476         case 0x5102:
477                 mmc5_wram_protect0 = data & 0x03;
478                 break;
479         case 0x5103:
480                 mmc5_wram_protect1 = data & 0x03;
481                 break;
482         case 0x5104:
483                 mmc5_gfx_mode = data & 0x03;
484                 break;
485         case 0x5105:
486                 for(int i = 0; i < 4; i++) {
487                         d_ppu->set_ppu_bank(8 + i, data & 0x03);
488                         data >>= 2;
489                 }
490                 break;
491         case 0x5106:
492                 for(int i = 0; i < 0x3c0; i++) {
493                         (d_ppu->get_name_tables() + 0xc00)[i] = data;
494                 }
495                 break;
496         case 0x5107:
497                 for(int i = 0x3c0; i < 0x400; i++) {
498                         (d_ppu->get_name_tables() + 0xc00)[i] = 0x55 * (data & 3);
499                 }
500                 break;
501         case 0x5113:
502                 mmc5_set_wram_bank(3, data & 0x07);
503                 break;
504         case 0x5114:
505         case 0x5115:
506         case 0x5116:
507         case 0x5117:
508                 mmc5_set_cpu_bank(addr & 0x07, data);
509                 break;
510         case 0x5120:
511         case 0x5121:
512         case 0x5122:
513         case 0x5123:
514         case 0x5124:
515         case 0x5125:
516         case 0x5126:
517         case 0x5127:
518                 mmc5_chr_reg[addr & 0x07][0] = data;
519                 mmc5_set_ppu_bank(0);
520                 break;
521         case 0x5128:
522         case 0x5129:
523         case 0x512a:
524         case 0x512b:
525                 mmc5_chr_reg[(addr & 0x03) + 0][1] = data;
526                 mmc5_chr_reg[(addr & 0x03) + 4][1] = data;
527                 break;
528         case 0x5200:
529 //              mmc5_split_control = data;
530                 break;
531         case 0x5201:
532 //              mmc5_split_scroll = data;
533                 break;
534         case 0x5202:
535 //              mmc5_split_bank = data & 0x3f;
536                 break;
537         case 0x5203:
538                 mmc5_irq_line = data;
539                 break;
540         case 0x5204:
541                 mmc5_irq_enabled = data;
542                 break;
543         case 0x5205:
544                 mmc5_value0 = data;
545                 break;
546         case 0x5206:
547                 mmc5_value1 = data;
548                 break;
549         default:
550                 if(addr >= 0x5000 && addr <= 0x5015) {
551 //                      d_mmc5->write_io8(addr, data);
552                 } else if(addr >= 0x5c00 && addr <= 0x5fff) {
553                         if(mmc5_gfx_mode != 3) {
554                                 (d_ppu->get_name_tables() + 0x800)[addr & 0x3ff] = data; //(mmc5_irq_status & 0) ? data : 0x40;
555                         }
556                 }
557                 break;
558         }
559 }
560
561 //uint32_t MEMORY::mmc5_save_read(uint32_t addr)
562 //{
563 //      return bank_ptr[3][addr & 0x1fff];
564 //}
565
566 void MEMORY::mmc5_save_write(uint32_t addr, uint32_t data)
567 {
568         if(mmc5_wram_protect0 == 0x02 && mmc5_wram_protect1 == 0x01) {
569                 if(mmc5_wram_bank[3] < 8) {
570                         bank_ptr[3][addr & 0x1fff] = data;
571                 }
572         }
573 }
574
575 void MEMORY::mmc5_hi_write(uint32_t addr, uint32_t data)
576 {
577         if(mmc5_wram_protect0 == 0x02 && mmc5_wram_protect1 == 0x01) {
578                 if(addr < 0xa000) {
579                         if(mmc5_wram_bank[4] < 8) {
580                                 bank_ptr[4][addr & 0x1fff] = data;
581                         }
582                 } else if(addr < 0xc000) {
583                         if(mmc5_wram_bank[5] < 8) {
584                                 bank_ptr[5][addr & 0x1fff] = data;
585                         }
586                 } else if(addr < 0xe000) {
587                         if(mmc5_wram_bank[6] < 8) {
588                                 bank_ptr[6][addr & 0x1fff] = data;
589                         }
590                 } else {
591                         if(mmc5_wram_bank[7] < 8) {
592                                 bank_ptr[7][addr & 0x1fff] = data;
593                         }
594                 }
595         }
596 }
597
598 void MEMORY::mmc5_hsync(int v)
599 {
600         if(v <= 240) {
601                 if(v == mmc5_irq_line) {
602                         if(d_ppu->spr_enabled() && d_ppu->bg_enabled()) {
603                                 mmc5_irq_status |= 0x80;
604                         }
605                 }
606                 if((mmc5_irq_status & 0x80) && (mmc5_irq_enabled & 0x80)) {
607                         d_cpu->write_signal(SIG_CPU_IRQ, 1, 1);
608                 }
609         } else {
610                 mmc5_irq_status |= 0x40;
611         }
612 }
613
614 void MEMORY::mmc5_set_cpu_bank(uint8_t bank, uint32_t bank_num)
615 {
616         if(bank_num & 0x80) {
617                 if(mmc5_prg_size == 0) {
618                         if(bank == 7) {
619                                 set_rom_bank(4, (bank_num & 0x7c) + 0);
620                                 set_rom_bank(5, (bank_num & 0x7c) + 1);
621                                 set_rom_bank(6, (bank_num & 0x7c) + 2);
622                                 set_rom_bank(7, (bank_num & 0x7c) + 3);
623                         }
624                 } else if(mmc5_prg_size == 1) {
625                         if(bank == 5) {
626                                 set_rom_bank(4, (bank_num & 0x7e) + 0);
627                                 set_rom_bank(5, (bank_num & 0x7e) + 1);
628                         } else if(bank == 7) {
629                                 set_rom_bank(6, (bank_num & 0x7e) + 0);
630                                 set_rom_bank(7, (bank_num & 0x7e) + 1);
631                         }
632                 } else if(mmc5_prg_size == 2) {
633                         if(bank == 5) {
634                                 set_rom_bank(4, (bank_num & 0x7e) + 0);
635                                 set_rom_bank(5, (bank_num & 0x7e) + 1);
636                         } else if(bank == 6) {
637                                 set_rom_bank(6, bank_num & 0x7f);
638                         } else if(bank == 7) {
639                                 set_rom_bank(7, bank_num & 0x7f);
640                         }
641                 } else if(mmc5_prg_size == 3) {
642                         if(bank == 4) {
643                                 set_rom_bank(4, bank_num & 0x7f);
644                         } else if(bank == 5) {
645                                 set_rom_bank(5, bank_num & 0x7f);
646                         } else if(bank == 6) {
647                                 set_rom_bank(6, bank_num & 0x7f);
648                         } else if(bank == 7) {
649                                 set_rom_bank(7, bank_num & 0x7f);
650                         }
651                 }
652         } else {
653                 if(mmc5_prg_size == 1) {
654                         if(bank == 5) {
655                                 mmc5_set_wram_bank(4, (bank_num & 0x06)+0);
656                                 mmc5_set_wram_bank(5, (bank_num & 0x06)+1);
657                         }
658                 } else if(mmc5_prg_size == 2) {
659                         if(bank == 5) {
660                                 mmc5_set_wram_bank(4, (bank_num & 0x06)+0);
661                                 mmc5_set_wram_bank(5, (bank_num & 0x06)+1);
662                         } else  if(bank == 6)
663                         {
664                                 mmc5_set_wram_bank(6, bank_num & 0x07);
665                         }
666                 } else if(mmc5_prg_size == 3) {
667                         if(bank == 4) {
668                                 mmc5_set_wram_bank(4, bank_num & 0x07);
669                         } else if(bank == 5) {
670                                 mmc5_set_wram_bank(5, bank_num & 0x07);
671                         } else if(bank == 6) {
672                                 mmc5_set_wram_bank(6, bank_num & 0x07);
673                         }
674                 }
675         }
676 }
677
678 void MEMORY::mmc5_set_wram_bank(uint8_t bank, uint32_t bank_num)
679 {
680         if(bank_num < 8) {
681                 bank_ptr[bank] = save_ram + 0x2000 * bank_num;
682                 mmc5_wram_bank[bank] = bank_num;
683         } else {
684                 set_rom_bank(bank, banks[bank]);
685         }
686 }
687
688 void MEMORY::mmc5_set_ppu_bank(uint8_t mode)
689 {
690         if(mmc5_chr_size == 0) {
691                 d_ppu->set_ppu_bank(0, mmc5_chr_reg[7][mode] * 8 + 0);
692                 d_ppu->set_ppu_bank(1, mmc5_chr_reg[7][mode] * 8 + 1);
693                 d_ppu->set_ppu_bank(2, mmc5_chr_reg[7][mode] * 8 + 2);
694                 d_ppu->set_ppu_bank(3, mmc5_chr_reg[7][mode] * 8 + 3);
695                 d_ppu->set_ppu_bank(4, mmc5_chr_reg[7][mode] * 8 + 4);
696                 d_ppu->set_ppu_bank(5, mmc5_chr_reg[7][mode] * 8 + 5);
697                 d_ppu->set_ppu_bank(6, mmc5_chr_reg[7][mode] * 8 + 6);
698                 d_ppu->set_ppu_bank(7, mmc5_chr_reg[7][mode] * 8 + 7);
699         } else if(mmc5_chr_size == 1) {
700                 d_ppu->set_ppu_bank(0, mmc5_chr_reg[3][mode] * 4 + 0);
701                 d_ppu->set_ppu_bank(1, mmc5_chr_reg[3][mode] * 4 + 1);
702                 d_ppu->set_ppu_bank(2, mmc5_chr_reg[3][mode] * 4 + 2);
703                 d_ppu->set_ppu_bank(3, mmc5_chr_reg[3][mode] * 4 + 3);
704                 d_ppu->set_ppu_bank(4, mmc5_chr_reg[7][mode] * 4 + 0);
705                 d_ppu->set_ppu_bank(5, mmc5_chr_reg[7][mode] * 4 + 1);
706                 d_ppu->set_ppu_bank(6, mmc5_chr_reg[7][mode] * 4 + 2);
707                 d_ppu->set_ppu_bank(7, mmc5_chr_reg[7][mode] * 4 + 3);
708         } else if(mmc5_chr_size == 2) {
709                 d_ppu->set_ppu_bank(0, mmc5_chr_reg[1][mode] * 2 + 0);
710                 d_ppu->set_ppu_bank(1, mmc5_chr_reg[1][mode] * 2 + 1);
711                 d_ppu->set_ppu_bank(2, mmc5_chr_reg[3][mode] * 2 + 0);
712                 d_ppu->set_ppu_bank(3, mmc5_chr_reg[3][mode] * 2 + 1);
713                 d_ppu->set_ppu_bank(4, mmc5_chr_reg[5][mode] * 2 + 0);
714                 d_ppu->set_ppu_bank(5, mmc5_chr_reg[5][mode] * 2 + 1);
715                 d_ppu->set_ppu_bank(6, mmc5_chr_reg[7][mode] * 2 + 0);
716                 d_ppu->set_ppu_bank(7, mmc5_chr_reg[7][mode] * 2 + 1);
717         } else {
718                 d_ppu->set_ppu_bank(0, mmc5_chr_reg[0][mode]);
719                 d_ppu->set_ppu_bank(1, mmc5_chr_reg[1][mode]);
720                 d_ppu->set_ppu_bank(2, mmc5_chr_reg[2][mode]);
721                 d_ppu->set_ppu_bank(3, mmc5_chr_reg[3][mode]);
722                 d_ppu->set_ppu_bank(4, mmc5_chr_reg[4][mode]);
723                 d_ppu->set_ppu_bank(5, mmc5_chr_reg[5][mode]);
724                 d_ppu->set_ppu_bank(6, mmc5_chr_reg[6][mode]);
725                 d_ppu->set_ppu_bank(7, mmc5_chr_reg[7][mode]);
726         }
727 }
728
729 uint8_t MEMORY::mmc5_ppu_latch_render(uint8_t mode, uint32_t addr)
730 {
731         uint8_t data = 0;
732         
733         if(mmc5_gfx_mode == 1 && mode == 1) {
734                 // ex gfx mode
735                 uint32_t bank_num = ((d_ppu->get_name_tables() + 0x800)[addr] & 0x3f) << 2;
736                 d_ppu->set_ppu_bank(0, bank_num + 0);
737                 d_ppu->set_ppu_bank(1, bank_num + 1);
738                 d_ppu->set_ppu_bank(2, bank_num + 2);
739                 d_ppu->set_ppu_bank(3, bank_num + 3);
740                 d_ppu->set_ppu_bank(4, bank_num + 0);
741                 d_ppu->set_ppu_bank(5, bank_num + 1);
742                 d_ppu->set_ppu_bank(6, bank_num + 2);
743                 d_ppu->set_ppu_bank(7, bank_num + 3);
744                 data = (((d_ppu->get_name_tables() + 0x800)[addr] & 0xc0) >> 4) | 0x01;
745         } else {
746                 // normal
747                 mmc5_set_ppu_bank(mode);
748         }
749         return data;
750 }
751
752 // vrc7
753
754 void MEMORY::vrc7_reset()
755 {
756         if(header.mapper() == 85) {
757                 vrc7_irq_enabled = 0;
758                 vrc7_irq_counter = 0;
759                 vrc7_irq_latch = 0;
760                 d_opll->write_signal(SIG_YM2413_MUTE, 0, 0);
761                 set_rom_bank(4, 0);
762                 set_rom_bank(5, 1);
763                 set_rom_bank(6, header.num_8k_rom_banks() - 2);
764                 set_rom_bank(7, header.num_8k_rom_banks() - 1);
765         } else {
766                 d_opll->write_signal(SIG_YM2413_MUTE, 1, 1);
767         }
768 }
769
770 //uint32_t MEMORY::vrc7_lo_read(uint32_t addr)
771 //{
772 //      return 0xff;
773 //}
774
775 //void MEMORY::vrc7_lo_write(uint32_t addr, uint32_t data)
776 //{
777 //}
778
779 //uint32_t MEMORY::vrc7_save_read(uint32_t addr)
780 //{
781 //      return bank_ptr[3][addr & 0x1fff];
782 //}
783
784 //void MEMORY::vrc7_save_write(uint32_t addr, uint32_t data)
785 //{
786 //      bank_ptr[3][addr & 0x1fff] = data;
787 //}
788
789 void MEMORY::vrc7_hi_write(uint32_t addr, uint32_t data)
790 {
791         switch(addr & 0xf038) {
792         case 0x8000:
793                 set_rom_bank(4, data);
794                 break;
795         case 0x8008:
796         case 0x8010:
797                 set_rom_bank(5, data);
798                 break;
799         case 0x9000:
800                 set_rom_bank(6, data);
801                 break;
802         case 0x9010:
803         case 0x9030:
804                 d_opll->write_io8(addr >> 5, data);
805                 break;
806         case 0xa000:
807                 d_ppu->set_ppu_bank(0, data);
808                 break;
809         case 0xa008:
810         case 0xa010:
811                 d_ppu->set_ppu_bank(1, data);
812                 break;
813         case 0xb000:
814                 d_ppu->set_ppu_bank(2, data);
815                 break;
816         case 0xb008:
817         case 0xb010:
818                 d_ppu->set_ppu_bank(3, data);
819                 break;
820         case 0xc000:
821                 d_ppu->set_ppu_bank(4, data);
822                 break;
823         case 0xc008:
824         case 0xc010:
825                 d_ppu->set_ppu_bank(5, data);
826                 break;
827         case 0xd000:
828                 d_ppu->set_ppu_bank(6, data);
829                 break;
830         case 0xd008:
831         case 0xd010:
832                 d_ppu->set_ppu_bank(7, data);
833                 break;
834         case 0xe000:
835                 switch(data & 0x03) {
836                 case 0x00:
837                         d_ppu->set_mirroring(MIRROR_VERT);
838                         break;
839                 case 0x01:
840                         d_ppu->set_mirroring(MIRROR_HORIZ);
841                         break;
842                 case 0x02:
843                         d_ppu->set_mirroring(0, 0, 0, 0);
844                         break;
845                 case 0x03:
846                         d_ppu->set_mirroring(1, 1, 1, 1);
847                         break;
848                 }
849                 break;
850         case 0xe008:
851         case 0xe010:
852                 vrc7_irq_latch = data;
853                 break;
854         case 0xf000:
855                 if(data & 0x02) {
856                         vrc7_irq_counter = vrc7_irq_latch;
857                 }
858                 vrc7_irq_enabled = data & 0x03;
859                 break;
860         case 0xf008:
861         case 0xf010:
862                 vrc7_irq_enabled = (vrc7_irq_enabled & 0x01) * 3;
863                 break;
864         }
865 }
866
867 void MEMORY::vrc7_hsync(int v)
868 {
869         if(vrc7_irq_enabled & 0x02) {
870                 if(vrc7_irq_counter == 0xff) {
871                         d_cpu->write_signal(SIG_CPU_IRQ, 1, 1);
872                         vrc7_irq_counter = vrc7_irq_latch;
873                 } else {
874                         vrc7_irq_counter++;
875                 }
876         }
877 }
878
879 #define STATE_VERSION   2
880
881 bool MEMORY::process_state(FILEIO* state_fio, bool loading)
882 {
883         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
884                 return false;
885         }
886         if(!state_fio->StateCheckInt32(this_device_id)) {
887                 return false;
888         }
889         state_fio->StateBuffer(save_file_name, sizeof(save_file_name), 1);
890         state_fio->StateBuffer(&header, sizeof(header), 1); // OK?
891         state_fio->StateUint32(rom_size);
892 //      state_fio->StateUint32(rom_mask);
893         if(loading) {
894                 rom_mask = (rom_size / 0x2000) - 1;
895                 if(rom != NULL) {
896                         free(rom);
897                 }
898                 rom = (uint8_t *)malloc(rom_size);
899         }
900         state_fio->StateBuffer(rom, rom_size, 1);
901         state_fio->StateBuffer(ram, sizeof(ram), 1);
902         state_fio->StateBuffer(save_ram, sizeof(save_ram), 1);
903         state_fio->StateUint32(save_ram_crc32);
904         //state_fio->StateBuffer(banks, sizeof(banks), 1);
905         for(int i = 0; i < (sizeof(banks) / sizeof(uint32_t)); i++) {
906                 state_fio->StateUint32(banks[i]);
907         }
908         state_fio->StateUint16(dma_addr);
909         state_fio->StateUint8(frame_irq_enabled);
910         //state_fio->StateBuffer(mmc5_wram_bank, sizeof(mmc5_wram_bank), 1);
911         for(int i = 0; i < (sizeof(mmc5_wram_bank) / sizeof(uint32_t)); i++) {
912                 state_fio->StateUint32(mmc5_wram_bank[i]);
913         }
914         state_fio->StateBuffer(mmc5_chr_reg, sizeof(mmc5_chr_reg), 1);
915         state_fio->StateUint32(mmc5_value0);
916         state_fio->StateUint32(mmc5_value0);
917         state_fio->StateUint8(mmc5_wram_protect0);
918         state_fio->StateUint8(mmc5_wram_protect1);
919         state_fio->StateUint8(mmc5_prg_size);
920         state_fio->StateUint8(mmc5_chr_size);
921         state_fio->StateUint8(mmc5_gfx_mode);
922 //      state_fio->StateUint8(mmc5_split_control);
923 //      state_fio->StateUint8(mmc5_split_bank);
924         state_fio->StateUint8(mmc5_irq_enabled);
925         state_fio->StateUint8(mmc5_irq_status);
926         state_fio->StateUint32(mmc5_irq_line);
927         state_fio->StateUint8(vrc7_irq_enabled);
928         state_fio->StateUint8(vrc7_irq_counter);
929         state_fio->StateUint8(vrc7_irq_latch);
930         state_fio->StateBool(pad_strobe);
931         state_fio->StateUint8(pad1_bits);
932         state_fio->StateUint8(pad2_bits);
933         state_fio->StateBool(kb_out);
934         state_fio->StateUint8(kb_scan);
935         
936         // post process
937         if(loading) {
938                 if(header.mapper() == 5) {
939                         for(int i = 3; i < 8; i++) {
940                                 mmc5_set_wram_bank(i, mmc5_wram_bank[i]);
941                         }
942                 } else {
943                         for(int i = 4; i < 8; i++) {
944                                 set_rom_bank(i, banks[i]);
945                         }
946                         bank_ptr[3] = save_ram;
947                 }
948         }
949         return true;
950 }
951
952 }