OSDN Git Service

[VM][Qt][OSD][Genaral] Sync to upstream ; phase 1: Merege upstream 20151217.
[csp-qt/common_source_project-fm7.git] / source / src / vm / familybasic / ppu.cpp
1 /*
2         Nintendo Family BASIC Emulator 'eFamilyBASIC'
3
4         Origin : nester
5         Author : Takeda.Toshiya
6         Date   : 2010.08.11-
7
8         [ PPU ]
9 */
10
11 #include "ppu.h"
12
13 static const uint8 palette[64][3] = {
14         {0x75, 0x75, 0x75}, {0x27, 0x1b, 0x8f}, {0x00, 0x00, 0xab}, {0x47, 0x00, 0x9f},
15         {0x8f, 0x00, 0x77}, {0xab, 0x00, 0x13}, {0xa7, 0x00, 0x00}, {0x7f, 0x0b, 0x00},
16         {0x43, 0x2f, 0x00}, {0x00, 0x47, 0x00}, {0x00, 0x51, 0x00}, {0x00, 0x3f, 0x17},
17         {0x1b, 0x3f, 0x5f}, {0x00, 0x00, 0x00}, {0x05, 0x05, 0x05}, {0x05, 0x05, 0x05},
18         {0xbc, 0xbc, 0xbc}, {0x00, 0x73, 0xef}, {0x23, 0x3b, 0xef}, {0x83, 0x00, 0xf3},
19         {0xbf, 0x00, 0xbf}, {0xe7, 0x00, 0x5b}, {0xdb, 0x2b, 0x00}, {0xcb, 0x4f, 0x0f},
20         {0x8b, 0x73, 0x00}, {0x00, 0x97, 0x00}, {0x00, 0xab, 0x00}, {0x00, 0x93, 0x3b},
21         {0x00, 0x83, 0x8b}, {0x11, 0x11, 0x11}, {0x09, 0x09, 0x09}, {0x09, 0x09, 0x09},
22         {0xff, 0xff, 0xff}, {0x3f, 0xbf, 0xff}, {0x5f, 0x97, 0xff}, {0xa7, 0x8b, 0xfd},
23         {0xf7, 0x7b, 0xff}, {0xff, 0x77, 0xb7}, {0xff, 0x77, 0x63}, {0xff, 0x9b, 0x3b},
24         {0xf3, 0xbf, 0x3f}, {0x83, 0xd3, 0x13}, {0x4f, 0xdf, 0x4b}, {0x58, 0xf8, 0x98},
25         {0x00, 0xeb, 0xdb}, {0x66, 0x66, 0x66}, {0x0d, 0x0d, 0x0d}, {0x0d, 0x0d, 0x0d},
26         {0xff, 0xff, 0xff}, {0xab, 0xe7, 0xff}, {0xc7, 0xd7, 0xff}, {0xd7, 0xcb, 0xff},
27         {0xff, 0xc7, 0xff}, {0xff, 0xc7, 0xdb}, {0xff, 0xbf, 0xb3}, {0xff, 0xdb, 0xab},
28         {0xff, 0xe7, 0xa3}, {0xe3, 0xff, 0xa3}, {0xab, 0xf3, 0xbf}, {0xb3, 0xff, 0xcf},
29         {0x9f, 0xff, 0xf3}, {0xdd, 0xdd, 0xdd}, {0x11, 0x11, 0x11}, {0x11, 0x11, 0x11}
30 };
31
32 #define VRAM(addr)      banks[((addr) >> 10) & 0x0f][(addr) & 0x3ff]
33
34 #define NMI_enabled()   (regs[0] & 0x80)
35 #define sprites_8x16()  (regs[0] & 0x20)
36 #define spr_enabled()   (regs[1] & 0x10)
37 #define bg_enabled()    (regs[1] & 0x08)
38 #define spr_clip()      (!(regs[1] & 0x04))
39 #define bg_clip()       (!(regs[1] & 0x02))
40 #define monochrome()    (regs[1] & 0x01)
41 #define rgb_pal()       (regs[1] & 0xe0)
42 #define sprite0_hit()   (regs[2] & 0x40)
43
44 #define LOOPY_SCANLINE_START(v, t) { \
45         v = (v & 0xfbe0) | (t & 0x041f); \
46 }
47
48 #define LOOPY_NEXT_LINE(v) { \
49         if((v & 0x7000) == 0x7000) { \
50                 v &= 0x8fff; \
51                 if((v & 0x3e0) == 0x3a0) { \
52                         v ^= 0x0800; \
53                         v &= 0xfc1f; \
54                 } else { \
55                         if((v & 0x3e0) == 0x3e0) { \
56                                 v &= 0xfc1f; \
57                         } else { \
58                                 v += 0x20; \
59                         } \
60                 } \
61         } else { \
62                 v += 0x1000; \
63         } \
64 }
65
66 #define LOOPY_NEXT_TILE(v) { \
67         if((v & 0x1f) == 0x1f) { \
68                 v ^= 0x0400; \
69                 v &= 0xffe0; \
70         } else { \
71                 v++; \
72         } \
73 }
74
75 #define LOOPY_NEXT_PIXEL(v, x) { \
76         if(x == 7) { \
77                 LOOPY_NEXT_TILE(v); \
78                 x = 0; \
79         } else { \
80                 x++; \
81         } \
82 }
83
84 void PPU::initialize()
85 {
86         // register event
87         register_vline_event(this);
88 }
89
90 void PPU::load_rom_image(const _TCHAR *file_name)
91 {
92         FILEIO* fio = new FILEIO();
93         bool file_open = false;
94         
95         if(fio->Fopen(create_local_path(file_name), FILEIO_READ_BINARY)) {
96                 file_open = true;
97         } else if(fio->Fopen(create_local_path(_T("BASIC.NES")), FILEIO_READ_BINARY)) {
98                 // for compatibility
99                 file_open = true;
100         }
101         if(file_open) {
102                 // read header
103                 fio->Fread(header, sizeof(header), 1);
104                 // skip program rom
105                 fio->Fseek(header[4] * 0x4000, FILEIO_SEEK_CUR);
106                 // read chr rom (max 8kb)
107                 fio->Fread(chr_rom, sizeof(chr_rom), 1);
108                 fio->Fclose();
109         } else {
110                 memset(header, 0, sizeof(header));
111                 memset(chr_rom, 0xff, sizeof(chr_rom));
112         }
113         delete fio;
114 }
115
116 void PPU::reset()
117 {
118         // set up PPU memory space table
119         for(int i = 0; i < 8; i++) {
120                 banks[i] = chr_rom + 0x400 * i;
121         }
122         
123         // set mirroring
124 #if 0
125         if(header[6] & 8) {
126                 // 4 screen mirroring
127                 banks[ 8] = banks[12] = name_tables;
128                 banks[ 9] = banks[13] = name_tables + 0x400;
129                 banks[10] = banks[14] = name_tables + 0x800;
130                 banks[11] = banks[15] = name_tables + 0xc00;
131         } else if(header[6] & 1) {
132 #endif
133                 // vertical mirroring
134                 banks[ 8] = banks[10] = banks[12] = banks[14] = name_tables;
135                 banks[ 9] = banks[11] = banks[13] = banks[15] = name_tables + 0x400;
136 #if 0
137         } else {
138                 // horizontal mirroring
139                 banks[ 8] = banks[ 9] = banks[12] = banks[13] = name_tables;
140                 banks[10] = banks[11] = banks[14] = banks[15] = name_tables + 0x400;
141         }
142 #endif
143         
144         memset(bg_pal, 0, sizeof(bg_pal));
145         memset(spr_pal, 0, sizeof(spr_pal));
146         memset(solid_buf, 0, sizeof(solid_buf));
147         memset(name_tables, 0, sizeof(name_tables));
148         
149         memset(spr_ram, 0, sizeof(spr_ram));
150         spr_ram_rw_ptr = 0;
151         
152         memset(regs, 0, sizeof(regs));
153         bg_pattern_table_addr = 0;
154         spr_pattern_table_addr = 0;
155         ppu_addr_inc = 0;
156         rgb_bak = 0;
157         toggle_2005_2006 = false;
158         read_2007_buffer = 0;
159         
160         loopy_v = 0;
161         loopy_t = 0;
162         loopy_x = 0;
163         
164         // reset emphasised palette
165         update_palette();
166 }
167
168 void PPU::write_data8(uint32 addr, uint32 data)
169 {
170         uint16 ofs;
171         
172         regs[addr & 7] = data;
173         
174         switch(addr & 0xe007) {
175         case 0x2000:
176                 bg_pattern_table_addr = (data & 0x10) ? 0x1000 : 0;
177                 spr_pattern_table_addr = (data & 0x08) ? 0x1000 : 0;
178                 ppu_addr_inc = (data & 0x04) ? 32 : 1;
179                 loopy_t = (loopy_t & 0xf3ff) | (((uint16)(data & 0x03)) << 10);
180                 break;
181         case 0x2001:
182                 if(rgb_bak != (data & 0xe0)) {
183                         update_palette();
184                         rgb_bak = data & 0xe0;
185                 }
186                 break;
187         case 0x2003:
188                 spr_ram_rw_ptr = data;
189                 break;
190         case 0x2004:
191                 spr_ram[spr_ram_rw_ptr++] = data;
192                 break;
193         case 0x2005:
194                 toggle_2005_2006 = !toggle_2005_2006;
195                 if(toggle_2005_2006) {
196                         // first write
197                         loopy_t = (loopy_t & 0xffe0) | (((uint16)(data & 0xf8)) >> 3);
198                         loopy_x = data & 0x07;
199                 } else {
200                         // second write
201                         loopy_t = (loopy_t & 0xfc1f) | (((uint16)(data & 0xf8)) << 2);
202                         loopy_t = (loopy_t & 0x8fff) | (((uint16)(data & 0x07)) << 12);
203                 }
204                 break;
205         case 0x2006:
206                 toggle_2005_2006 = !toggle_2005_2006;
207                 if(toggle_2005_2006) {
208                         // first write
209                         loopy_t = (loopy_t & 0x00ff) | (((uint16)(data & 0x3f)) << 8);
210                 } else {
211                         // second write
212                         loopy_t = (loopy_t & 0xff00) | ((uint16)data);
213                         loopy_v = loopy_t;
214                 }
215                 break;
216         case 0x2007:
217                 ofs = loopy_v & 0x3fff;
218                 loopy_v += ppu_addr_inc;
219                 if(ofs >= 0x3000) {
220                         // is it a palette entry?
221                         if(ofs >= 0x3f00) {
222                                 data &= 0x3f;
223                                 if(!(ofs & 0x000f)) {
224                                         bg_pal[0] = spr_pal[0] = data;
225                                 } else if(!(ofs & 0x10)) {
226                                         bg_pal[ofs & 0x000f] = data;
227                                 } else {
228                                         spr_pal[ofs & 0x000f] = data;
229                                 }
230                                 break;
231                         }
232                         // handle mirroring
233                         ofs &= 0xefff;
234                 }
235                 if(ofs >= 0x2000) {
236                         VRAM(ofs) = data;
237                 }
238                 break;
239         }
240 }
241
242 uint32 PPU::read_data8(uint32 addr)
243 {
244         uint16 ofs;
245         uint8 val;
246         
247         switch(addr & 0xe007) {
248         case 0x2002:
249                 // clear toggle
250                 toggle_2005_2006 = false;
251                 val = regs[2];
252                 // clear v-blank flag
253                 regs[2] &= ~0x80;
254                 return val;
255         case 0x2007:
256                 ofs = loopy_v & 0x3fff;
257                 loopy_v += ppu_addr_inc;
258                 if(ofs >= 0x3000) {
259                         // is it a palette entry?
260                         if(ofs >= 0x3f00) {
261                                 if(!(ofs & 0x0010)) {
262                                         return bg_pal[ofs & 0x000f];
263                                 } else {
264                                         return spr_pal[ofs & 0x000f];
265                                 }
266                         }
267                         // handle mirroring
268                         ofs &= 0xefff;
269                 }
270                 val = read_2007_buffer;
271                 read_2007_buffer = VRAM(ofs);
272                 return val;
273         }
274         return regs[addr & 7];
275 }
276
277 void PPU::event_vline(int v, int clock)
278 {
279         switch(v) {
280         case 0:
281                 if(spr_enabled() || bg_enabled()) {
282                         loopy_v = loopy_t;
283                 }
284                 break;
285         case 241:
286                 // set vblank register flag
287                 regs[2] |= 0x80;
288                 if(NMI_enabled()) {
289                         d_cpu->write_signal(SIG_CPU_NMI, 1, 1);
290                 }
291                 break;
292         case 261:
293                 // reset vblank register flag and sprite0 hit flag1
294                 regs[2] &= 0x3F;
295                 break;
296         }
297         if(v < 240) {
298                 render_scanline(v);
299         }
300 }
301
302 void PPU::draw_screen()
303 {
304         
305         for(int y = 0; y < 240; y++) {
306                 scrntype* dest = emu->screen_buffer(y);
307                 uint8* src = screen[y];
308                 
309                 for(int x = 0; x < 256; x++) {
310                         dest[x] = palette_pc[src[x + 8] & 0x3f];
311                 }
312         }
313 }
314
315 void PPU::update_palette()
316 {
317         for(int i = 0; i < 64; i++) {
318                 uint8 r = palette[i][0];
319                 uint8 g = palette[i][1];
320                 uint8 b = palette[i][2];
321                 
322                 switch(rgb_pal()) {
323                 case 0x20:
324                         g = (uint8)(g * 0.80);
325                         b = (uint8)(b * 0.73);
326                         break;
327                 case 0x40:
328                         r = (uint8)(r * 0.73);
329                         b = (uint8)(b * 0.70);
330                         break;
331                 case 0x60:
332                         r = (uint8)(r * 0.76);
333                         g = (uint8)(g * 0.78);
334                         b = (uint8)(b * 0.58);
335                         break;
336                 case 0x80:
337                         r = (uint8)(r * 0.86);
338                         g = (uint8)(g * 0.80);
339                         break;
340                 case 0xa0:
341                         r = (uint8)(r * 0.83);
342                         g = (uint8)(g * 0.68);
343                         b = (uint8)(b * 0.85);
344                         break;
345                 case 0xc0:
346                         r = (uint8)(r * 0.67);
347                         g = (uint8)(g * 0.77);
348                         b = (uint8)(b * 0.83);
349                         break;
350                 case 0xe0:
351                         r = (uint8)(r * 0.68);
352                         g = (uint8)(g * 0.68);
353                         b = (uint8)(b * 0.68);
354                         break;
355                 }
356                 palette_pc[i] = RGB_COLOR(r, g, b);
357         }
358 }
359
360 void PPU::render_scanline(int v)
361 {
362         uint8* buf = screen[v];
363         
364         if(!bg_enabled()) {
365                 // set to background color
366                 memset(screen[v], bg_pal[0], 256 + 16);
367         }
368         if(spr_enabled() || bg_enabled()) {
369                 LOOPY_SCANLINE_START(loopy_v, loopy_t);
370                 if(bg_enabled()) {
371                         render_bg(v);
372                 } else {
373                         memset(solid_buf, 0, sizeof(solid_buf));
374                 }
375                 if(spr_enabled()) {
376                         // draw sprites
377                         render_spr(v);
378                 }
379                 LOOPY_NEXT_LINE(loopy_v);
380         }
381 }
382
383 #define BG_WRITTEN_FLAG 1
384 #define SPR_WRITTEN_FLAG 2
385
386 #define DRAW_BG_PIXEL() \
387         col = attrib_bits; \
388         if(pattern_lo & pattern_mask) { \
389                 col |= 1; \
390         } \
391         if(pattern_hi & pattern_mask) { \
392                 col |= 2; \
393         } \
394         *p++ = monochrome() ? (bg_pal[col] & 0xf0) : bg_pal[col]; \
395         *solid++ = (col & 3) ? BG_WRITTEN_FLAG : 0; \
396
397 void PPU::render_bg(int v)
398 {
399         uint32 tile_x = (loopy_v & 0x001f);
400         uint32 tile_y = (loopy_v & 0x03e0) >> 5;
401         uint32 name_addr = 0x2000 + (loopy_v & 0x0fff);
402         uint32 attrib_addr = 0x2000 + (loopy_v & 0x0c00) + 0x03c0 + ((tile_y & 0xfffc) << 1) + (tile_x >> 2);
403         uint8 attrib_bits;
404         
405         if(!(tile_y & 2)) {
406                 if(!(tile_x & 2)) {
407                         attrib_bits = (VRAM(attrib_addr) & 0x03) << 2;
408                 } else {
409                         attrib_bits = (VRAM(attrib_addr) & 0x0C);
410                 }
411         } else {
412                 if(!(tile_x & 2)) {
413                         attrib_bits = (VRAM(attrib_addr) & 0x30) >> 2;
414                 } else {
415                         attrib_bits = (VRAM(attrib_addr) & 0xC0) >> 4;
416                 }
417         }
418         uint8 *p = screen[v] + (8 - loopy_x);
419         uint8 *solid = solid_buf + (8 - loopy_x);
420         
421         for(int i = 33; i; i--) {
422                 uint32 pattern_addr = bg_pattern_table_addr + ((int32)VRAM(name_addr) << 4) + ((loopy_v & 0x7000) >> 12);
423                 uint8 pattern_lo = VRAM(pattern_addr);
424                 uint8 pattern_hi = VRAM(pattern_addr + 8);
425                 uint8 pattern_mask = 0x80;
426                 uint8 col;
427                 
428                 DRAW_BG_PIXEL();
429                 pattern_mask >>= 1;
430                 DRAW_BG_PIXEL();
431                 pattern_mask >>= 1;
432                 DRAW_BG_PIXEL();
433                 pattern_mask >>= 1;
434                 DRAW_BG_PIXEL();
435                 pattern_mask >>= 1;
436                 DRAW_BG_PIXEL();
437                 pattern_mask >>= 1;
438                 DRAW_BG_PIXEL();
439                 pattern_mask >>= 1;
440                 DRAW_BG_PIXEL();
441                 pattern_mask >>= 1;
442                 DRAW_BG_PIXEL();
443                 
444                 tile_x++;
445                 name_addr++;
446                 
447                 if(!(tile_x & 1)) {
448                         if(!(tile_x & 3)) {
449                                 if(!(tile_x & 0x1f)) {
450                                         name_addr ^= 0x0400; // switch name tables
451                                         attrib_addr ^= 0x0400;
452                                         name_addr -= 0x0020;
453                                         attrib_addr -= 0x0008;
454                                         tile_x -= 0x0020;
455                                 }
456                                 attrib_addr++;
457                         }
458                         if(!(tile_y & 2)) {
459                                 if(!(tile_x & 2)) {
460                                         attrib_bits = (VRAM(attrib_addr) & 0x03) << 2;
461                                 } else {
462                                         attrib_bits = (VRAM(attrib_addr) & 0x0c);
463                                 }
464                         } else {
465                                 if(!(tile_x & 2)) {
466                                         attrib_bits = (VRAM(attrib_addr) & 0x30) >> 2;
467                                 } else {
468                                         attrib_bits = (VRAM(attrib_addr) & 0xc0) >> 4;
469                                 }
470                         }
471                 }
472         }
473         if(bg_clip()) {
474                 memset(&screen[v][8], bg_pal[0], 8);
475                 memset(solid + 8, 0, 8);
476         }
477 }
478
479 void PPU::render_spr(int v)
480 {
481         int num_sprites = 0;
482         int spr_height = sprites_8x16() ? 16 : 8;
483         
484         for(int s = 0; s < 64; s++) {
485                 uint8* spr = &spr_ram[s << 2];
486                 int spr_y = spr[0] + 1;
487                 
488                 if(spr_y > v || (spr_y + spr_height) <= v) {
489                         continue;
490                 }
491                 num_sprites++;
492                 if(num_sprites > 8) {
493                         break;
494                 }
495                 int spr_x = spr[3];
496                 int start_x = 0;
497                 int end_x = 8;
498                 int inc_x = 1;
499                 
500                 if((spr_x + 7) > 255) {
501                         end_x -= ((spr_x + 7) - 255);
502                 }
503                 if((spr_x < 8) && (spr_clip())) {
504                         if(!spr_x) {
505                                 continue;
506                         }
507                         start_x += (8 - spr_x);
508                 }
509                 int y = v - spr_y;
510                 
511                 uint8 *p = &screen[v][8 + spr_x + start_x];
512                 uint8 *solid = &solid_buf[8 + spr_x + start_x];
513                 
514                 if(spr[2] & 0x40) {
515                         start_x = (8 - 1) - start_x;
516                         end_x = (8 - 1) - end_x;
517                         inc_x = -1;
518                 }
519                 if(spr[2] & 0x80) {
520                         y = (spr_height - 1) - y;
521                 }
522                 uint8 priority = spr[2] & 0x20;
523                 
524                 for(int x = start_x; x != end_x; x += inc_x) {
525                         uint8 col = 0;
526                         uint32 tile_addr;
527                         uint8 tile_mask;
528                         
529                         if(!((*solid) & SPR_WRITTEN_FLAG)) {
530                                 if(sprites_8x16()) {
531                                         tile_addr = spr[1] << 4;
532                                         if(spr[1] & 0x01) {
533                                                 tile_addr += 0x1000;
534                                                 if(y < 8) {
535                                                         tile_addr -= 16;
536                                                 }
537                                         } else {
538                                                 if(y >= 8) {
539                                                         tile_addr += 16;
540                                                 }
541                                         }
542                                         tile_addr += y & 0x07;
543                                         tile_mask = (0x80 >> (x & 0x07));
544                                 } else {
545                                         tile_addr = spr[1] << 4;
546                                         tile_addr += y & 0x07;
547                                         tile_addr += spr_pattern_table_addr;
548                                         tile_mask = (0x80 >> (x & 0x07));
549                                 }
550                                 if(VRAM(tile_addr) & tile_mask) {
551                                         col |= 1;
552                                 }
553                                 tile_addr += 8;
554                                 if(VRAM(tile_addr) & tile_mask) {
555                                         col |= 2;
556                                 }
557                                 if(spr[2] & 2) {
558                                         col |= 8;
559                                 }
560                                 if(spr[2] & 1) {
561                                         col |= 4;
562                                 }
563                                 if(col & 3) {
564                                         if(s && (*solid & BG_WRITTEN_FLAG)) {
565                                                 regs[2] |= 0x40;
566                                         }
567                                         if(priority) {
568                                                 *solid |= SPR_WRITTEN_FLAG;
569                                                 if(!(*solid & BG_WRITTEN_FLAG)) {
570                                                         *p = monochrome() ? (spr_pal[col] & 0xf0) : spr_pal[col];
571                                                 }
572                                         } else {
573                                                 if(!(*solid & SPR_WRITTEN_FLAG)) {
574                                                         *p = monochrome() ? (spr_pal[col] & 0xf0) : spr_pal[col];
575                                                         *solid |= SPR_WRITTEN_FLAG;
576                                                 }
577                                         }
578                                 }
579                         }
580                         p++;
581                         solid++;
582                 }
583         }
584         if(num_sprites >= 8) {
585                 regs[2] |= 0x20;
586         } else {
587                 regs[2] &= ~0x20;
588         }
589 }
590
591 #define STATE_VERSION   1
592
593 void PPU::save_state(FILEIO* state_fio)
594 {
595         state_fio->FputUint32(STATE_VERSION);
596         state_fio->FputInt32(this_device_id);
597         
598         state_fio->Fwrite(palette_pc, sizeof(palette_pc), 1);
599         state_fio->Fwrite(solid_buf, sizeof(solid_buf), 1);
600         state_fio->Fwrite(header, sizeof(header), 1);
601         state_fio->Fwrite(chr_rom, sizeof(chr_rom), 1);
602         state_fio->Fwrite(name_tables, sizeof(name_tables), 1);
603         state_fio->Fwrite(spr_ram, sizeof(spr_ram), 1);
604         state_fio->Fwrite(bg_pal, sizeof(bg_pal), 1);
605         state_fio->Fwrite(spr_pal, sizeof(spr_pal), 1);
606         state_fio->FputUint8(spr_ram_rw_ptr);
607         state_fio->Fwrite(regs, sizeof(regs), 1);
608         state_fio->FputUint16(bg_pattern_table_addr);
609         state_fio->FputUint16(spr_pattern_table_addr);
610         state_fio->FputUint16(ppu_addr_inc);
611         state_fio->FputUint8(rgb_bak);
612         state_fio->FputBool(toggle_2005_2006);
613         state_fio->FputUint8(read_2007_buffer);
614         state_fio->FputUint16(loopy_v);
615         state_fio->FputUint16(loopy_t);
616         state_fio->FputUint8(loopy_x);
617 }
618
619 bool PPU::load_state(FILEIO* state_fio)
620 {
621         if(state_fio->FgetUint32() != STATE_VERSION) {
622                 return false;
623         }
624         if(state_fio->FgetInt32() != this_device_id) {
625                 return false;
626         }
627         state_fio->Fread(palette_pc, sizeof(palette_pc), 1);
628         state_fio->Fread(solid_buf, sizeof(solid_buf), 1);
629         state_fio->Fread(header, sizeof(header), 1);
630         state_fio->Fread(chr_rom, sizeof(chr_rom), 1);
631         state_fio->Fread(name_tables, sizeof(name_tables), 1);
632         state_fio->Fread(spr_ram, sizeof(spr_ram), 1);
633         state_fio->Fread(bg_pal, sizeof(bg_pal), 1);
634         state_fio->Fread(spr_pal, sizeof(spr_pal), 1);
635         spr_ram_rw_ptr = state_fio->FgetUint8();
636         state_fio->Fread(regs, sizeof(regs), 1);
637         bg_pattern_table_addr = state_fio->FgetUint16();
638         spr_pattern_table_addr = state_fio->FgetUint16();
639         ppu_addr_inc = state_fio->FgetUint16();
640         rgb_bak = state_fio->FgetUint8();
641         toggle_2005_2006 = state_fio->FgetBool();
642         read_2007_buffer = state_fio->FgetUint8();
643         loopy_v = state_fio->FgetUint16();
644         loopy_t = state_fio->FgetUint16();
645         loopy_x = state_fio->FgetUint8();
646         return true;
647 }
648