2 Nintendo Family BASIC Emulator 'eFamilyBASIC'
5 Author : Takeda.Toshiya
14 static const uint8_t palette[64][3] = {
15 {0x75, 0x75, 0x75}, {0x27, 0x1b, 0x8f}, {0x00, 0x00, 0xab}, {0x47, 0x00, 0x9f},
16 {0x8f, 0x00, 0x77}, {0xab, 0x00, 0x13}, {0xa7, 0x00, 0x00}, {0x7f, 0x0b, 0x00},
17 {0x43, 0x2f, 0x00}, {0x00, 0x47, 0x00}, {0x00, 0x51, 0x00}, {0x00, 0x3f, 0x17},
18 {0x1b, 0x3f, 0x5f}, {0x00, 0x00, 0x00}, {0x05, 0x05, 0x05}, {0x05, 0x05, 0x05},
19 {0xbc, 0xbc, 0xbc}, {0x00, 0x73, 0xef}, {0x23, 0x3b, 0xef}, {0x83, 0x00, 0xf3},
20 {0xbf, 0x00, 0xbf}, {0xe7, 0x00, 0x5b}, {0xdb, 0x2b, 0x00}, {0xcb, 0x4f, 0x0f},
21 {0x8b, 0x73, 0x00}, {0x00, 0x97, 0x00}, {0x00, 0xab, 0x00}, {0x00, 0x93, 0x3b},
22 {0x00, 0x83, 0x8b}, {0x11, 0x11, 0x11}, {0x09, 0x09, 0x09}, {0x09, 0x09, 0x09},
23 {0xff, 0xff, 0xff}, {0x3f, 0xbf, 0xff}, {0x5f, 0x97, 0xff}, {0xa7, 0x8b, 0xfd},
24 {0xf7, 0x7b, 0xff}, {0xff, 0x77, 0xb7}, {0xff, 0x77, 0x63}, {0xff, 0x9b, 0x3b},
25 {0xf3, 0xbf, 0x3f}, {0x83, 0xd3, 0x13}, {0x4f, 0xdf, 0x4b}, {0x58, 0xf8, 0x98},
26 {0x00, 0xeb, 0xdb}, {0x66, 0x66, 0x66}, {0x0d, 0x0d, 0x0d}, {0x0d, 0x0d, 0x0d},
27 {0xff, 0xff, 0xff}, {0xab, 0xe7, 0xff}, {0xc7, 0xd7, 0xff}, {0xd7, 0xcb, 0xff},
28 {0xff, 0xc7, 0xff}, {0xff, 0xc7, 0xdb}, {0xff, 0xbf, 0xb3}, {0xff, 0xdb, 0xab},
29 {0xff, 0xe7, 0xa3}, {0xe3, 0xff, 0xa3}, {0xab, 0xf3, 0xbf}, {0xb3, 0xff, 0xcf},
30 {0x9f, 0xff, 0xf3}, {0xdd, 0xdd, 0xdd}, {0x11, 0x11, 0x11}, {0x11, 0x11, 0x11}
33 #define VRAM(addr) bank_ptr[((addr) >> 10) & 0x0f][(addr) & 0x3ff]
35 #define NMI_enabled() (regs[0] & 0x80)
36 #define sprites_8x16() (regs[0] & 0x20)
37 //#define spr_enabled() (regs[1] & 0x10)
38 //#define bg_enabled() (regs[1] & 0x08)
39 #define spr_clip() (!(regs[1] & 0x04))
40 #define bg_clip() (!(regs[1] & 0x02))
41 #define monochrome() (regs[1] & 0x01)
42 #define rgb_pal() (regs[1] & 0xe0)
43 #define sprite0_hit() (regs[2] & 0x40)
45 #define LOOPY_SCANLINE_START(v, t) { \
46 v = (v & 0xfbe0) | (t & 0x041f); \
49 #define LOOPY_NEXT_LINE(v) { \
50 if((v & 0x7000) == 0x7000) { \
52 if((v & 0x3e0) == 0x3a0) { \
56 if((v & 0x3e0) == 0x3e0) { \
67 #define LOOPY_NEXT_TILE(v) { \
68 if((v & 0x1f) == 0x1f) { \
76 #define LOOPY_NEXT_PIXEL(v, x) { \
85 void PPU::initialize()
90 register_vline_event(this);
100 void PPU::load_rom_image(const _TCHAR *file_name)
102 FILEIO* fio = new FILEIO();
104 if(chr_rom != NULL) {
109 memset(&header, 0x00, sizeof(header));
111 if(!fio->Fopen(create_local_path(file_name), FILEIO_READ_BINARY)) {
113 fio->Fopen(create_local_path(_T("BASIC.NES")), FILEIO_READ_BINARY);
115 if(fio->IsOpened()) {
117 fio->Fread(&header, sizeof(header), 1);
119 fio->Fseek(0x2000 * header.num_8k_rom_banks(), FILEIO_SEEK_CUR);
121 if((chr_rom_size = 8192 * header.num_8k_vrom_banks) != 0) {
122 for(uint32_t bit = 0x40000; bit != 0; bit >>= 1) {
123 if(chr_rom_size & bit) {
124 if(chr_rom_size & (bit - 1)) {
125 chr_rom_size = (chr_rom_size | (bit - 1)) + 1;
130 chr_rom = (uint8_t *)calloc(chr_rom_size, 1);
131 fio->Fread(chr_rom, 8192 * header.num_8k_vrom_banks, 1);
137 if(chr_rom_size == 0) {
139 chr_rom = (uint8_t *)calloc(chr_rom_size, 1);
141 chr_rom_mask = (chr_rom_size / 0x400) - 1;
146 // set up PPU memory space table
147 for(int i = 0; i < 8; i++) {
152 if(header.flags_1 & 8) {
153 set_mirroring(MIRROR_4SCREEN);
154 } else if(header.flags_1 & 1) {
155 set_mirroring(MIRROR_VERT);
157 set_mirroring(MIRROR_HORIZ);
160 memset(bg_pal, 0, sizeof(bg_pal));
161 memset(spr_pal, 0, sizeof(spr_pal));
162 memset(solid_buf, 0, sizeof(solid_buf));
163 memset(name_tables, 0, sizeof(name_tables));
165 memset(spr_ram, 0, sizeof(spr_ram));
168 memset(regs, 0, sizeof(regs));
169 bg_pattern_table_addr = 0;
170 spr_pattern_table_addr = 0;
173 toggle_2005_2006 = false;
174 read_2007_buffer = 0;
180 // reset emphasised palette
184 void PPU::write_data8(uint32_t addr, uint32_t data)
188 regs[addr & 7] = data;
190 switch(addr & 0xe007) {
192 bg_pattern_table_addr = (data & 0x10) ? 0x1000 : 0;
193 spr_pattern_table_addr = (data & 0x08) ? 0x1000 : 0;
194 ppu_addr_inc = (data & 0x04) ? 32 : 1;
195 loopy_t = (loopy_t & 0xf3ff) | (((uint16_t)(data & 0x03)) << 10);
198 if(rgb_bak != (data & 0xe0)) {
200 rgb_bak = data & 0xe0;
204 spr_ram_rw_ptr = data;
207 spr_ram[spr_ram_rw_ptr++] = data;
210 toggle_2005_2006 = !toggle_2005_2006;
211 if(toggle_2005_2006) {
213 loopy_t = (loopy_t & 0xffe0) | (((uint16_t)(data & 0xf8)) >> 3);
214 loopy_x = data & 0x07;
217 loopy_t = (loopy_t & 0xfc1f) | (((uint16_t)(data & 0xf8)) << 2);
218 loopy_t = (loopy_t & 0x8fff) | (((uint16_t)(data & 0x07)) << 12);
222 toggle_2005_2006 = !toggle_2005_2006;
223 if(toggle_2005_2006) {
225 loopy_t = (loopy_t & 0x00ff) | (((uint16_t)(data & 0x3f)) << 8);
228 loopy_t = (loopy_t & 0xff00) | ((uint16_t)data);
233 ofs = loopy_v & 0x3fff;
234 loopy_v += ppu_addr_inc;
236 // is it a palette entry?
239 if(!(ofs & 0x000f)) {
240 bg_pal[0] = spr_pal[0] = data;
241 } else if(!(ofs & 0x10)) {
242 bg_pal[ofs & 0x000f] = data;
244 spr_pal[ofs & 0x000f] = data;
251 if(ofs >= 0x2000 || header.num_8k_vrom_banks == 0) {
258 uint32_t PPU::read_data8(uint32_t addr)
263 switch(addr & 0xe007) {
266 toggle_2005_2006 = false;
268 // clear v-blank flag
272 ofs = loopy_v & 0x3fff;
273 loopy_v += ppu_addr_inc;
275 // is it a palette entry?
277 if(!(ofs & 0x0010)) {
278 return bg_pal[ofs & 0x000f];
280 return spr_pal[ofs & 0x000f];
286 val = read_2007_buffer;
287 read_2007_buffer = VRAM(ofs);
290 return regs[addr & 7];
293 void PPU::event_vline(int v, int clock)
303 if(spr_enabled() || bg_enabled()) {
308 // set vblank register flag
311 d_cpu->write_signal(SIG_CPU_NMI, 1, 1);
315 // reset vblank register flag and sprite0 hit flag1
324 void PPU::draw_screen()
327 for(int y = 0; y < 240; y++) {
328 scrntype_t* dest = emu->get_screen_buffer(y);
329 uint8_t* src = screen[y];
331 for(int x = 0; x < 256; x++) {
332 dest[x] = palette_pc[src[x + 8] & 0x3f];
337 void PPU::update_palette()
339 for(int i = 0; i < 64; i++) {
340 uint8_t r = palette[i][0];
341 uint8_t g = palette[i][1];
342 uint8_t b = palette[i][2];
346 g = (uint8_t)(g * 0.80);
347 b = (uint8_t)(b * 0.73);
350 r = (uint8_t)(r * 0.73);
351 b = (uint8_t)(b * 0.70);
354 r = (uint8_t)(r * 0.76);
355 g = (uint8_t)(g * 0.78);
356 b = (uint8_t)(b * 0.58);
359 r = (uint8_t)(r * 0.86);
360 g = (uint8_t)(g * 0.80);
363 r = (uint8_t)(r * 0.83);
364 g = (uint8_t)(g * 0.68);
365 b = (uint8_t)(b * 0.85);
368 r = (uint8_t)(r * 0.67);
369 g = (uint8_t)(g * 0.77);
370 b = (uint8_t)(b * 0.83);
373 r = (uint8_t)(r * 0.68);
374 g = (uint8_t)(g * 0.68);
375 b = (uint8_t)(b * 0.68);
378 palette_pc[i] = RGB_COLOR(r, g, b);
382 void PPU::render_scanline(int v)
384 uint8_t* buf = screen[v];
387 // set to background color
388 memset(screen[v], bg_pal[0], 256 + 16);
390 if(spr_enabled() || bg_enabled()) {
391 LOOPY_SCANLINE_START(loopy_v, loopy_t);
395 memset(solid_buf, 0, sizeof(solid_buf));
401 LOOPY_NEXT_LINE(loopy_v);
405 #define BG_WRITTEN_FLAG 1
406 #define SPR_WRITTEN_FLAG 2
408 #define DRAW_BG_PIXEL() \
410 if(pattern_lo & pattern_mask) { \
413 if(pattern_hi & pattern_mask) { \
416 *p++ = monochrome() ? (bg_pal[col] & 0xf0) : bg_pal[col]; \
417 *solid++ = (col & 3) ? BG_WRITTEN_FLAG : 0; \
419 void PPU::render_bg(int v)
421 uint32_t tile_x = (loopy_v & 0x001f);
422 uint32_t tile_y = (loopy_v & 0x03e0) >> 5;
423 uint32_t name_addr = 0x2000 + (loopy_v & 0x0fff);
424 uint32_t attrib_addr = 0x2000 + (loopy_v & 0x0c00) + 0x03c0 + ((tile_y & 0xfffc) << 1) + (tile_x >> 2);
429 attrib_bits = (VRAM(attrib_addr) & 0x03) << 2;
431 attrib_bits = (VRAM(attrib_addr) & 0x0C);
435 attrib_bits = (VRAM(attrib_addr) & 0x30) >> 2;
437 attrib_bits = (VRAM(attrib_addr) & 0xC0) >> 4;
440 uint8_t *p = screen[v] + (8 - loopy_x);
441 uint8_t *solid = solid_buf + (8 - loopy_x);
443 for(int i = 33; i; i--) {
444 if(header.mapper() == 5) {
445 uint8_t mmc5_pal = d_memory->mmc5_ppu_latch_render(1, name_addr & 0x03ff);
447 attrib_bits = mmc5_pal & 0x0c;
451 uint32_t pattern_addr = bg_pattern_table_addr + ((int32_t)VRAM(name_addr) << 4) + ((loopy_v & 0x7000) >> 12);
452 uint8_t pattern_lo = VRAM(pattern_addr);
453 uint8_t pattern_hi = VRAM(pattern_addr + 8);
454 uint8_t pattern_mask = 0x80;
478 if(!(tile_x & 0x1f)) {
479 name_addr ^= 0x0400; // switch name tables
480 attrib_addr ^= 0x0400;
482 attrib_addr -= 0x0008;
489 attrib_bits = (VRAM(attrib_addr) & 0x03) << 2;
491 attrib_bits = (VRAM(attrib_addr) & 0x0c);
495 attrib_bits = (VRAM(attrib_addr) & 0x30) >> 2;
497 attrib_bits = (VRAM(attrib_addr) & 0xc0) >> 4;
506 memset(&screen[v][8], bg_pal[0], 8);
507 memset(solid + 8, 0, 8);
511 void PPU::render_spr(int v)
514 int spr_height = sprites_8x16() ? 16 : 8;
516 if(header.mapper() == 5) {
517 d_memory->mmc5_ppu_latch_render(0, 0);
519 for(int s = 0; s < 64; s++) {
520 uint8_t* spr = &spr_ram[s << 2];
521 int spr_y = spr[0] + 1;
523 if(spr_y > v || (spr_y + spr_height) <= v) {
527 if(num_sprites > 8) {
535 if((spr_x + 7) > 255) {
536 end_x -= ((spr_x + 7) - 255);
538 if((spr_x < 8) && (spr_clip())) {
542 start_x += (8 - spr_x);
546 uint8_t *p = &screen[v][8 + spr_x + start_x];
547 uint8_t *solid = &solid_buf[8 + spr_x + start_x];
550 start_x = (8 - 1) - start_x;
551 end_x = (8 - 1) - end_x;
555 y = (spr_height - 1) - y;
557 uint8_t priority = spr[2] & 0x20;
559 for(int x = start_x; x != end_x; x += inc_x) {
564 if(!((*solid) & SPR_WRITTEN_FLAG)) {
566 tile_addr = spr[1] << 4;
577 tile_addr += y & 0x07;
578 tile_mask = (0x80 >> (x & 0x07));
580 tile_addr = spr[1] << 4;
581 tile_addr += y & 0x07;
582 tile_addr += spr_pattern_table_addr;
583 tile_mask = (0x80 >> (x & 0x07));
585 if(VRAM(tile_addr) & tile_mask) {
589 if(VRAM(tile_addr) & tile_mask) {
599 if(s && (*solid & BG_WRITTEN_FLAG)) {
603 *solid |= SPR_WRITTEN_FLAG;
604 if(!(*solid & BG_WRITTEN_FLAG)) {
605 *p = monochrome() ? (spr_pal[col] & 0xf0) : spr_pal[col];
608 if(!(*solid & SPR_WRITTEN_FLAG)) {
609 *p = monochrome() ? (spr_pal[col] & 0xf0) : spr_pal[col];
610 *solid |= SPR_WRITTEN_FLAG;
619 if(num_sprites >= 8) {
626 void PPU::set_ppu_bank(uint8_t bank, uint32_t bank_num)
629 bank_ptr[bank] = chr_rom + 0x400 * (bank_num & chr_rom_mask);
630 } else if(bank < 12) {
631 bank_ptr[bank] = bank_ptr[bank + 4] = name_tables + 0x400 * (bank_num & 0x03);
633 banks[bank] = bank_num;
636 void PPU::set_mirroring(int mirror)
640 // horizontal mirroring
641 set_mirroring(0, 0, 1, 1);
644 // vertical mirroring
645 set_mirroring(0, 1, 0, 1);
648 // 4 screen mirroring
649 set_mirroring(0, 1, 2, 3);
654 void PPU::set_mirroring(uint32_t nt0, uint32_t nt1, uint32_t nt2, uint32_t nt3)
656 set_ppu_bank( 8, nt0);
657 set_ppu_bank( 9, nt1);
658 set_ppu_bank(10, nt2);
659 set_ppu_bank(11, nt3);
662 #define STATE_VERSION 3
664 bool PPU::process_state(FILEIO* state_fio, bool loading)
666 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
669 if(!state_fio->StateCheckInt32(this_device_id)) {
672 //state_fio->StateBuffer(palette_pc, sizeof(palette_pc), 1);
674 for(int i = 0; i < (sizeof(palette_pc) / sizeof(scrntype_t)); i++) {
676 r = state_fio->FgetUint8();
677 g = state_fio->FgetUint8();
678 b = state_fio->FgetUint8();
679 palette_pc[i] = RGB_COLOR(r, g, b);
682 for(int i = 0; i < (sizeof(palette_pc) / sizeof(scrntype_t)); i++) {
684 r = R_OF_COLOR(palette_pc[i]);
685 g = G_OF_COLOR(palette_pc[i]);
686 b = B_OF_COLOR(palette_pc[i]);
687 state_fio->FputUint8(r);
688 state_fio->FputUint8(g);
689 state_fio->FputUint8(b);
692 state_fio->StateBuffer(solid_buf, sizeof(solid_buf), 1);
693 state_fio->StateBuffer(&header, sizeof(header), 1); // OK?
694 // state_fio->StateBuffer(banks, sizeof(banks), 1);
695 for(int i = 0; i < (sizeof(banks) / sizeof(uint32_t)); i++) {
696 state_fio->StateUint32(banks[i]);
698 state_fio->StateUint32(chr_rom_size);
699 // state_fio->StateInt32(chr_rom_mask);
701 chr_rom_mask = (chr_rom_size / 0x400) - 1;
702 if(chr_rom != NULL) {
705 chr_rom = (uint8_t *)malloc(chr_rom_size);
707 state_fio->StateBuffer(chr_rom, chr_rom_size, 1);
708 state_fio->StateBuffer(name_tables, sizeof(name_tables), 1);
709 state_fio->StateBuffer(spr_ram, sizeof(spr_ram), 1);
710 state_fio->StateBuffer(bg_pal, sizeof(bg_pal), 1);
711 state_fio->StateBuffer(spr_pal, sizeof(spr_pal), 1);
712 state_fio->StateUint8(spr_ram_rw_ptr);
713 state_fio->StateBuffer(regs, sizeof(regs), 1);
714 state_fio->StateUint16(bg_pattern_table_addr);
715 state_fio->StateUint16(spr_pattern_table_addr);
716 state_fio->StateUint16(ppu_addr_inc);
717 state_fio->StateUint8(rgb_bak);
718 state_fio->StateBool(toggle_2005_2006);
719 state_fio->StateUint8(read_2007_buffer);
720 state_fio->StateUint16(loopy_v);
721 state_fio->StateUint16(loopy_t);
722 state_fio->StateUint8(loopy_x);
726 for(int i = 0; i < 12; i++) {
727 set_ppu_bank(i, banks[i]);