├── .gitignore ├── TODO.txt ├── cci ├── icon.icn ├── banner.bnr ├── build-3ds.bat ├── build-cia.bat ├── build_cia.rsf └── gw_workaround.rsf ├── 3DNES_old.3dsx ├── include ├── utils.h ├── nesLoadROM.h ├── mapper79.h ├── aorom.h ├── unrom.h ├── cnrom.h ├── nes6502.h ├── nesSystem.h ├── nesPPU.h ├── FileSystem.h ├── palette.h ├── nesGlobal.h ├── mmc1.h ├── mmc3.h ├── mmc5.h └── gfx │ └── imgdata.h ├── README.md ├── source ├── nes6502.inc ├── unrom.s ├── cnrom.s ├── nesSystem.c ├── nesLoadROM.c ├── FileSystem.c ├── main.c └── nesPPU.c ├── ccd00.ld └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3DNES.elf 3 | 3DNES.3dsx 4 | *.cia -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/st4rk/3DNES/HEAD/TODO.txt -------------------------------------------------------------------------------- /cci/icon.icn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/st4rk/3DNES/HEAD/cci/icon.icn -------------------------------------------------------------------------------- /3DNES_old.3dsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/st4rk/3DNES/HEAD/3DNES_old.3dsx -------------------------------------------------------------------------------- /cci/banner.bnr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/st4rk/3DNES/HEAD/cci/banner.bnr -------------------------------------------------------------------------------- /cci/build-3ds.bat: -------------------------------------------------------------------------------- 1 | arm-none-eabi-strip 3DNES.elf 2 | makerom -f cci -o 3DNES.3ds -rsf gw_workaround.rsf -target d -exefslogo -elf 3DNES.elf -icon icon.icn -banner banner.bnr -------------------------------------------------------------------------------- /cci/build-cia.bat: -------------------------------------------------------------------------------- 1 | arm-none-eabi-strip 3DNES.elf 2 | makerom -f cia -o 3DNES.cia -elf 3DNES.elf -rsf build_cia.rsf -icon icon.icn -banner banner.bnr -exefslogo -target t 3 | pause -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | /* Funções usadas por vários mappers */ 2 | int maskaddr(unsigned char bank) { 3 | if (bank >= PRG * 2) { 4 | unsigned char i = 0xFF; 5 | while ((bank & i) >= PRG * 2) { 6 | i /= 2; 7 | } 8 | return bank & i; 9 | } else { 10 | return bank; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 3DNES 2 | ================== 3 | 4 | 3DNES is an NES( Nintendo Entertainment System) emulator for Nintendo 3DS, developed by St4rk and gdkChan. 5 | The project is on an initial phase. It’s capable of emulating many games( with speed going from great to somewhat slow), 6 | and already supports some mappers. However, it doesn’t have support for sound yet. 7 | 8 | o 9 | -------------------------------------------------------------------------------- /include/nesLoadROM.h: -------------------------------------------------------------------------------- 1 | #ifndef NESLOADROM_H 2 | #define NESLOADROM_H 3 | 4 | 5 | #include 6 | #include 7 | #include <3ds.h> 8 | #include "nesGlobal.h" 9 | #include "nes6502.h" 10 | 11 | u8 PRG; 12 | u8 CHR; 13 | u8 MAPPER; 14 | 15 | int RCB; 16 | int OS_MIRROR; 17 | int FS_MIRROR; 18 | int TRAINER; 19 | int SRAM; 20 | int MIRRORING; 21 | int VRAM; 22 | 23 | int NES_LoadROM(); 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/mapper79.h: -------------------------------------------------------------------------------- 1 | typedef unsigned char UINT_8; 2 | typedef unsigned int UINT_32; 3 | 4 | 5 | 6 | 7 | void mapper79_chr_switch(UINT_32 bank) { 8 | UINT_32 CHR_SIZE = 8192; 9 | UINT_8 bank_select = (bank & 0x7); // 0x7 == 0x00000111 10 | 11 | memcpy(PPU_Memory, ROM_Cache + 16 + (PRG * 16384) + (bank_select * CHR_SIZE), CHR_SIZE); 12 | } 13 | 14 | 15 | void mapper79_access(UINT_32 address, UINT_8 data) { 16 | 17 | mapper79_chr_switch(data); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /include/aorom.h: -------------------------------------------------------------------------------- 1 | 2 | void aorom_switch_prg(int bank) { 3 | int prg_size; 4 | unsigned int address; 5 | 6 | address = 0x8000; 7 | prg_size = 32768; 8 | 9 | 10 | memcpy(memory + address, ROM_Cache + 16 + (bank * prg_size), prg_size); 11 | } 12 | 13 | void 14 | aorom_access(unsigned int address,unsigned char data) 15 | { 16 | 17 | if(address > 0x7fff && address < 0x10000) { 18 | if (data & 0x10) {do_mirror(2);} else {do_mirror(3);} 19 | aorom_switch_prg(data & 0xF); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/unrom.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | @ ----------------------------------------------------------------- 4 | @ 3DNES unrom - Written by St4rk 5 | @ Date: 27/09/2014 6 | @ 3DNES é um emulador de Nintendo Entertainment System para 3DS 7 | @ esse é um projeto open-source, você pode modificar e utilizar 8 | @ os arquivos para estudo, desde que mantenha os devidos créditos 9 | @ ----------------------------------------------------------------- 10 | */ 11 | 12 | extern void unrom_access(unsigned int address,unsigned char data); 13 | 14 | -------------------------------------------------------------------------------- /include/cnrom.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | @ ----------------------------------------------------------------- 4 | @ 3DNES unrom - Written by St4rk 5 | @ Date: 18/11/2014 6 | @ 3DNES é um emulador de Nintendo Entertainment System para 3DS 7 | @ esse é um projeto open-source, você pode modificar e utilizar 8 | @ os arquivos para estudo, desde que mantenha os devidos créditos 9 | @ ----------------------------------------------------------------- 10 | */ 11 | 12 | extern void cnrom_switch_chr(int bank); 13 | extern void cnrom_access(unsigned int address,unsigned char data); -------------------------------------------------------------------------------- /include/nes6502.h: -------------------------------------------------------------------------------- 1 | /* 2 | @ ----------------------------------------------------------------- 3 | @ 3DNES 6502core - Written by gdkchan and St4rk 4 | @ Date: 27/09/2014 5 | @ 3DNES é um emulador de Nintendo Entertainment System para 3DS 6 | @ esse é um projeto open-source, você pode modificar e utilizar 7 | @ os arquivos para estudo, desde que mantenha os devidos créditos 8 | @ ----------------------------------------------------------------- 9 | */ 10 | 11 | 12 | #include <3ds.h> 13 | 14 | u8 memory[65536]; 15 | 16 | extern void IRQ(); 17 | extern void NMI(); 18 | extern void CPU_Reset(); 19 | extern void CPU_Execute(); 20 | -------------------------------------------------------------------------------- /include/nesSystem.h: -------------------------------------------------------------------------------- 1 | #ifndef NESSYSTEM_H 2 | #define NESSYSTEM_H 3 | 4 | 5 | #include <3ds.h> 6 | #include "nesGlobal.h" 7 | #include "FileSystem.h" 8 | #include "nes6502.h" 9 | 10 | u32 PAD1_UP; 11 | u32 PAD1_DOWN; 12 | u32 PAD1_LEFT; 13 | u32 PAD1_RIGHT; 14 | 15 | u32 PAD1_A; 16 | u32 PAD1_B; 17 | 18 | u32 PAD1_START; 19 | u32 PAD1_SELECT; 20 | 21 | 22 | /* SRAM Save and Load */ 23 | void SRAM_LOADSTATE(); 24 | void SRAM_SAVESTATE(); 25 | 26 | /* Emulation Stuff */ 27 | void SET_INPUT(u32 padKey); 28 | void CLEAR_INPUT(u32 padKey); 29 | void RESET_INPUT(); 30 | 31 | 32 | /* Save State and Load State */ 33 | void SAVE_STATE(int n); 34 | void LOAD_STATE(int n); 35 | 36 | 37 | #endif -------------------------------------------------------------------------------- /include/nesPPU.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include <3ds.h> 4 | #include <3ds/gfx.h> 5 | 6 | #include "nesGlobal.h" 7 | #include "nes6502.h" 8 | 9 | 10 | extern u32 ppu_control1; 11 | extern u32 ppu_control2; 12 | extern u32 ppu_addr; 13 | extern u32 ppu_addr_h; 14 | extern u32 ppu_addr_tmp; 15 | extern u32 ppu_status; 16 | extern u32 ppu_status_tmp; 17 | extern u32 ppu_bgscr_f; 18 | 19 | extern int current_scanline; 20 | 21 | extern u32 sprite_address; 22 | 23 | extern u32 loopyT; 24 | extern u32 loopyV; 25 | extern u32 loopyX; 26 | 27 | extern void init_ppu(); 28 | extern void show_gfxcache(); 29 | extern void write_PPU_Memory(u32 address,u8 data); 30 | extern void render_scanline(int scanline); 31 | extern void render_background(int scanline); 32 | extern void render_sprite(int scanline,bool foreground); 33 | extern void NES_ColorBackground(); 34 | extern void do_mirror(int type); -------------------------------------------------------------------------------- /source/nes6502.inc: -------------------------------------------------------------------------------- 1 | @ ----------------------------------------------------------------- 2 | @ 3DNES 6502 - Written by St4rk 3 | @ Date: 18/11/2014 4 | @ 3DNES é um emulador de Nintendo Entertainment System para 3DS 5 | @ esse é um projeto open-source, você pode modificar e utilizar 6 | @ os arquivos para estudo, desde que mantenha os devidos créditos 7 | @ ----------------------------------------------------------------- 8 | 9 | 10 | 11 | @ --------------- CPU FLAGS -------------------------------- 12 | 13 | .equ carryFlag, 0x01 14 | .equ zeroFlag, 0x02 15 | .equ interruptFlag, 0x04 16 | .equ decimalFlag, 0x08 17 | .equ sInterruptFlag, 0x10 18 | .equ unusedFlag, 0x20 19 | .equ overflowFlag, 0x40 20 | .equ signFlag, 0x80 21 | 22 | @ ----------------- CPU REGISTERS -------------------------------- 23 | 24 | 25 | @ TODO: each ARM register has 32 bits, so use A,X,Y in just one register(24 bits, 8 bits unused or other important thing =P) 26 | nesF .req r4 27 | nesA .req r5 28 | nesX .req r6 29 | nesY .req r7 30 | nesStack .req r8 31 | nesPC .req r9 32 | nesEA .req r10 33 | nesTick .req r11 34 | nesMemory .req r12 35 | 36 | -------------------------------------------------------------------------------- /source/unrom.s: -------------------------------------------------------------------------------- 1 | @ ----------------------------------------------------------------- 2 | @ 3DNES unrom - Written by St4rk 3 | @ Date: 27/09/2014 4 | @ 3DNES é um emulador de Nintendo Entertainment System para 3DS 5 | @ esse é um projeto open-source, você pode modificar e utilizar 6 | @ os arquivos para estudo, desde que mantenha os devidos créditos 7 | @ ----------------------------------------------------------------- 8 | 9 | .arm 10 | .align 2 11 | .global unrom_access 12 | .type unrom_access STT_FUNC 13 | unrom_access: @ unrom_acess(adress, data) 14 | push {r0-r5, lr} 15 | 16 | ldr r2, =0x7fff 17 | cmp r0, r2 18 | cmpgt r0, #0x10000 19 | blt unrom_switch_prg 20 | b unrom_end 21 | 22 | 23 | unrom_switch_prg: 24 | 25 | 26 | @ r1 = bank 27 | @ address 28 | ldr r4, =0x8000 29 | @ bank * prg_size 30 | ldr r2, =0x4000 31 | mul r3, r2, r1 32 | @ memory + address 33 | ldr r0, =memory 34 | add r0, r0, r4 35 | @ romcache + 16 + (bank * prg_size) 36 | ldr r1, =ROM_Cache+16 37 | add r1, r1, r3 38 | @ memcpy (memory, romcache, prg_size) 39 | 40 | unrom_memcpy: 41 | 42 | ldr r3, [r1], #4 43 | str r3, [r0], #4 44 | subs r2, r2, #4 45 | bge unrom_memcpy 46 | 47 | unrom_end: 48 | pop {r0-r5, pc} 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /include/FileSystem.h: -------------------------------------------------------------------------------- 1 | #ifndef FILESYSTEM_H 2 | #define FILESYSTEM_H 3 | 4 | 5 | 6 | 7 | #include <3ds.h> 8 | #include 9 | #include 10 | 11 | 12 | #define MAX_FILENAME_SIZE 0xA0 13 | 14 | 15 | /* File System Structure */ 16 | typedef struct FS_MENU { 17 | /* File System PAD */ 18 | u8 UKEY_UP; 19 | u8 UKEY_DOWN; 20 | u8 UKEY_LEFT; 21 | u8 UKEY_RIGHT; 22 | u8 UKEY_B; 23 | 24 | /* Selected File */ 25 | int sFile; 26 | /* Cursor File */ 27 | int cFile; 28 | /* Current File */ 29 | int currFile; 30 | 31 | /* inConfiguration ? */ 32 | bool inMenu; 33 | /* Configuration Menu Cursor */ 34 | int cConfig; 35 | /* FileList */ 36 | char *fileList; 37 | 38 | /* totalFiles */ 39 | int totalFiles; 40 | } FS_MENU; 41 | 42 | 43 | FS_MENU fileSystem; 44 | 45 | 46 | /* Load Complete ROM LIST */ 47 | void NES_LOADROMLIST(); 48 | /* Draw All ROM's */ 49 | void NES_drawROMLIST(); 50 | /* Draw Configuration Menu */ 51 | void NES_drawConfigurationMenu(); 52 | /* Update Cursor Position */ 53 | void NES_ConfigurationMenu(); 54 | /* Update Cursor Position */ 55 | void NES_CurrentFileUpdate(); 56 | /* Load Game on ROM */ 57 | void NES_LoadSelectedGame(); 58 | /* Main Menu of 3DNES */ 59 | void NES_MainMenu(); 60 | 61 | /* FS_String Conc */ 62 | void FS_StringConc(char* dst, char* src1, char* src2); 63 | 64 | /* unicode_to_char */ 65 | void unicodeToChar(char* dst, u16* src); 66 | 67 | #endif -------------------------------------------------------------------------------- /include/palette.h: -------------------------------------------------------------------------------- 1 | #ifndef PALETTE_H 2 | #define PALETTE_H 3 | 4 | 5 | typedef struct _pal { 6 | int r; 7 | int g; 8 | int b; 9 | } rgb; 10 | 11 | rgb palette[64] = { 12 | {0x68,0x68,0x68},{0x00,0x2A,0x88},{0x14,0x12,0xA7},{0x3B,0x00,0xA4}, 13 | {0x5C,0x00,0x7E},{0x6E,0x00,0x40},{0x6C,0x06,0x00},{0x56,0x1D,0x00}, 14 | {0x33,0x35,0x00},{0x0B,0x48,0x00},{0x00,0x52,0x00},{0x00,0x4F,0x08}, 15 | {0x00,0x40,0x4D},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00}, 16 | {0xAD,0xAD,0xAD},{0x15,0x5F,0xD9},{0x42,0x40,0xFF},{0x75,0x27,0xFE}, 17 | {0xA0,0x1A,0xCC},{0xB7,0x1E,0x7B},{0x8D,0x31,0x0C},{0x71,0x3F,0x00}, 18 | {0x64,0x63,0x2E},{0x38,0x87,0x00},{0x00,0x6E,0x00},{0x00,0x8F,0x32}, 19 | {0x00,0x68,0x65},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00}, 20 | {0xFF,0xFE,0xFF},{0x64,0xB0,0xFF},{0x92,0x9A,0xFF},{0xC6,0x76,0xFF}, 21 | {0xF3,0x6A,0xFF},{0xFE,0x6E,0xCC},{0xFE,0x81,0x70},{0xE1,0xB8,0x72}, 22 | {0xBC,0xBE,0x00},{0xAF,0xC4,0x00},{0x5C,0xE4,0x30},{0x45,0xE0,0x82}, 23 | {0x48,0xCD,0xDE},{0x4F,0x4F,0x4F},{0x00,0x00,0x00},{0x00,0x00,0x00}, 24 | {0xFF,0xFE,0xFF},{0xC0,0xDF,0xFF},{0xD3,0xD2,0xFF},{0xE8,0xC8,0xFF}, 25 | {0xFB,0xC2,0xFF},{0xFE,0xC4,0xEA},{0xFE,0xCC,0xC5},{0xF7,0xEC,0xE1}, 26 | {0xE4,0xE5,0x94},{0xCF,0xEF,0x96},{0xBD,0xF4,0xAB},{0xB3,0xF3,0xCC}, 27 | {0xB5,0xEB,0xF2},{0xB8,0xB8,0xB8},{0x00,0x00,0x00},{0x00,0x00,0x00} 28 | }; 29 | 30 | 31 | #endif -------------------------------------------------------------------------------- /source/cnrom.s: -------------------------------------------------------------------------------- 1 | @ ----------------------------------------------------------------- 2 | @ 3DNES unrom - Written by St4rk 3 | @ Date: 18/11/2014 4 | @ 3DNES é um emulador de Nintendo Entertainment System para 3DS 5 | @ esse é um projeto open-source, você pode modificar e utilizar 6 | @ os arquivos para estudo, desde que mantenha os devidos créditos 7 | @ ----------------------------------------------------------------- 8 | 9 | .arm 10 | .align 2 11 | .global cnrom_access 12 | .type cnrom_access STT_FUNC 13 | cnrom_access: @ void cnrom_acess(address, data) 14 | push {r0-r5, lr} 15 | ldr r2, =0x7FFF 16 | cmp r0, r2 17 | cmpgt r0, #0x10000 18 | blt cnrom_switch_prg 19 | b cnrom_end 20 | 21 | 22 | cnrom_switch_prg: 23 | @ data & (CHR - 1) 24 | ldr r2, =CHR 25 | sub r2, #0x1 26 | and r1, r1, r2 27 | 28 | @ address = 0x0000 29 | @ r2 prg_size = 16384 = 0x4000 30 | @ r3 chr_size = 8192 = 0x2000 31 | @ r4 chr_start = prg_size * PRG; 32 | ldr r2, =0x4000 33 | ldr r3, =0x2000 34 | ldr r4, =PRG 35 | @ r4 = chr_start 36 | mul r4, r2, r4 37 | 38 | @ memcpy(PPU_Memory + address, 39 | @ ROM_Cache + 16 + chr_start + (bank * chr_size), chr_size); 40 | 41 | @ ROM_Cache + 16 42 | ldr r0, =ROM_Cache+16 43 | @ ROM_Cache + chr_start 44 | add r0, r0, r4 45 | @ (Bank * chr_size) 46 | mul r4, r1, r3 47 | @ ROM_Cache + (bank * chr_Size) 48 | add r0, r0, r4 49 | @ PPU_Memory 50 | ldr r1, =PPU_Memory 51 | 52 | cnrom_memcpy: @ memcpy(r1, r0, r3) 53 | ldr r2, [r0], #4 54 | str r2, [r1], #4 55 | subs r2, r2, #4 56 | bge cnrom_memcpy 57 | 58 | 59 | cnrom_end: 60 | pop {r0-r5, pc} 61 | -------------------------------------------------------------------------------- /include/nesGlobal.h: -------------------------------------------------------------------------------- 1 | #ifndef NESGLOBAL_H 2 | #define NESGLOBAL_H 3 | 4 | #include 5 | #include <3ds.h> 6 | 7 | 8 | /*********************************************** 9 | ** All global defines will be declared here ** 10 | ************************************************/ 11 | 12 | #define BUTTON_A 1 13 | #define BUTTON_B 2 14 | #define BUTTON_UP 64 15 | #define BUTTON_LEFT 32 16 | #define BUTTON_DOWN 128 17 | #define BUTTON_RIGHT 16 18 | #define BUTTON_X 1024 19 | #define BUTTON_Y 2048 20 | #define BUTTON_L1 512 21 | #define BUTTON_R1 256 22 | #define BUTTON_START 8 23 | #define BUTTON_SELECT 4 24 | 25 | #define MAX_ROM_SIZE 0x100000 26 | 27 | /* memory[0x2000] */ 28 | #define exec_nmi_on_vblank (ppu_control1 & 0x80) /* 1 = Generate VBlank NMI */ 29 | #define sprite_16 (ppu_control1 & 0x20) /* 1 = Sprites 8x16/8x8 */ 30 | #define background_addr_hi (ppu_control1 & 0x10) /* 1 = BG pattern adr $0000/$1000 */ 31 | #define sprite_addr_hi (ppu_control1 & 0x08) /* 1 = Sprite pattern adr $0000/$1000 */ 32 | #define increment_32 (ppu_control1 & 0x04) /* 1 = auto increment 1/32 */ 33 | 34 | /* memory[0x2001] */ 35 | #define sprite_on (ppu_control2 & 0x10) /* 1 = Show sprite */ 36 | #define background_on (ppu_control2 & 0x08) /* 1 = Show background */ 37 | #define sprite_clipping_off (ppu_control2 & 0x04) /* 1 = 1 = No clipping */ 38 | #define background_clipping_off (ppu_control2 & 0x02) /* 1 = 1 = No clipping */ 39 | #define monochrome_on (ppu_control2 & 0x01) /* 1 = Display monochrome */ 40 | 41 | /* memory[0x2002] */ 42 | #define vblank_on (ppu_status & 0x80) /* 1 = In VBlank */ 43 | #define sprite_zero (ppu_status & 0x40) /* 1 = PPU has hit Sprite #0 */ 44 | #define scanline_sprite_count (ppu_status & 0x20) /* 1 = More than 8 sprites on current scanline */ 45 | #define vram_write_flag (ppu_status & 0x10) /* 1 = Writes to VRAM are ignored */ 46 | 47 | 48 | /*********************************************** 49 | ** All global variables will be declared here ** 50 | ************************************************/ 51 | 52 | extern u8 ROM_Cache[MAX_ROM_SIZE]; 53 | extern u8 *PPU_Memory; 54 | extern u8 *SPRITE_Memory; 55 | extern u8 *SRAM_Name; 56 | extern u8 frameSkip; 57 | extern u8 skipFrame; 58 | extern u8 ROM_Title[128]; 59 | 60 | extern u32 PAD1_Data; 61 | extern u64 ROM_Size; 62 | extern u32 line_ticks; 63 | 64 | extern bool CPU_Running; 65 | extern bool PAUSE_Emulation; 66 | extern bool ENABLE_Background; 67 | extern bool ENABLE_Sprite; 68 | extern bool inGame; 69 | extern bool VSYNC; 70 | 71 | #endif -------------------------------------------------------------------------------- /include/mmc1.h: -------------------------------------------------------------------------------- 1 | #include "nes6502.h" 2 | // TODO: Write in ASM 3 | 4 | int mmc1_reg[4]; 5 | int mmc1_seq; 6 | int mmc1_acc; 7 | 8 | void mmc1_switch_chr(int bank, int pagesize, int area) { 9 | int prg_size; 10 | int chr_size; 11 | int chr_start; 12 | 13 | unsigned int address; 14 | 15 | prg_size = 16384; 16 | 17 | chr_start = prg_size * PRG; 18 | 19 | if(pagesize == 0) { 20 | chr_size = 8192; 21 | address = 0x0000; 22 | } else if(pagesize == 1) { 23 | chr_size = 4096; 24 | if(area == 0) { 25 | address = 0x0000; 26 | } else if(area == 1) { 27 | address = 0x1000; 28 | } else { 29 | 30 | } 31 | } else { 32 | 33 | } 34 | 35 | memcpy(PPU_Memory + address, ROM_Cache + 16 + chr_start + (bank * chr_size), chr_size); 36 | } 37 | 38 | void mmc1_access(unsigned int address,unsigned char data) { 39 | int regnum; 40 | 41 | if(address > 0x7fff && address < 0x10000) { 42 | if(address > 0x7fff && address < 0xa000) {regnum = 0;} 43 | if(address > 0x9fff && address < 0xc000) {regnum = 1;} 44 | if(address > 0xbfff && address < 0xe000) {regnum = 2;} 45 | if(address > 0xdfff && address < 0x10000) {regnum = 3;} 46 | if (data & 0x80) { 47 | mmc1_reg[0] |= 0xC; 48 | mmc1_acc = mmc1_reg[regnum]; 49 | mmc1_seq = 5; 50 | } else { 51 | if (data & 1) {mmc1_acc |= (1 << mmc1_seq);} 52 | mmc1_seq++; 53 | } 54 | 55 | if (mmc1_seq == 5) { 56 | mmc1_reg[regnum] = mmc1_acc; 57 | mmc1_seq = 0; 58 | mmc1_acc = 0; 59 | 60 | //Mirroring 61 | if (mmc1_reg[0] & 2) { 62 | do_mirror((mmc1_reg[0] & 0x01) ^ 1); 63 | } else { 64 | do_mirror(2); 65 | } 66 | 67 | //Bank Switch PRG 68 | if ((mmc1_reg[0] & 0x08) == 0) { //32k PRG 69 | //Copia um banco de 32k 70 | memcpy(memory + 0x8000, ROM_Cache + 16 + (maskaddr((mmc1_reg[3] & 15) * 4) * 0x2000), 32768); 71 | } else { //16k PRG 72 | if (mmc1_reg[0] & 0x04) { 73 | //Copia dois bancos de 16k 74 | memcpy(memory + 0xC000, ROM_Cache + 16 + (maskaddr(0xFE) * 0x2000), 16384); 75 | memcpy(memory + 0x8000, ROM_Cache + 16 + (maskaddr((mmc1_reg[3] & 15) * 2) * 0x2000), 16384); 76 | } else { 77 | //Copia dois bancos de 16k 78 | memcpy(memory + 0x8000, ROM_Cache + 16, 16384); 79 | memcpy(memory + 0xC000, ROM_Cache + 16 + (maskaddr((mmc1_reg[3] & 15) * 2) * 0x2000), 16384); 80 | } 81 | } 82 | 83 | //Bank Switch CHR 84 | if (CHR != 0) { 85 | if(mmc1_reg[0] & 0x10) { //4k 86 | mmc1_switch_chr(mmc1_reg[1], 1, 0); 87 | mmc1_switch_chr(mmc1_reg[2], 1, 1); 88 | } else { //8k 89 | mmc1_switch_chr(mmc1_reg[1] / 2, 0, 0); 90 | } 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /source/nesSystem.c: -------------------------------------------------------------------------------- 1 | #include "nesSystem.h" 2 | 3 | 4 | /* SRAM Save and Load */ 5 | void SRAM_LOADSTATE() { 6 | /*Handle dirHandle; 7 | u32 bytesRead; 8 | 9 | u8 resultado[strlen(SRAM_Name) + strlen("/3DNES/SAVES/") + 1]; 10 | 11 | FS_StringConc( resultado, (u8*)"/3DNES/SAVES/", SRAM_Name); 12 | FS_path dirPath=FS_makePath(PATH_CHAR, "/3DNES/saves/"); 13 | 14 | FSUSER_OpenDirectory(NULL, &dirHandle, sdmcArchive, dirPath); 15 | 16 | Handle fileHandledump; 17 | FSUSER_OpenFile(NULL, &fileHandledump, sdmcArchive, FS_makePath(PATH_CHAR, resultado), FS_OPEN_WRITE|FS_OPEN_CREATE, FS_ATTRIBUTE_NONE); 18 | 19 | FSFILE_Read(fileHandledump, &bytesRead, 0x0, (u32*)&memory[0x6000],(u32)8192); 20 | 21 | FSFILE_Close(fileHandledump); 22 | */ 23 | } 24 | 25 | void SRAM_SAVESTATE() { 26 | /*Handle dirHandle; 27 | u32 bytesRead; 28 | 29 | u8 resultado[strlen(SRAM_Name) + strlen("/3DNES/SAVES/") + 1]; 30 | 31 | FS_StringConc( resultado, (u8*)"/3DNES/SAVES/", SRAM_Name); 32 | FS_path dirPath=FS_makePath(PATH_CHAR, "/3DNES/saves/"); 33 | 34 | FSUSER_OpenDirectory(NULL, &dirHandle, sdmcArchive, dirPath); 35 | 36 | Handle fileHandledump; 37 | FSUSER_OpenFile(NULL, &fileHandledump, sdmcArchive, FS_makePath(PATH_CHAR, resultado), FS_OPEN_WRITE|FS_OPEN_CREATE, FS_ATTRIBUTE_NONE); 38 | 39 | FSFILE_Write(fileHandledump, &bytesRead, 0x0, &memory[0x6000], 8192, 0x10001); 40 | 41 | FSFILE_Close(fileHandledump); 42 | */ 43 | } 44 | 45 | /* Emulation Stuff */ 46 | void SET_INPUT(u32 padKey) { 47 | switch(padKey) { 48 | /* pad_down */ 49 | case 1: 50 | PAD1_DOWN = 0x01; 51 | break; 52 | 53 | /* pad_up */ 54 | case 2: 55 | PAD1_UP = 0x01; 56 | break; 57 | 58 | /* pad_left */ 59 | case 3: 60 | PAD1_LEFT = 0x01; 61 | break; 62 | 63 | /* pad_right */ 64 | case 4: 65 | PAD1_RIGHT = 0x01; 66 | break; 67 | 68 | /* pad_start */ 69 | case 5: 70 | PAD1_START = 0x01; 71 | break; 72 | 73 | /* pad_select */ 74 | case 6: 75 | PAD1_SELECT = 0x01; 76 | break; 77 | 78 | /* pad_a */ 79 | case 7: 80 | PAD1_A = 0x01; 81 | break; 82 | 83 | /* pad_b */ 84 | case 8: 85 | PAD1_B = 0x01; 86 | break; 87 | 88 | default: 89 | 90 | break; 91 | } 92 | 93 | } 94 | 95 | void RESET_INPUT() { 96 | PAD1_DOWN = 0x40; 97 | PAD1_UP = 0x40; 98 | PAD1_LEFT = 0x40; 99 | PAD1_RIGHT = 0x40; 100 | PAD1_START = 0x40; 101 | PAD1_SELECT = 0x40; 102 | PAD1_A = 0x40; 103 | PAD1_B = 0x40; 104 | } 105 | 106 | 107 | void CLEAR_INPUT(u32 padKey) { 108 | switch(padKey) { 109 | /* pad_down */ 110 | case 1: 111 | PAD1_DOWN = 0x40; 112 | break; 113 | 114 | /* pad_up */ 115 | case 2: 116 | PAD1_UP = 0x40; 117 | break; 118 | 119 | /* pad_left */ 120 | case 3: 121 | PAD1_LEFT = 0x40; 122 | break; 123 | 124 | /* pad_right */ 125 | case 4: 126 | PAD1_RIGHT = 0x40; 127 | break; 128 | 129 | /* pad_start */ 130 | case 5: 131 | PAD1_START = 0x40; 132 | break; 133 | 134 | /* pad_select */ 135 | case 6: 136 | PAD1_SELECT = 0x40; 137 | break; 138 | 139 | /* pad_a */ 140 | case 7: 141 | PAD1_A = 0x40; 142 | break; 143 | 144 | /* pad_b */ 145 | case 8: 146 | PAD1_B = 0x40; 147 | break; 148 | 149 | default: 150 | /* never reached */ 151 | break; 152 | } 153 | } 154 | 155 | 156 | /* Save State and Load State */ 157 | // TODO : Save State of course 158 | void SAVE_STATE(int n) { 159 | 160 | } 161 | 162 | void LOAD_STATE(int n) { 163 | 164 | } -------------------------------------------------------------------------------- /source/nesLoadROM.c: -------------------------------------------------------------------------------- 1 | #include "nesLoadROM.h" 2 | 3 | u8 ROM_Header[15]; 4 | u8 ROM_Title[128]; 5 | 6 | int NES_LoadROM() { 7 | int i = 0; 8 | 9 | memcpy (ROM_Header, ROM_Cache, 15); 10 | 11 | /* Check if is a valid NES ROM */ 12 | if ((ROM_Header[0] != 'N' || (ROM_Header[1] != 'E') || (ROM_Header[2] != 'S'))) { 13 | 14 | return -1; 15 | } 16 | 17 | for (i = 8; i < 15; i++) { 18 | if ((ROM_Header[i] != 0x0) && (ROM_Header[i] != 0xFF)) { 19 | 20 | return -1; 21 | } 22 | } 23 | 24 | 25 | 26 | /* Load PRG, CHR, MAPPER, RCB etc */ 27 | PRG = ROM_Header[4]; 28 | CHR = ROM_Header[5]; 29 | MAPPER = (ROM_Header[6] >> 4) | (ROM_Header[7] & 0x0F); 30 | RCB = (ROM_Header[6] - ((ROM_Header[6] >> 4) << 4)); 31 | 32 | switch (RCB) { 33 | case 0x00: 34 | /* horizontal mirroring only */ 35 | MIRRORING = 0; 36 | SRAM = 0; 37 | TRAINER = 0; 38 | FS_MIRROR = 0; 39 | break; 40 | 41 | case 0x01: 42 | /* vertical mirroring only */ 43 | MIRRORING = 1; 44 | SRAM = 0; 45 | TRAINER = 0; 46 | FS_MIRROR = 0; 47 | break; 48 | 49 | case 0x02: 50 | /* horizontal mirroring and sram enabled */ 51 | MIRRORING = 0; 52 | SRAM = 1; 53 | TRAINER = 0; 54 | FS_MIRROR = 0; 55 | break; 56 | 57 | case 0x03: 58 | /* vertical mirroring and sram enabled */ 59 | MIRRORING = 1; 60 | SRAM = 1; 61 | TRAINER = 0; 62 | FS_MIRROR = 0; 63 | break; 64 | 65 | case 0x04: 66 | /* horizontal mirroring and trainer on */ 67 | MIRRORING = 0; 68 | SRAM = 0; 69 | TRAINER = 1; 70 | FS_MIRROR = 0; 71 | break; 72 | 73 | case 0x05: 74 | /* vertical mirroring and trainer on */ 75 | MIRRORING = 1; 76 | SRAM = 0; 77 | TRAINER = 1; 78 | FS_MIRROR = 0; 79 | break; 80 | 81 | case 0x06: 82 | /* horizontal mirroring, sram enabled and trainer on */ 83 | MIRRORING = 0; 84 | SRAM = 1; 85 | TRAINER = 1; 86 | FS_MIRROR = 0; 87 | break; 88 | 89 | case 0x07: 90 | /* vertical mirroring, sram enabled and trainer on */ 91 | MIRRORING = 1; 92 | SRAM = 1; 93 | TRAINER = 1; 94 | FS_MIRROR = 0; 95 | break; 96 | 97 | case 0x08: 98 | /* horizontal mirroring and four screen vram on */ 99 | MIRRORING = 0; 100 | SRAM = 0; 101 | TRAINER = 0; 102 | FS_MIRROR = 1; 103 | break; 104 | 105 | case 0x09: 106 | /* vertical mirroring and four screen vram on */ 107 | MIRRORING = 1; 108 | SRAM = 0; 109 | TRAINER = 0; 110 | FS_MIRROR = 1; 111 | break; 112 | 113 | case 0x0A: 114 | /* horizontal mirroring, sram enabled and four screen vram on */ 115 | MIRRORING = 0; 116 | SRAM = 1; 117 | TRAINER = 0; 118 | FS_MIRROR = 1; 119 | break; 120 | 121 | case 0x0B: 122 | /* vertical mirroring, sram enabled and four screen vram on */ 123 | MIRRORING = 1; 124 | SRAM = 1; 125 | TRAINER = 0; 126 | FS_MIRROR = 1; 127 | break; 128 | 129 | case 0x0C: 130 | /* horizontal mirroring, trainer on and four screen vram on */ 131 | MIRRORING = 0; 132 | SRAM = 0; 133 | TRAINER = 1; 134 | FS_MIRROR = 1; 135 | break; 136 | 137 | case 0x0D: 138 | /* vertical mirroring, trainer on and four screen vram on */ 139 | MIRRORING = 1; 140 | SRAM = 0; 141 | TRAINER = 1; 142 | FS_MIRROR = 1; 143 | break; 144 | 145 | case 0x0E: 146 | /* horizontal mirroring, sram enabled, trainer on and four screen vram on */ 147 | MIRRORING = 0; 148 | SRAM = 1; 149 | TRAINER = 1; 150 | FS_MIRROR = 1; 151 | break; 152 | 153 | case 0x0F: 154 | /* vertical mirroring, sram enabled, trainer on and four screen vram on */ 155 | MIRRORING = 1; 156 | SRAM = 1; 157 | TRAINER = 1; 158 | FS_MIRROR = 1; 159 | break; 160 | 161 | default: 162 | // TODO: Err Msg 163 | return -1; 164 | break; 165 | 166 | } 167 | 168 | 169 | /* load prg data in memory */ 170 | if(PRG == 0x01) { 171 | /* map 16kb in mirror mode */ 172 | memcpy(memory + 0x8000, ROM_Cache + 16, 16384); 173 | memcpy(memory + 0xC000, ROM_Cache + 16, 16384); 174 | } else { 175 | /* map 2x 16kb the first one into 8000 and the last one into c000 */ 176 | memcpy(memory + 0x8000, ROM_Cache + 16, 16384); 177 | memcpy(memory + 0xC000, ROM_Cache + 16 + ((PRG - 1) * 16384), 16384); 178 | } 179 | 180 | /* load chr data in ppu memory */ 181 | if(CHR != 0x00) { 182 | memcpy(PPU_Memory, ROM_Cache + 16 + (PRG * 16384), 8192); 183 | 184 | /* fetch title from last 128 bytes */ 185 | memcpy(ROM_Title, ROM_Cache + 16 + (PRG * 16384) + 8192, 128); 186 | 187 | } 188 | 189 | 190 | return 0; 191 | } -------------------------------------------------------------------------------- /include/mmc3.h: -------------------------------------------------------------------------------- 1 | 2 | // TODO: Write in ASM 3 | unsigned char mmc3_cmd; 4 | 5 | int mmc3_prg_bank0 = 0; 6 | int mmc3_prg_bank1 = 0; 7 | 8 | int mmc3_prg_page = 0; 9 | 10 | int mmc3_chr_xor = 0; 11 | 12 | int mmc3_irq_counter = 0; 13 | int mmc3_irq_latch; 14 | int mmc3_irq_control0; 15 | int mmc3_irq_control1; 16 | int mmc3_irq_enable = 0; 17 | 18 | int mmc3_prg_addr; 19 | 20 | void 21 | mmc3_reset() 22 | { 23 | memcpy(memory + 0xa000, ROM_Cache + 16, 8192); 24 | } 25 | 26 | void 27 | mmc3_switch_prg(unsigned int address, int bank) 28 | { 29 | int prg_size = 8192; 30 | memcpy(memory + address, ROM_Cache + 16 + (bank * prg_size), prg_size); 31 | } 32 | 33 | void 34 | mmc3_switch_chr(unsigned int address, int bank, int pagecount) 35 | { 36 | if (CHR != 0) { 37 | int prg_size; 38 | int chr_size; 39 | int chr_start; 40 | 41 | prg_size = 16384; 42 | chr_size = 1024; 43 | 44 | chr_start = prg_size * PRG; 45 | 46 | memcpy(PPU_Memory + address, ROM_Cache + 16 + chr_start + (bank * chr_size), chr_size * pagecount); 47 | } 48 | } 49 | 50 | void 51 | mmc3_access(unsigned int address,unsigned char data) 52 | { 53 | switch(address) { 54 | case 0x8000: 55 | /* store command */ 56 | mmc3_cmd = data & 7; 57 | mmc3_prg_addr = data & 0x40; 58 | 59 | /* check for chr swapping */ 60 | if(data & 0x80) { 61 | mmc3_chr_xor = 1; 62 | } else { 63 | mmc3_chr_xor = 0; 64 | } 65 | break; 66 | case 0x8001: 67 | /* exec command (bit 0-2)*/ 68 | switch(mmc3_cmd){ 69 | case 0: 70 | if(mmc3_chr_xor == 0) { 71 | mmc3_switch_chr(0x0000, data, 2); 72 | } else { 73 | mmc3_switch_chr(0x1000, data, 2); 74 | } 75 | break; 76 | 77 | case 1: 78 | if(mmc3_chr_xor == 0) { 79 | mmc3_switch_chr(0x0800, data, 2); 80 | } else { 81 | mmc3_switch_chr(0x1800, data, 2); 82 | } 83 | break; 84 | 85 | case 2: 86 | if(mmc3_chr_xor == 0) { 87 | mmc3_switch_chr(0x1000, data, 1); 88 | } else { 89 | mmc3_switch_chr(0x0000, data, 1); 90 | } 91 | break; 92 | 93 | case 3: 94 | if(mmc3_chr_xor == 0) { 95 | mmc3_switch_chr(0x1400, data, 1); 96 | } else { 97 | mmc3_switch_chr(0x400, data, 1); 98 | } 99 | break; 100 | 101 | case 4: 102 | if(mmc3_chr_xor == 0) { 103 | mmc3_switch_chr(0x1800, data, 1); 104 | } else { 105 | mmc3_switch_chr(0x800, data, 1); 106 | } 107 | break; 108 | 109 | case 5: 110 | if(mmc3_chr_xor == 0) { 111 | mmc3_switch_chr(0x1c00, data, 1); 112 | } else { 113 | mmc3_switch_chr(0x0c00, data, 1); 114 | } 115 | break; 116 | 117 | case 6: mmc3_prg_bank0 = data; break; 118 | case 7: mmc3_prg_bank1 = data; break; 119 | } 120 | 121 | if ((mmc3_cmd == 6) || (mmc3_cmd == 7)) { 122 | if(mmc3_prg_addr) { 123 | mmc3_switch_prg(0x8000,(PRG << 1) - 2); 124 | mmc3_switch_prg(0xa000,mmc3_prg_bank1); 125 | mmc3_switch_prg(0xc000,mmc3_prg_bank0); 126 | mmc3_switch_prg(0xe000,(PRG << 1) - 1); 127 | } else { 128 | mmc3_switch_prg(0x8000,mmc3_prg_bank0); 129 | mmc3_switch_prg(0xa000,mmc3_prg_bank1); 130 | mmc3_switch_prg(0xc000,(PRG << 1) - 2); 131 | mmc3_switch_prg(0xe000,(PRG << 1) - 1); 132 | } 133 | } 134 | break; 135 | case 0xa000: 136 | /* set horizontal/vertical mirroring */ 137 | if(data & 0x01) { 138 | /* set to vertical */ 139 | //MIRRORING = 1; 140 | do_mirror(0); 141 | } else { 142 | /* set to horizontal */ 143 | //MIRRORING = 0; 144 | do_mirror(1); 145 | } 146 | break; 147 | case 0xa001: if(data) SRAM = 1; break; 148 | case 0xc000: 149 | /* set IRQ counter */ 150 | mmc3_irq_counter = data; 151 | break; 152 | case 0xc001: 153 | /* set IRQ tmp latch */ 154 | mmc3_irq_latch = data; 155 | break; 156 | case 0xe000: 157 | mmc3_irq_counter = mmc3_irq_latch; 158 | mmc3_irq_enable = 0; 159 | break; 160 | case 0xe001: mmc3_irq_enable = 1; break; 161 | } 162 | } 163 | 164 | void mmc3_hblank(int scanline) { 165 | if (scanline == 0) { 166 | mmc3_irq_counter = mmc3_irq_latch; 167 | } else { 168 | if(mmc3_irq_enable && (ppu_control2 & 0x18)) { //MMC3 IRQ 169 | mmc3_irq_counter = (mmc3_irq_counter - 1) & 0xFF; 170 | if(mmc3_irq_counter == 0) { 171 | // TODO: Fix tick 172 | // tick_count = 0; //[!!!] Workaround: Conserta partes da tela balançando em SMB3, Kirby 173 | IRQ(); 174 | mmc3_irq_counter = mmc3_irq_latch; 175 | } 176 | } 177 | } 178 | } -------------------------------------------------------------------------------- /ccd00.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | STARTUP(build/crt0.o) 4 | 5 | MEMORY { 6 | 7 | memregion : ORIGIN = 0x00100000, LENGTH = 2395K 8 | } 9 | 10 | __memregion_start = ORIGIN(memregion); 11 | __memregion_top = ORIGIN(memregion)+ LENGTH(memregion); 12 | 13 | PHDRS 14 | { 15 | text PT_LOAD FLAGS(5); 16 | rodata PT_LOAD FLAGS(4); 17 | data PT_LOAD FLAGS(6); 18 | bss PT_LOAD; 19 | } 20 | 21 | SECTIONS 22 | { 23 | .init : ALIGN(0x1000) 24 | { 25 | __text_start = . ; 26 | KEEP (*(.init)) 27 | /*. = ALIGN(4); REQUIRED. LD is flaky without it. */ 28 | } >memregion :text 29 | 30 | .plt : 31 | { 32 | *(.plt) 33 | } >memregion = 0xff 34 | 35 | .text : ALIGN (0x1000) 36 | { 37 | 38 | *(.text*) 39 | *(.stub) 40 | /* .gnu.warning sections are handled specially by elf32.em. */ 41 | *(.gnu.warning) 42 | *(.gnu.linkonce.t*) 43 | *(.glue_7) 44 | *(.glue_7t) 45 | /*. = ALIGN(4); REQUIRED. LD is flaky without it. */ 46 | } >memregion 47 | 48 | .fini : 49 | { 50 | KEEP (*(.fini)) 51 | . = ALIGN(0x1000); 52 | } >memregion 53 | 54 | __text_end = . ; 55 | 56 | .rodata : 57 | { 58 | *(.rodata) 59 | *all.rodata*(*) 60 | *(.roda) 61 | *(.rodata.*) 62 | *(.gnu.linkonce.r*) 63 | SORT(CONSTRUCTORS) 64 | . = ALIGN(0x1000); /* REQUIRED. LD is flaky without it. */ 65 | } >memregion :rodata 66 | 67 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >memregion 68 | __exidx_start = .; 69 | .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >memregion 70 | __exidx_end = .; 71 | 72 | /* Ensure the __preinit_array_start label is properly aligned. We 73 | could instead move the label definition inside the section, but 74 | the linker would then create the section even if it turns out to 75 | be empty, which isn't pretty. */ 76 | . = ALIGN(32 / 8); 77 | PROVIDE (__preinit_array_start = .); 78 | .preinit_array : { KEEP (*(.preinit_array)) } >memregion :data 79 | PROVIDE (__preinit_array_end = .); 80 | PROVIDE (__init_array_start = .); 81 | .init_array : { KEEP (*(.init_array)) } >memregion :data 82 | PROVIDE (__init_array_end = .); 83 | PROVIDE (__fini_array_start = .); 84 | .fini_array : { KEEP (*(.fini_array)) } >memregion = 0xff 85 | PROVIDE (__fini_array_end = .); 86 | 87 | .ctors : ALIGN(0x1000) 88 | { 89 | /* gcc uses crtbegin.o to find the start of the constructors, so 90 | we make sure it is first. Because this is a wildcard, it 91 | doesn't matter if the user does not actually link against 92 | crtbegin.o; the linker won't look for a file to match a 93 | wildcard. The wildcard also means that it doesn't matter which 94 | directory crtbegin.o is in. */ 95 | KEEP (*crtbegin.o(.ctors)) 96 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 97 | KEEP (*(SORT(.ctors.*))) 98 | KEEP (*(.ctors)) 99 | /*. = ALIGN(4); REQUIRED. LD is flaky without it. */ 100 | } >memregion = 0xff 101 | 102 | .dtors : ALIGN(0x1000) 103 | { 104 | KEEP (*crtbegin.o(.dtors)) 105 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 106 | KEEP (*(SORT(.dtors.*))) 107 | KEEP (*(.dtors)) 108 | /*. = ALIGN(4); REQUIRED. LD is flaky without it. */ 109 | } >memregion = 0xff 110 | 111 | .eh_frame : ALIGN(0x1000) 112 | { 113 | KEEP (*(.eh_frame)) 114 | /*. = ALIGN(4); REQUIRED. LD is flaky without it. */ 115 | } >memregion = 0xff 116 | 117 | .gcc_except_table : ALIGN(0x1000) 118 | { 119 | *(.gcc_except_table) 120 | /*. = ALIGN(4); REQUIRED. LD is flaky without it. */ 121 | } >memregion = 0xff 122 | .jcr : { KEEP (*(.jcr)) } >memregion = 0 123 | 124 | .got : 125 | { 126 | __got_start = ABSOLUTE(.); 127 | *(.got.plt) *(.got) 128 | } >memregion = 0 129 | __got_end = . ; 130 | 131 | .memregion ALIGN(4) : 132 | { 133 | __memregion_start = ABSOLUTE(.) ; 134 | *(.memregion) 135 | *memregion.*(.text) 136 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 137 | __memregion_end = ABSOLUTE(.) ; 138 | } >memregion = 0xff 139 | 140 | 141 | .data ALIGN(4) : { 142 | __data_start = ABSOLUTE(.); 143 | *(.data) 144 | *(.data.*) 145 | *(.gnu.linkonce.d*) 146 | CONSTRUCTORS 147 | . = ALIGN(0x1000); 148 | __data_end = ABSOLUTE(.) ; 149 | } >memregion :data 150 | 151 | 152 | 153 | .bss ALIGN(0x1000) : 154 | { 155 | __bss_start = ABSOLUTE(.); 156 | __bss_start__ = ABSOLUTE(.); 157 | *(.dynbss) 158 | *(.gnu.linkonce.b*) 159 | *(.bss*) 160 | *(COMMON) 161 | /*. = ALIGN(4); REQUIRED. LD is flaky without it. */ 162 | } >memregion :bss 163 | 164 | __bss_end = . ; 165 | __bss_end__ = . ; 166 | 167 | _end = . ; 168 | __end__ = . ; 169 | PROVIDE (end = _end); 170 | 171 | /* Stabs debugging sections. */ 172 | .stab 0 : { *(.stab) } 173 | .stabstr 0 : { *(.stabstr) } 174 | .stab.excl 0 : { *(.stab.excl) } 175 | .stab.exclstr 0 : { *(.stab.exclstr) } 176 | .stab.index 0 : { *(.stab.index) } 177 | .stab.indexstr 0 : { *(.stab.indexstr) } 178 | .comment 0 : { *(.comment) } 179 | /* DWARF debug sections. 180 | Symbols in the DWARF debugging sections are relative to the beginning 181 | of the section so we begin them at 0. */ 182 | /* DWARF 1 */ 183 | .debug 0 : { *(.debug) } 184 | .line 0 : { *(.line) } 185 | /* GNU DWARF 1 extensions */ 186 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 187 | .debug_sfnames 0 : { *(.debug_sfnames) } 188 | /* DWARF 1.1 and DWARF 2 */ 189 | .debug_aranges 0 : { *(.debug_aranges) } 190 | .debug_pubnames 0 : { *(.debug_pubnames) } 191 | /* DWARF 2 */ 192 | .debug_info 0 : { *(.debug_info) } 193 | .debug_abbrev 0 : { *(.debug_abbrev) } 194 | .debug_line 0 : { *(.debug_line) } 195 | .debug_frame 0 : { *(.debug_frame) } 196 | .debug_str 0 : { *(.debug_str) } 197 | .debug_loc 0 : { *(.debug_loc) } 198 | .debug_macinfo 0 : { *(.debug_macinfo) } 199 | /* SGI/MIPS DWARF 2 extensions */ 200 | .debug_weaknames 0 : { *(.debug_weaknames) } 201 | .debug_funcnames 0 : { *(.debug_funcnames) } 202 | .debug_typenames 0 : { *(.debug_typenames) } 203 | .debug_varnames 0 : { *(.debug_varnames) } 204 | .stack 0x80000 : { _stack = .; *(.stack) } 205 | /* These must appear regardless of . */ 206 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | ifeq ($(strip $(CTRULIB)),) 10 | # THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru 11 | $(error "Please set CTRULIB in your environment. export CTRULIB=libctru") 12 | endif 13 | 14 | TOPDIR ?= $(CURDIR) 15 | include $(DEVKITARM)/3ds_rules 16 | 17 | #--------------------------------------------------------------------------------- 18 | # TARGET is the name of the output 19 | # BUILD is the directory where object files & intermediate files will be placed 20 | # SOURCES is a list of directories containing source code 21 | # DATA is a list of directories containing data files 22 | # INCLUDES is a list of directories containing header files 23 | # SPECS is the directory containing the important build and link files 24 | #--------------------------------------------------------------------------------- 25 | export TARGET := $(shell basename $(CURDIR)) 26 | BUILD := build 27 | SOURCES := source 28 | DATA := data 29 | INCLUDES := include 30 | 31 | 32 | #--------------------------------------------------------------------------------- 33 | # options for code generation 34 | #--------------------------------------------------------------------------------- 35 | ARCH := -march=armv6k -mtune=mpcore 36 | 37 | CFLAGS := -g -Wall -O3 -mword-relocations -save-temps \ 38 | -fomit-frame-pointer -ffast-math -mfloat-abi=softfp \ 39 | $(ARCH) 40 | 41 | CFLAGS += $(INCLUDE) -DARM11 -D_3DS 42 | 43 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 44 | 45 | ASFLAGS := -g $(ARCH) 46 | LDFLAGS = -specs=3dsx.specs -g $(ARCH) \ 47 | -Wl,-Map,$(TARGET).map 48 | 49 | LIBS := -lctru -lm 50 | 51 | #--------------------------------------------------------------------------------- 52 | # list of directories containing libraries, this must be the top level containing 53 | # include and lib 54 | #--------------------------------------------------------------------------------- 55 | LIBDIRS := $(CTRULIB) 56 | 57 | 58 | #--------------------------------------------------------------------------------- 59 | # no real need to edit anything past this point unless you need to add additional 60 | # rules for different file extensions 61 | #--------------------------------------------------------------------------------- 62 | ifneq ($(BUILD),$(notdir $(CURDIR))) 63 | #--------------------------------------------------------------------------------- 64 | 65 | export OUTPUT := $(CURDIR)/$(TARGET) 66 | export TOPDIR := $(CURDIR) 67 | 68 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 69 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 70 | 71 | export DEPSDIR := $(CURDIR)/$(BUILD) 72 | 73 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 74 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 75 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 76 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 77 | 78 | #--------------------------------------------------------------------------------- 79 | # use CXX for linking C++ projects, CC for standard C 80 | #--------------------------------------------------------------------------------- 81 | ifeq ($(strip $(CPPFILES)),) 82 | #--------------------------------------------------------------------------------- 83 | export LD := $(CC) 84 | #--------------------------------------------------------------------------------- 85 | else 86 | #--------------------------------------------------------------------------------- 87 | export LD := $(CXX) 88 | #--------------------------------------------------------------------------------- 89 | endif 90 | #--------------------------------------------------------------------------------- 91 | 92 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 93 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 94 | 95 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 96 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 97 | -I$(CURDIR)/$(BUILD) 98 | 99 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 100 | 101 | .PHONY: $(BUILD) clean all 102 | 103 | #--------------------------------------------------------------------------------- 104 | all: $(BUILD) 105 | 106 | $(BUILD): 107 | @[ -d $@ ] || mkdir -p $@ 108 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 109 | 110 | #--------------------------------------------------------------------------------- 111 | clean: 112 | @echo clean ... 113 | @rm -fr $(BUILD) $(TARGET).3dsx $(TARGET).elf 114 | 115 | 116 | #--------------------------------------------------------------------------------- 117 | else 118 | 119 | DEPENDS := $(OFILES:.o=.d) 120 | 121 | #--------------------------------------------------------------------------------- 122 | # main targets 123 | #--------------------------------------------------------------------------------- 124 | $(OUTPUT).3dsx : $(OUTPUT).elf 125 | $(OUTPUT).elf : $(OFILES) 126 | 127 | #--------------------------------------------------------------------------------- 128 | # you need a rule like this for each extension you use as binary data 129 | #--------------------------------------------------------------------------------- 130 | %.bin.o : %.bin 131 | #--------------------------------------------------------------------------------- 132 | @echo $(notdir $<) 133 | @$(bin2o) 134 | 135 | # not the right way to do this 136 | #--------------------------------------------------------------------------------- 137 | %.vsh.o : %.vsh 138 | #--------------------------------------------------------------------------------- 139 | @echo $(notdir $<) 140 | @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin 141 | @bin2s ../$(notdir $<).shbin | arm-none-eabi-as -o $@ 142 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h 143 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h 144 | @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h 145 | @rm ../$(notdir $<).shbin 146 | 147 | -include $(DEPENDS) 148 | 149 | #--------------------------------------------------------------------------------------- 150 | endif 151 | #--------------------------------------------------------------------------------------- 152 | -------------------------------------------------------------------------------- /cci/build_cia.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "3DNES" 3 | CompanyCode : "00" 4 | ProductCode : "CTR-N-3DNX" 5 | ContentType : Application # Application / SystemUpdate / Manual / Child / Trial 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | Rom: 9 | # Specifies the root path of the file system to include in the ROM. 10 | # HostRoot : "$(ROMFS_ROOT)" 11 | 12 | 13 | TitleInfo: 14 | UniqueId : 0xf0021 # This was/is the first real homebrew app. I hope this TID range is not used by any retail game/app. 15 | Category : Application # Application / SystemApplication / Applet / Firmware / Base / DlpChild / Demo / Contents / SystemContents / SharedContents / AddOnContents / Patch / AutoUpdateContents 16 | 17 | CardInfo: 18 | MediaSize : 512MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB 19 | MediaType : Card1 # Card1 / Card2 20 | CardDevice : NorFlash # NorFlash / None 21 | 22 | 23 | Option: 24 | UseOnSD : true # true if App is to be installed to SD 25 | EnableCompress : true # Compresses exefs code 26 | FreeProductCode : true # Removes limitations on ProductCode 27 | EnableCrypt : false # Enables encryption for NCCH and CIA 28 | MediaFootPadding : false # If true CCI files are created with padding 29 | 30 | ExeFs: # these are the program segments from the ELF, check your elf for the appropriate segment names 31 | ReadOnly: 32 | - .rodata 33 | - RO 34 | ReadWrite: 35 | - .data 36 | - RO 37 | Text: 38 | - .init 39 | - .text 40 | - STUP_ENTRY 41 | 42 | PlainRegion: # only used with SDK ELFs 43 | # - .module_id 44 | 45 | AccessControlInfo: 46 | # UseOtherVariationSaveData : true 47 | # UseExtSaveData : true 48 | # ExtSaveDataId: 0xffffffff 49 | # SystemSaveDataId1: 0x220 50 | # SystemSaveDataId2: 0x00040010 51 | # OtherUserSaveDataId1: 0x220 52 | # OtherUserSaveDataId2: 0x330 53 | # OtherUserSaveDataId3: 0x440 54 | # UseExtendedSaveDataAccessControl: true 55 | # AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 56 | FileSystemAccess: 57 | # - CategorySystemApplication 58 | # - CategoryHardwareCheck 59 | # - CategoryFileSystemTool 60 | - Debug 61 | # - TwlCardBackup 62 | # - TwlNandData 63 | # - Boss 64 | - DirectSdmc 65 | # - Core 66 | # - CtrNandRo 67 | # - CtrNandRw 68 | # - CtrNandRoWrite 69 | # - CategorySystemSettings 70 | # - CardBoard 71 | # - ExportImportIvs 72 | # - DirectSdmcWrite 73 | # - SwitchCleanup 74 | # - SaveDataMove 75 | # - Shop 76 | # - Shell 77 | # - CategoryHomeMenu 78 | IoAccessControl: 79 | # - FsMountNand 80 | # - FsMountNandRoWrite 81 | # - FsMountTwln 82 | # - FsMountWnand 83 | # - FsMountCardSpi 84 | # - UseSdif3 85 | # - CreateSeed 86 | # - UseCardSpi 87 | 88 | IdealProcessor : 0 89 | AffinityMask : 1 90 | 91 | Priority : 16 92 | 93 | MaxCpu : 0x9E # Default 94 | 95 | DisableDebug : true 96 | EnableForceDebug : false 97 | CanWriteSharedPage : true 98 | CanUsePrivilegedPriority : false 99 | CanUseNonAlphabetAndNumber : true 100 | PermitMainFunctionArgument : true 101 | CanShareDeviceMemory : true 102 | RunnableOnSleep : false 103 | SpecialMemoryArrange : true 104 | 105 | CoreVersion : 2 106 | DescVersion : 2 107 | 108 | ReleaseKernelMajor : "02" 109 | ReleaseKernelMinor : "33" 110 | MemoryType : Application # Application / System / Base 111 | HandleTableSize: 512 112 | IORegisterMapping: 113 | - 1ff50000-1ff57fff 114 | - 1ff70000-1ff77fff 115 | MemoryMapping: 116 | - 1f000000-1f5fffff:r 117 | SystemCallAccess: 118 | ArbitrateAddress: 34 119 | Break: 60 120 | CancelTimer: 28 121 | ClearEvent: 25 122 | ClearTimer: 29 123 | CloseHandle: 35 124 | ConnectToPort: 45 125 | ControlMemory: 1 126 | CreateAddressArbiter: 33 127 | CreateEvent: 23 128 | CreateMemoryBlock: 30 129 | CreateMutex: 19 130 | CreateSemaphore: 21 131 | CreateThread: 8 132 | CreateTimer: 26 133 | DuplicateHandle: 39 134 | ExitProcess: 3 135 | ExitThread: 9 136 | GetCurrentProcessorNumber: 17 137 | GetHandleInfo: 41 138 | GetProcessId: 53 139 | GetProcessIdOfThread: 54 140 | GetProcessIdealProcessor: 6 141 | GetProcessInfo: 43 142 | GetResourceLimit: 56 143 | GetResourceLimitCurrentValues: 58 144 | GetResourceLimitLimitValues: 57 145 | GetSystemInfo: 42 146 | GetSystemTick: 40 147 | GetThreadContext: 59 148 | GetThreadId: 55 149 | GetThreadIdealProcessor: 15 150 | GetThreadInfo: 44 151 | GetThreadPriority: 11 152 | MapMemoryBlock: 31 153 | OutputDebugString: 61 154 | QueryMemory: 2 155 | ReleaseMutex: 20 156 | ReleaseSemaphore: 22 157 | SendSyncRequest1: 46 158 | SendSyncRequest2: 47 159 | SendSyncRequest3: 48 160 | SendSyncRequest4: 49 161 | SendSyncRequest: 50 162 | SetThreadPriority: 12 163 | SetTimer: 27 164 | SignalEvent: 24 165 | SleepThread: 10 166 | UnmapMemoryBlock: 32 167 | WaitSynchronization1: 36 168 | WaitSynchronizationN: 37 169 | InterruptNumbers: 170 | ServiceAccessControl: 171 | - APT:U 172 | - $hioFIO 173 | - $hostio0 174 | - $hostio1 175 | - ac:u 176 | - boss:U 177 | - cam:u 178 | - cecd:u 179 | - cfg:u 180 | - dlp:FKCL 181 | - dlp:SRVR 182 | - dsp::DSP 183 | - frd:u 184 | - fs:USER 185 | - gsp::Gpu 186 | - hid:USER 187 | - http:C 188 | - mic:u 189 | - ndm:u 190 | - news:u 191 | - nwm::UDS 192 | - ptm:u 193 | - pxi:dev 194 | - soc:U 195 | - ssl:C 196 | - y2r:u 197 | - ldr:ro 198 | - ir:USER 199 | 200 | 201 | SystemControlInfo: 202 | SaveDataSize: 0KB # It doesn't use any save data. 203 | RemasterVersion: 2 204 | StackSize: 0x40000 205 | # JumpId: 0 206 | Dependency: 207 | ac: 0x0004013000002402L 208 | am: 0x0004013000001502L 209 | boss: 0x0004013000003402L 210 | camera: 0x0004013000001602L 211 | cecd: 0x0004013000002602L 212 | cfg: 0x0004013000001702L 213 | codec: 0x0004013000001802L 214 | csnd: 0x0004013000002702L 215 | dlp: 0x0004013000002802L 216 | dsp: 0x0004013000001a02L 217 | friends: 0x0004013000003202L 218 | gpio: 0x0004013000001b02L 219 | gsp: 0x0004013000001c02L 220 | hid: 0x0004013000001d02L 221 | http: 0x0004013000002902L 222 | i2c: 0x0004013000001e02L 223 | ir: 0x0004013000003302L 224 | mcu: 0x0004013000001f02L 225 | mic: 0x0004013000002002L 226 | ndm: 0x0004013000002b02L 227 | news: 0x0004013000003502L 228 | nim: 0x0004013000002c02L 229 | nwm: 0x0004013000002d02L 230 | pdn: 0x0004013000002102L 231 | ps: 0x0004013000003102L 232 | ptm: 0x0004013000002202L 233 | ro: 0x0004013000003702L 234 | socket: 0x0004013000002e02L 235 | spi: 0x0004013000002302L 236 | ssl: 0x0004013000002f02L -------------------------------------------------------------------------------- /source/FileSystem.c: -------------------------------------------------------------------------------- 1 | #include "FileSystem.h" 2 | #include "nesGlobal.h" 3 | 4 | 5 | u8 ROM_Cache[MAX_ROM_SIZE]; 6 | u8 *SRAM_Name; 7 | 8 | u64 ROM_Size; 9 | 10 | FS_archive sdmcArchive; 11 | 12 | extern bool inGame; 13 | extern bool VSYNC; 14 | extern bool CPU_Running; 15 | 16 | extern u8 frameSkip; 17 | 18 | void unicodeToChar(char* dst, u16* src) { 19 | if(!src || !dst)return; 20 | while(*src)*(dst++)=(*(src++))&0xFF; 21 | *dst=0x00; 22 | } 23 | 24 | 25 | void NES_LOADROMLIST() { 26 | Handle romHandle; 27 | 28 | FS_dirent dirStruct; 29 | FS_path dirPath = FS_makePath(PATH_CHAR, "/3DNES/ROMS"); 30 | 31 | // init SDMC archive 32 | sdmcArchive = (FS_archive){0x9, (FS_path){PATH_EMPTY, 1, (u8*)""}}; 33 | FSUSER_OpenArchive(NULL, &sdmcArchive); 34 | FSUSER_OpenDirectory(NULL, &romHandle, sdmcArchive, dirPath); 35 | 36 | // Get number of files in directory 37 | fileSystem.totalFiles = 0 38 | while(1) { 39 | u32 dataRead = 0; 40 | FSDIR_Read(romHandle, &dataRead, 1, &dirStruct); 41 | if(dataRead == 0) break; 42 | fileSystem.totalFiles++; 43 | } 44 | 45 | fileSystem.fileList = linearAlloc(MAX_FILENAME_SIZE * fileSystem.totalFiles); 46 | 47 | FSUSER_OpenDirectory(NULL, &romHandle, sdmcArchive, dirPath); 48 | 49 | fileSystem.totalFiles = 0; 50 | while(1) { 51 | u32 dataRead = 0; 52 | FSDIR_Read(romHandle, &dataRead, 1, &dirStruct); 53 | if(dataRead == 0) break; 54 | unicodeToChar(&fileSystem.fileList[MAX_FILENAME_SIZE * fileSystem.totalFiles), dirStruct.name); 55 | fileSystem.totalFiles++; 56 | } 57 | 58 | FSDIR_Close(romHandle); 59 | } 60 | 61 | /* Draw All ROM's */ 62 | void NES_drawROMLIST() { 63 | int i = 0; 64 | 65 | for(i = 0; i < fileSystem.totalFiles; i++) { 66 | draw_string_c(55 + (i * 15), fileSystem.fileList[i * MAX_FILENAME_SIZE]); 67 | } 68 | 69 | draw_string(10, (fileSystem.cFile * 15) + 53, "->"); 70 | 71 | } 72 | 73 | /* Draw Configuration Menu */ 74 | void NES_drawConfigurationMenu() { 75 | char gameFPS[18]; 76 | 77 | 78 | draw_string(10, (fileSystem.cConfig* 15) + 70, "->"); 79 | 80 | sprintf(gameFPS, "FrameSkip: %d", frameSkip); 81 | 82 | draw_string_c(50, "Configuration Menu"); 83 | draw_string_c(73, gameFPS); 84 | 85 | if (VSYNC) 86 | draw_string_c(88, "VSYNC: ENABLE"); 87 | else 88 | draw_string_c(88, "VSYNC: DISABLE"); 89 | 90 | draw_string_c(118, "Exit and Start Game"); 91 | 92 | } 93 | 94 | void FS_StringConc(char* dst, char* src1, char* src2) { 95 | int i = 0; 96 | int Size2 = strlen(src1); 97 | int Size3 = strlen(src2); 98 | 99 | 100 | for (i = 0; i < Size2; i++) { 101 | dst[i] = src1[i]; 102 | } 103 | 104 | for (i = 0; i < Size3; i++) { 105 | dst[i + Size2] = src2[i]; 106 | } 107 | 108 | } 109 | 110 | // TODO: 111 | // Here will need a complete re-work, because the files now are loaded 112 | // in different way, so we need copy to the "filename stream" the correct 113 | // size of filename, another important thing is reset the cpu 114 | // that include clear all registers 115 | 116 | void NES_LoadSelectedGame() { 117 | u32 bytesRead = 0; 118 | u32 SRAM_Size = 0; 119 | u32 ROMDIR_Size = (strlen("/3DNES/ROMS/") + strlen(fileSystem.fileList[fileSystem.currFile]) + 1); 120 | Handle fileHandle; 121 | 122 | 123 | CPU_Running = false; 124 | 125 | /* Alloc ROM Directory */ 126 | char ROM_DIR[ROMDIR_Size]; 127 | 128 | /* Clear ROM_Dir */ 129 | memset(ROM_DIR, 0x0, ROMDIR_Size); 130 | 131 | 132 | //FS_StringConc(ROM_DIR, "/3DNES/ROMS/", fileSystem.fileList[fileSystem.currFile]); 133 | 134 | /* TODO: FIX IT 135 | /*if (SRAM_Name != NULL) { 136 | linearFree(SRAM_Name); 137 | SRAM_Size = (strlen(fileSystem.fileList[fileSystem.currFile]) - 4); 138 | SRAM_Name = linearAlloc(SRAM_Size); 139 | strncpy((char*)SRAM_Name, fileSystem.fileList[fileSystem.currFile], SRAM_Size); 140 | } 141 | */ 142 | 143 | FSUSER_OpenFileDirectly(NULL, &fileHandle, sdmcArchive, FS_makePath(PATH_CHAR, ROM_DIR), FS_OPEN_READ, FS_ATTRIBUTE_NONE); 144 | FSFILE_GetSize(fileHandle, &ROM_Size); 145 | FSFILE_Read(fileHandle, &bytesRead, 0x0, (u32*)ROM_Cache, (u32)ROM_Size); 146 | FSFILE_Close(fileHandle); 147 | 148 | /* Start Emulation */ 149 | inGame = true; 150 | } 151 | 152 | void NES_ConfigurationMenu() { 153 | u32 keys = ((u32*)0x10000000)[7]; 154 | 155 | /* Configuration Menu */ 156 | if(keys & BUTTON_LEFT) { 157 | if(!fileSystem.UKEY_LEFT) { 158 | switch(fileSystem.cConfig) { 159 | case 0: 160 | frameSkip--; 161 | break; 162 | 163 | case 1: 164 | VSYNC = false; 165 | break; 166 | 167 | case 2: 168 | 169 | break; 170 | 171 | default: 172 | 173 | break; 174 | } 175 | 176 | fileSystem.UKEY_LEFT = 1; 177 | } 178 | } else { 179 | fileSystem.UKEY_LEFT = 0; 180 | } 181 | 182 | if(keys & BUTTON_RIGHT) { 183 | if(!fileSystem.UKEY_RIGHT) { 184 | switch(fileSystem.cConfig) { 185 | case 0: 186 | frameSkip++; 187 | break; 188 | 189 | case 1: 190 | VSYNC = true; 191 | break; 192 | 193 | case 2: 194 | 195 | break; 196 | 197 | default: 198 | 199 | break; 200 | } 201 | 202 | 203 | fileSystem.UKEY_RIGHT = 1; 204 | } 205 | } else { 206 | fileSystem.UKEY_RIGHT = 0; 207 | } 208 | 209 | if(keys & BUTTON_UP){ 210 | if(!fileSystem.UKEY_UP){ 211 | if(fileSystem.cConfig > 0) 212 | fileSystem.cConfig--; 213 | 214 | fileSystem.UKEY_UP = 1; 215 | } 216 | } else { 217 | fileSystem.UKEY_UP = 0; 218 | } 219 | 220 | if(keys & BUTTON_DOWN){ 221 | if(!fileSystem.UKEY_DOWN) { 222 | 223 | if(fileSystem.cConfig < 2) 224 | fileSystem.cConfig++; 225 | 226 | fileSystem.UKEY_DOWN = 1; 227 | } 228 | } else { 229 | fileSystem.UKEY_DOWN = 0; 230 | } 231 | 232 | 233 | if(keys & BUTTON_B) { 234 | if(!fileSystem.UKEY_B) { 235 | if(fileSystem.cConfig == 2) 236 | fileSystem.inMenu = 0; 237 | 238 | fileSystem.UKEY_B = 1; 239 | } else { 240 | fileSystem.UKEY_B = 0; 241 | } 242 | } 243 | 244 | } 245 | 246 | void NES_CurrentFileUpdate() { 247 | u32 keys = ((u32*)0x10000000)[7]; 248 | 249 | if(fileSystem.inMenu == 0) { 250 | if(keys & BUTTON_UP){ 251 | if(!fileSystem.UKEY_UP){ 252 | if(fileSystem.sFile > 0) 253 | fileSystem.sFile--; 254 | else { 255 | if(fileSystem.cFile > 0) 256 | fileSystem.cFile--; 257 | } 258 | 259 | if(fileSystem.currFile > 0) 260 | fileSystem.currFile--; 261 | 262 | fileSystem.UKEY_UP = 1; 263 | } 264 | } else { 265 | fileSystem.UKEY_UP = 0; 266 | } 267 | 268 | if(keys & BUTTON_DOWN){ 269 | if(!fileSystem.UKEY_DOWN) { 270 | if(fileSystem.cFile < fileSystem.totalFiles) 271 | fileSystem.cFile++; 272 | else 273 | fileSystem.sFile++; 274 | 275 | fileSystem.currFile++; 276 | 277 | fileSystem.UKEY_DOWN = 1; 278 | } 279 | } else { 280 | fileSystem.UKEY_DOWN = 0; 281 | } 282 | 283 | 284 | if(keys & BUTTON_LEFT) { 285 | if(!fileSystem.UKEY_LEFT) { 286 | fileSystem.inMenu = 1; 287 | 288 | fileSystem.UKEY_LEFT = 1; 289 | } 290 | } else { 291 | fileSystem.UKEY_LEFT = 0; 292 | } 293 | 294 | 295 | } 296 | 297 | 298 | if(keys & BUTTON_B) { 299 | if(!fileSystem.UKEY_B) { 300 | NES_LoadSelectedGame(); 301 | 302 | fileSystem.UKEY_B = 1; 303 | } else { 304 | fileSystem.UKEY_B = 0; 305 | } 306 | } 307 | 308 | } 309 | 310 | 311 | void NES_MainMenu() { 312 | if (fileSystem.inMenu == 0) { 313 | NES_drawROMLIST(); 314 | NES_CurrentFileUpdate(); 315 | } 316 | else { 317 | NES_drawConfigurationMenu(); 318 | NES_ConfigurationMenu(); 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /cci/gw_workaround.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "3DNES" 3 | CompanyCode : "00" 4 | ProductCode : "CTR-N-3DNX" 5 | ContentType : Application 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | Rom: 9 | # Specifies the root path of the file system to include in the ROM. 10 | #HostRoot : "romfs" 11 | 12 | 13 | TitleInfo: 14 | UniqueId : 0xf0021 15 | Category : Application 16 | 17 | CardInfo: 18 | MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB 19 | MediaType : Card1 # Card1 / Card2 20 | CardDevice : NorFlash # NorFlash(Pick this if you use savedata) / None 21 | 22 | 23 | Option: 24 | FreeProductCode : true # Removes limitations on ProductCode 25 | MediaFootPadding : false # If true CCI files are created with padding 26 | EnableCrypt : true # Enables encryption for NCCH and CIA 27 | EnableCompress : true # Compresses exefs code 28 | 29 | ExeFs: # these are the program segments from the ELF, check your elf for the appropriate segment names 30 | ReadOnly: 31 | - .rodata 32 | - RO 33 | ReadWrite: 34 | - .data 35 | - RO 36 | Text: 37 | - .init 38 | - .text 39 | - STUP_ENTRY 40 | 41 | PlainRegion: # only used with SDK ELFs 42 | - .module_id 43 | 44 | AccessControlInfo: 45 | #UseExtSaveData : true 46 | #ExtSaveDataId: 0xff3ff 47 | #UseExtendedSaveDataAccessControl: true 48 | #AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 49 | 50 | SystemControlInfo: 51 | SaveDataSize: 128KB 52 | RemasterVersion: 0 53 | StackSize: 0x40000 54 | 55 | # DO NOT EDIT BELOW HERE OR PROGRAMS WILL NOT LAUNCH (most likely) 56 | 57 | AccessControlInfo: 58 | FileSystemAccess: 59 | - Debug 60 | - DirectSdmc 61 | - DirectSdmcWrite 62 | 63 | IdealProcessor : 0 64 | AffinityMask : 1 65 | 66 | Priority : 16 67 | 68 | MaxCpu : 0x9E # Default 69 | 70 | CoreVersion : 2 71 | DescVersion : 2 72 | 73 | ReleaseKernelMajor : "02" 74 | ReleaseKernelMinor : "33" 75 | MemoryType : Application 76 | HandleTableSize: 512 77 | IORegisterMapping: 78 | - 1ff50000-1ff57fff 79 | - 1ff70000-1ff77fff 80 | MemoryMapping: 81 | - 1f000000-1f5fffff:r 82 | SystemCallAccess: 83 | ArbitrateAddress: 34 84 | Break: 60 85 | CancelTimer: 28 86 | ClearEvent: 25 87 | ClearTimer: 29 88 | CloseHandle: 35 89 | ConnectToPort: 45 90 | ControlMemory: 1 91 | CreateAddressArbiter: 33 92 | CreateEvent: 23 93 | CreateMemoryBlock: 30 94 | CreateMutex: 19 95 | CreateSemaphore: 21 96 | CreateThread: 8 97 | CreateTimer: 26 98 | DuplicateHandle: 39 99 | ExitProcess: 3 100 | ExitThread: 9 101 | GetCurrentProcessorNumber: 17 102 | GetHandleInfo: 41 103 | GetProcessId: 53 104 | GetProcessIdOfThread: 54 105 | GetProcessIdealProcessor: 6 106 | GetProcessInfo: 43 107 | GetResourceLimit: 56 108 | GetResourceLimitCurrentValues: 58 109 | GetResourceLimitLimitValues: 57 110 | GetSystemInfo: 42 111 | GetSystemTick: 40 112 | GetThreadContext: 59 113 | GetThreadId: 55 114 | GetThreadIdealProcessor: 15 115 | GetThreadInfo: 44 116 | GetThreadPriority: 11 117 | MapMemoryBlock: 31 118 | OutputDebugString: 61 119 | QueryMemory: 2 120 | ReleaseMutex: 20 121 | ReleaseSemaphore: 22 122 | SendSyncRequest1: 46 123 | SendSyncRequest2: 47 124 | SendSyncRequest3: 48 125 | SendSyncRequest4: 49 126 | SendSyncRequest: 50 127 | SetThreadPriority: 12 128 | SetTimer: 27 129 | SignalEvent: 24 130 | SleepThread: 10 131 | UnmapMemoryBlock: 32 132 | WaitSynchronization1: 36 133 | WaitSynchronizationN: 37 134 | InterruptNumbers: 135 | ServiceAccessControl: 136 | - APT:U 137 | - $hioFIO 138 | - $hostio0 139 | - $hostio1 140 | - ac:u 141 | - boss:U 142 | - cam:u 143 | - cecd:u 144 | - cfg:u 145 | - dlp:FKCL 146 | - dlp:SRVR 147 | - dsp::DSP 148 | - frd:u 149 | - fs:USER 150 | - gsp::Gpu 151 | - hid:USER 152 | - http:C 153 | - mic:u 154 | - ndm:u 155 | - news:u 156 | - nwm::UDS 157 | - ptm:u 158 | - pxi:dev 159 | - soc:U 160 | - ssl:C 161 | - y2r:u 162 | - ldr:ro 163 | - ir:USER 164 | 165 | 166 | SystemControlInfo: 167 | Dependency: 168 | ac: 0x0004013000002402L 169 | am: 0x0004013000001502L 170 | boss: 0x0004013000003402L 171 | camera: 0x0004013000001602L 172 | cecd: 0x0004013000002602L 173 | cfg: 0x0004013000001702L 174 | codec: 0x0004013000001802L 175 | csnd: 0x0004013000002702L 176 | dlp: 0x0004013000002802L 177 | dsp: 0x0004013000001a02L 178 | friends: 0x0004013000003202L 179 | gpio: 0x0004013000001b02L 180 | gsp: 0x0004013000001c02L 181 | hid: 0x0004013000001d02L 182 | http: 0x0004013000002902L 183 | i2c: 0x0004013000001e02L 184 | ir: 0x0004013000003302L 185 | mcu: 0x0004013000001f02L 186 | mic: 0x0004013000002002L 187 | ndm: 0x0004013000002b02L 188 | news: 0x0004013000003502L 189 | nim: 0x0004013000002c02L 190 | nwm: 0x0004013000002d02L 191 | pdn: 0x0004013000002102L 192 | ps: 0x0004013000003102L 193 | ptm: 0x0004013000002202L 194 | ro: 0x0004013000003702L 195 | socket: 0x0004013000002e02L 196 | spi: 0x0004013000002302L 197 | ssl: 0x0004013000002f02L 198 | CommonHeaderKey: 199 | D: | 200 | jL2yO86eUQnYbXIrzgFVMm7FVze0LglZ2f5g+c42hWoEdnb5BOotaMQPBfqt 201 | aUyAEmzQPaoi/4l4V+hTJRXQfthVRqIEx27B84l8LA6Tl5Fy9PaQaQ+4yRfP 202 | g6ylH2l0EikrIVjy2uMlFgl0QJCrG+QGKHftxhaGCifdAwFNmiZuyJ/TmktZ 203 | 0RCb66lYcr2h/p2G7SnpKUliS9h9KnpmG+UEgVYQUK+4SCfByUa9PxYGpT0E 204 | nw1UcRz0gsBmdOqcgzwnAd9vVqgb42hVn6uQZyAl+j1RKiMWywZarazIR/k5 205 | Lmr4+groimSEa+3ajyoIho9WaWTDmFU3mkhA2tUDIQ== 206 | Exponent: | 207 | AQAB 208 | Modulus: | 209 | zwCcsyCgMkdlieCgQMVXA6X2jmb1ICjup0Q+jk/AydPkOgsx7I/MjUymFEkU 210 | vgXBtCKtzh3NKXtFFuW51tJ60GPOabLKuG0Qm5li+UXALrWhzWuvd5vv2FZI 211 | dTQCbrq/MFS/M02xNtwqzWiBjE/LwqIdbrDAAvX4HGy0ydaQJ1DKYeQeph5D 212 | lAGBw2nQ4izXhhuLaU3w8VQkIJHdhxIKI5gJY/20AGkG0vHD553Mh5kBINrWp 213 | CRYmmJS8DCYbAiQtKbkeUfzHViGTZuj6PwaY8Mv39PGO47a++pt45IUyCEs4/ 214 | LjMS72cyfo8tU4twRGp76SFGYejYj3wGC1f/POQw== 215 | Signature: | 216 | BOPR0jL0BOV5Zx502BuPbOvi/hvOq5ID8Dz1MQfOjkey6FKP/6cb4f9YXpm6c 217 | ZCHAZLo0GduKdMepiKPUq1rsbbAxkRdQdjOOusEWoxNA58x3E4373tCAhlqM2 218 | DvuQERrIIQ/XnYLV9C3uw4efZwhFqog1jvVyoEHpuvs8xnYtGbsKQ8FrgLwXv 219 | pOZYy9cSgq+jqLy2D9IxiowPcbq2cRlbW9d2xlUfpq0AohyuXQhpxn7d9RUor 220 | 9veoARRAdxRJK12EpcSoEM1LhTRYdJnSRCY3x3p6YIV3c+l1sWvaQwKt0sZ/U 221 | 8TTDx2gb9g7r/+U9icneu/zlqUpSkexCS009Q== 222 | Descriptor: | 223 | AP///wAABAACAAAAAAAFGJ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 224 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiIAAAAAAAABBUFQ6VQAAACRo 225 | aW9GSU8AJGhvc3RpbzAkaG9zdGlvMWFjOnUAAAAAYm9zczpVAABjYW06dQAA 226 | AGNlY2Q6dQAAY2ZnOnUAAABkbHA6RktDTGRscDpTUlZSZHNwOjpEU1BmcmQ6 227 | dQAAAGZzOlVTRVIAZ3NwOjpHcHVoaWQ6VVNFUmh0dHA6QwAAbWljOnUAAABu 228 | ZG06dQAAAG5ld3M6dQAAbndtOjpVRFNwdG06dQAAAHB4aTpkZXYAc29jOlUA 229 | AABzc2w6QwAAAHkycjp1AAAAbGRyOnJvAABpcjpVU0VSAAAAAAAAAAAAAAAA 230 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 231 | AAAAAAAAAABOn/rw/7//8ec/APIA8JH/APaR/1D/gf9Y/4H/cP+B/3j/gf8B 232 | AQD/AAIA/iECAPz///////////////////////////////////////////// 233 | ////////////////////////////////////////AAAAAAAAAAAAAAAAAAAA 234 | AAADAAAAAAAAAAAAAAAAAAI= -------------------------------------------------------------------------------- /include/mmc5.h: -------------------------------------------------------------------------------- 1 | /* Mirroring especial */ 2 | extern int mirror[4]; //O MMC5 tem um Mirroring especial 3 | extern unsigned char nt[4][0x400]; //O MMC5 pode usar ExRam como NameTable 4 | int sel_nt; 5 | 6 | /* RAM Extra */ 7 | unsigned char ex_ram[1024]; //RAM Extra dentro do MAPPER de 1KB 8 | unsigned char mmc5_wram[65536]; //64kb de RAM extra em alguns cartuchos 9 | 10 | unsigned char mmc5_wram_page; 11 | unsigned char mmc5_wram_chip; 12 | 13 | /* PRG/CHR */ 14 | unsigned char mmc5_prgsize; 15 | unsigned char mmc5_chrsize; 16 | unsigned char mmc5_gfx_mode; 17 | 18 | unsigned char mmc5_chr_page_sprite[8]; 19 | unsigned char mmc5_chr_page_background[4]; 20 | 21 | /* IRQ */ 22 | unsigned char mmc5_irq_clear; 23 | unsigned int mmc5_irq_scanline; 24 | unsigned int mmc5_irq_line; 25 | unsigned char mmc5_irq_status; 26 | unsigned char mmc5_irq_enable; 27 | 28 | void copynt(int nt_num) { 29 | int i; 30 | for (i = 0; i < 1024; i++) { 31 | nt[nt_num][i] = ex_ram[i]; 32 | } 33 | } 34 | 35 | void mmc5_switch_prg(int address, int bank, int prg_size) { 36 | memcpy(memory + address, ROM_Cache + 16 + (maskaddr(bank) * 0x2000), prg_size); 37 | } 38 | 39 | void mmc5_switch_chr(int bank, int page, int chr_size) { 40 | int prg_size; 41 | 42 | int chr_start; 43 | 44 | unsigned int address; 45 | 46 | address = page * 0x400; 47 | 48 | prg_size = 16384; 49 | chr_start = prg_size * PRG; 50 | 51 | memcpy(PPU_Memory + address, ROM_Cache + 16 + chr_start + (bank * 0x400), chr_size); 52 | } 53 | 54 | void mmc5_access(unsigned int address,unsigned char data) { 55 | switch (address) { 56 | case 0x5100: mmc5_prgsize = data & 3; break; 57 | case 0x5101: mmc5_chrsize = data & 3; break; 58 | case 0x5104: mmc5_gfx_mode = data & 3; break; //OBS: Apenas um modo suportado 59 | case 0x5105: //Mirroring do MMC5 60 | mirror[0] = data & 1; 61 | mirror[1] = (data & 4) >> 2; 62 | mirror[2] = (data & 0x10) >> 4; 63 | mirror[3] = (data & 0x40) >> 6; 64 | 65 | if (mmc5_gfx_mode == 0) { //Modo de usar ExRam como NameTable 66 | if (data & 2) {sel_nt = 0;} 67 | if (data & 8) {sel_nt = 1;} 68 | if (data & 0x20) {sel_nt = 2;} 69 | if (data & 0x80) {sel_nt = 3;} 70 | } 71 | break; 72 | case 0x5113: 73 | mmc5_wram_page = data & 3; 74 | mmc5_wram_chip = (data & 4) >> 2; 75 | break; 76 | case 0x5114: 77 | case 0x5115: 78 | case 0x5116: 79 | case 0x5117: 80 | if (data & 0x80) { 81 | switch(address & 7) { 82 | case 4: if (mmc5_prgsize == 3) mmc5_switch_prg(0x8000, data & 0x7F, 8192); break; 83 | case 5: 84 | if ((mmc5_prgsize == 1) || (mmc5_prgsize == 2)) { //16k 8 85 | mmc5_switch_prg(0x8000, data & 0x7F, 16384); 86 | } else { //8k A 87 | mmc5_switch_prg(0xA000, data & 0x7F, 8192); 88 | } 89 | break; 90 | case 6: if ((mmc5_prgsize == 2) || (mmc5_prgsize == 3)) mmc5_switch_prg(0xC000, data & 0x7F, 8192); break; 91 | case 7: 92 | switch (mmc5_prgsize) { 93 | case 0: mmc5_switch_prg(0x8000, data & 0x7F, 32768); break; 94 | case 1: mmc5_switch_prg(0xC000, data & 0x7F, 16384); break; 95 | case 2: mmc5_switch_prg(0xE000, data & 0x7F, 8192); break; 96 | } 97 | break; 98 | } 99 | } else { //Usa SRAM como... PRG-RAM? 100 | switch(address & 7) { 101 | case 4: break; 102 | case 5: 103 | if ((mmc5_prgsize == 1) || (mmc5_prgsize == 2)) { 104 | //??? 105 | } else { //METAL SLADER GLORY ESCREVE AQUI !!!!!!!!!!!! 106 | //??? 107 | //printf("mmc5 wram\n"); 108 | memcpy(mmc5_wram + (mmc5_wram_page * 8192) + (mmc5_wram_chip * 8192), ROM_Cache + 16 + (maskaddr(data & 0x7F) * 0x2000), 8192); 109 | //mmc5_switch_prg(0x8000, data & 0x7F, 16384); break; 110 | } 111 | break; 112 | case 6: break; 113 | } 114 | } 115 | break; 116 | case 0x5120: //CHR Sprite 117 | case 0x5121: 118 | case 0x5122: 119 | case 0x5123: 120 | case 0x5124: 121 | case 0x5125: 122 | case 0x5126: 123 | case 0x5127: 124 | mmc5_chr_page_sprite[address & 7] = data; 125 | 126 | switch(mmc5_chrsize) { 127 | case 0: mmc5_switch_chr(mmc5_chr_page_sprite[7], 0, 8192); break; 128 | case 1: 129 | mmc5_switch_chr(mmc5_chr_page_sprite[3], 0, 4096); 130 | mmc5_switch_chr(mmc5_chr_page_sprite[7], 4, 4096); 131 | break; 132 | case 2: 133 | mmc5_switch_chr(mmc5_chr_page_sprite[1], 0, 2048); 134 | mmc5_switch_chr(mmc5_chr_page_sprite[3], 2, 2048); 135 | mmc5_switch_chr(mmc5_chr_page_sprite[5], 4, 2048); 136 | mmc5_switch_chr(mmc5_chr_page_sprite[7], 6, 2048); 137 | break; 138 | case 3: 139 | mmc5_switch_chr(mmc5_chr_page_sprite[0], 0, 1024); 140 | mmc5_switch_chr(mmc5_chr_page_sprite[1], 1, 1024); 141 | mmc5_switch_chr(mmc5_chr_page_sprite[2], 2, 1024); 142 | mmc5_switch_chr(mmc5_chr_page_sprite[3], 3, 1024); 143 | mmc5_switch_chr(mmc5_chr_page_sprite[4], 4, 1024); 144 | mmc5_switch_chr(mmc5_chr_page_sprite[5], 5, 1024); 145 | mmc5_switch_chr(mmc5_chr_page_sprite[6], 6, 1024); 146 | mmc5_switch_chr(mmc5_chr_page_sprite[7], 7, 1024); 147 | break; 148 | } 149 | break; 150 | case 0x5128: //CHR Background 151 | case 0x5129: 152 | case 0x512A: 153 | case 0x512B: 154 | mmc5_chr_page_background[address & 3] = data; 155 | 156 | switch(mmc5_chrsize) { 157 | case 1: mmc5_switch_chr(mmc5_chr_page_background[3], 0, 8192); break; 158 | case 3: 159 | mmc5_switch_chr(mmc5_chr_page_background[0], 4, 1024); 160 | mmc5_switch_chr(mmc5_chr_page_background[1], 5, 1024); 161 | mmc5_switch_chr(mmc5_chr_page_background[2], 6, 1024); 162 | mmc5_switch_chr(mmc5_chr_page_background[3], 7, 1024); 163 | break; 164 | } 165 | break; 166 | case 0x5203: mmc5_irq_line = data; break; 167 | case 0x5204: mmc5_irq_enable = data; break; 168 | } 169 | 170 | if (address >= 0x5C00 && address <= 0x5FFF) { 171 | ex_ram[address - 0x5C00] = data; 172 | if (mmc5_gfx_mode == 0) { //Modo de usar ExRam como NameTable 173 | copynt(sel_nt); 174 | } 175 | } 176 | } 177 | 178 | unsigned char mmc5_read(unsigned int address) { 179 | unsigned char tmp = 0; 180 | switch (address) { 181 | case 0x5204: 182 | tmp = mmc5_irq_status; 183 | mmc5_irq_status = 0; 184 | mmc5_irq_status &= 0x80; 185 | return tmp; 186 | break; 187 | } 188 | 189 | if ((address >= 0x5C00 && address <= 0x5FFF) && (mmc5_gfx_mode >= 2)) {return ex_ram[address - 0x5C00];} 190 | 191 | return(0); 192 | } 193 | 194 | void mmc5_hblank(int scanline) { 195 | if (scanline < 240) { 196 | mmc5_irq_scanline++; 197 | mmc5_irq_status |= 0x40; 198 | mmc5_irq_clear = 0; 199 | } 200 | 201 | if (mmc5_irq_scanline == mmc5_irq_line) { 202 | mmc5_irq_status |= 0x80; 203 | } 204 | if (++mmc5_irq_clear > 2) { 205 | mmc5_irq_scanline = 0; 206 | mmc5_irq_status &= ~0x80; 207 | mmc5_irq_status &= ~0x40; 208 | } 209 | 210 | if ((mmc5_irq_enable & 0x80) && (mmc5_irq_status & 0x80) && (mmc5_irq_status & 0x40)) IRQ(); 211 | } 212 | -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include <3ds.h> 3 | 4 | // NES SYSTEM 5 | #include "nesGlobal.h" 6 | #include "nesSystem.h" 7 | #include "nesLoadROM.h" 8 | #include "nes6502.h" 9 | #include "nesPPU.h" 10 | // NES MAPPERS 11 | #include "utils.h" 12 | #include "mmc1.h" // 1 13 | #include "unrom.h" // 2 14 | #include "cnrom.h" // 3 15 | #include "mmc3.h" // 4 16 | #include "mmc5.h" // 5 17 | #include "aorom.h" // 7 18 | #include "mapper79.h" // 79 19 | // FILESYSTEM, BACKGROUND, ETC 20 | #include "FileSystem.h" 21 | #include "background.h" 22 | 23 | u8 *PPU_Memory; 24 | u8 *SPRITE_Memory; 25 | u8 frameSkip; 26 | u8 skipFrame; 27 | 28 | u16 lastInstruction = 0; 29 | u8 lastOP = 0; 30 | u8 lastA = 0; 31 | 32 | u32 PAD1_Data; 33 | 34 | bool CPU_Running; 35 | bool PAUSE_Emulation; 36 | bool ENABLE_Background; 37 | bool ENABLE_Sprite; 38 | bool inGame; 39 | bool VSYNC; 40 | 41 | int PAD1_ReadCount = 0; 42 | 43 | extern u8 memory[65536]; 44 | 45 | /* It will init all services necessary to Homebrew work ! */ 46 | void INIT_3DS() { 47 | srvInit(); 48 | fsInit(); 49 | aptInit(); 50 | gfxInit(); 51 | hidInit(NULL); 52 | gfxSet3D(false); 53 | 54 | PPU_Memory = linearAlloc(16384); 55 | SPRITE_Memory = linearAlloc(256); 56 | frameSkip = 2; 57 | skipFrame = 0; 58 | 59 | 60 | 61 | PAD1_Data = 0; 62 | ROM_Size = 0; 63 | 64 | CPU_Running = false; 65 | PAUSE_Emulation = false; 66 | ENABLE_Background = true; 67 | ENABLE_Sprite = true; 68 | inGame = false; 69 | VSYNC = true; 70 | 71 | 72 | init_ppu(); 73 | } 74 | 75 | /* It will init and load the ROM List */ 76 | void INIT_FileSystem() { 77 | fileSystem.inMenu = false; 78 | NES_LOADROMLIST(); 79 | } 80 | 81 | 82 | /* Finish all services which was used ! */ 83 | void EXIT_3DS() { 84 | 85 | /* Free All Linear Allocation */ 86 | if (SRAM_Name != NULL) 87 | linearFree (SRAM_Name); 88 | 89 | if (fileSystem.fileList != NULL) 90 | linearFree (fileSystem.fileList); 91 | 92 | linearFree (memory); 93 | linearFree (PPU_Memory); 94 | linearFree (SPRITE_Memory); 95 | 96 | fsExit(); 97 | hidExit(); 98 | gfxExit(); 99 | aptExit(); 100 | srvExit(); 101 | svcExitProcess(); 102 | } 103 | 104 | void INIT_EMULATION() { 105 | 106 | if (NES_LoadROM() == -1) { 107 | 108 | inGame = false; 109 | } 110 | 111 | if (MAPPER == 4) 112 | mmc3_reset(); 113 | 114 | if (SRAM == 1) 115 | SRAM_LOADSTATE(); 116 | 117 | CPU_Reset(); 118 | RESET_INPUT(); 119 | do_mirror(MIRRORING); 120 | 121 | CPU_Running = true; 122 | } 123 | 124 | 125 | /* Check if a button is pressed */ 126 | void NES_CheckJoypad() { 127 | u32 keys = ((u32*)0x10000000)[7]; 128 | 129 | if (!inGame) 130 | inGame = true; 131 | 132 | if(inGame == true){ 133 | 134 | if(keys & BUTTON_L1) { 135 | inGame = false; 136 | } 137 | 138 | if(keys & BUTTON_A) 139 | SET_INPUT(7); 140 | else 141 | CLEAR_INPUT(7); 142 | 143 | if(keys & BUTTON_B) 144 | SET_INPUT(8); 145 | else 146 | CLEAR_INPUT(8); 147 | 148 | if(keys & BUTTON_START) 149 | SET_INPUT(5); 150 | else 151 | CLEAR_INPUT(5); 152 | 153 | if(keys & BUTTON_RIGHT) 154 | SET_INPUT(4); 155 | else 156 | CLEAR_INPUT(4); 157 | 158 | if(keys & BUTTON_LEFT) 159 | SET_INPUT(3); 160 | else 161 | CLEAR_INPUT(3); 162 | 163 | if(keys & BUTTON_UP) 164 | SET_INPUT(2); 165 | else 166 | CLEAR_INPUT(2); 167 | 168 | if(keys & BUTTON_DOWN) 169 | SET_INPUT(1); 170 | else 171 | CLEAR_INPUT(1); 172 | 173 | if(keys & BUTTON_SELECT) 174 | SET_INPUT(6); 175 | else 176 | CLEAR_INPUT(6); 177 | } 178 | } 179 | 180 | void NES_MAINLOOP() { 181 | APP_STATUS status; 182 | 183 | int scanline = 0; 184 | 185 | while ((status = aptGetStatus()) != APP_EXITING ) { 186 | 187 | switch (status) { 188 | case APP_RUNNING: 189 | 190 | if (!inGame) { 191 | drawMenu(); 192 | NES_MainMenu(); 193 | drawBuffers(); 194 | gspWaitForVBlank(); 195 | } else { 196 | ppu_status = 0; 197 | if (!CPU_Running) 198 | INIT_EMULATION(); 199 | 200 | /* Check FrameSkip */ 201 | 202 | if (skipFrame > frameSkip) 203 | skipFrame = 0; 204 | 205 | if (skipFrame == 0) 206 | NES_ColorBackground(); 207 | 208 | for (scanline = 0; scanline < 262; scanline++) { 209 | if (MAPPER == 5) mmc5_hblank(scanline); 210 | 211 | CPU_Execute(); 212 | 213 | if (scanline < 240) { 214 | if (MAPPER == 4) mmc3_hblank(scanline); 215 | 216 | render_scanline(scanline); 217 | 218 | } else { 219 | if (scanline == 241) { 220 | if (exec_nmi_on_vblank) { NMI(); } 221 | 222 | ppu_status = 0x80; 223 | } 224 | } 225 | } 226 | 227 | NES_CheckJoypad(); 228 | 229 | if (skipFrame == 0) 230 | drawBuffers(); 231 | 232 | skipFrame++; 233 | 234 | if (VSYNC) 235 | gspWaitForVBlank(); 236 | 237 | } 238 | break; 239 | 240 | case APP_SUSPENDING: 241 | aptReturnToMenu(); 242 | break; 243 | 244 | case APP_SLEEPMODE: 245 | aptWaitStatusEvent(); 246 | break; 247 | 248 | default: 249 | 250 | break; 251 | } 252 | 253 | } 254 | 255 | } 256 | 257 | // TODO 258 | // Write memoryRead and memoryWrite in Assembly 259 | // i belive which it will improve the speed 260 | u8 memoryRead(u32 addr) { 261 | /* this is ram or rom so we can return the addr */ 262 | if (addr < 0x2000) 263 | return memory[addr & 0x7FF]; 264 | 265 | if (addr > 0x7FFF) 266 | return memory[addr]; 267 | 268 | 269 | /* The addr between 0x200 and 0x500 are for input and ouput */ 270 | 271 | if (addr == 0x2002) { 272 | ppu_status_tmp = ppu_status; 273 | 274 | /* set ppu_status (D7) to 0 (vblank on) */ 275 | ppu_status &= 0x7F; 276 | 277 | /* set ppu_status (D6) to 0 (sprite zero) */ 278 | ppu_status &= 0x1F; 279 | 280 | /* Reset VRAM addr Register #1 */ 281 | ppu_bgscr_f = 0x0; 282 | 283 | /* reset VRAM addr Register #2 */ 284 | ppu_addr_h = 0x0; 285 | 286 | /* return bits 7-4 of unmodifyed ppu_status with bits 3-0 of the ppu_addr_tmp */ 287 | return (ppu_status_tmp); 288 | } 289 | 290 | if(addr == 0x2007) { 291 | int tmp = ppu_addr_tmp; 292 | ppu_addr_tmp = ppu_addr; 293 | 294 | if(increment_32 == 0) { 295 | ppu_addr++; 296 | } else { 297 | ppu_addr += 0x20; 298 | } 299 | 300 | return PPU_Memory[tmp]; 301 | } 302 | 303 | /* pAPU data (sound) */ 304 | if(addr == 0x4015) { 305 | return memory[addr]; 306 | } 307 | 308 | /* joypad1 data */ 309 | if(addr == 0x4016) { 310 | switch(PAD1_ReadCount) { 311 | case 0: 312 | memory[addr] = PAD1_A; 313 | PAD1_ReadCount++; 314 | break; 315 | 316 | case 1: 317 | memory[addr] = PAD1_B; 318 | PAD1_ReadCount++; 319 | break; 320 | 321 | case 2: 322 | memory[addr] = PAD1_SELECT; 323 | PAD1_ReadCount++; 324 | break; 325 | 326 | case 3: 327 | memory[addr] = PAD1_START; 328 | PAD1_ReadCount++; 329 | break; 330 | 331 | case 4: 332 | memory[addr] = PAD1_UP; 333 | PAD1_ReadCount++; 334 | break; 335 | 336 | case 5: 337 | memory[addr] = PAD1_DOWN; 338 | PAD1_ReadCount++; 339 | break; 340 | 341 | case 6: 342 | memory[addr] = PAD1_LEFT; 343 | PAD1_ReadCount++; 344 | break; 345 | 346 | case 7: 347 | memory[addr] = PAD1_RIGHT; 348 | PAD1_ReadCount = 0; 349 | break; 350 | } 351 | 352 | return memory[addr]; 353 | } 354 | 355 | if(addr == 0x4017) { 356 | return memory[addr]; 357 | } 358 | 359 | if (MAPPER == 5) { 360 | if((addr == 0x5204) || (addr >= 0x5C00 && addr <= 0x5FFF)) { 361 | return mmc5_read(addr); 362 | } 363 | } 364 | 365 | if((addr > 0x5FFF) && (addr < 0x8000) && (MAPPER == 5)) { //SRAM 366 | return mmc5_wram[(addr - 0x6000) + (mmc5_wram_page * 8192) + (mmc5_wram_chip * 8192)]; 367 | } 368 | 369 | 370 | return memory[addr]; 371 | } 372 | 373 | /* Read 2 bytes */ 374 | int memoryRead16(u32 addr) { 375 | return (memoryRead(addr) + (memoryRead(addr + 1) * 0x100)); 376 | } 377 | 378 | /* write a byte */ 379 | void writeMemory(u32 addr, u8 data) { 380 | /* PPU Video Memory area */ 381 | if(addr > 0x1fff && addr < 0x4000) { 382 | write_PPU_Memory(addr,data); 383 | return; 384 | } 385 | 386 | /* Sprite DMA Register */ 387 | if(addr == 0x4014) { 388 | write_PPU_Memory(addr,data); 389 | // TODO: Fix Sprite DMA Tick 390 | //nesTick += 512; 391 | return; 392 | } 393 | 394 | /* Joypad 1 */ 395 | if(addr == 0x4016) { 396 | memory[addr] = 0x40; 397 | 398 | return; 399 | } 400 | 401 | /* Joypad 2 */ 402 | if(addr == 0x4017) { 403 | memory[addr] = 0x48; 404 | return; 405 | } 406 | 407 | /* pAPU Sound Registers */ 408 | if(addr > 0x3fff && addr < 0x4016) { 409 | memory[addr] = data; 410 | return; 411 | } 412 | 413 | /* SRAM Registers */ 414 | if(addr > 0x5fff && addr < 0x8000) { 415 | if(MAPPER == 5) { //SRAM 416 | mmc5_wram[(addr - 0x6000) + (mmc5_wram_page * 8192) + (mmc5_wram_chip * 8192)] = data; 417 | return; 418 | } else { 419 | 420 | memory[addr] = data; 421 | return; 422 | } 423 | } 424 | 425 | /* RAM registers */ 426 | if(addr < 0x2000) {memory[addr & 0x7FF] = data; return;} 427 | 428 | switch (MAPPER) { 429 | case 1: 430 | mmc1_access(addr, data); 431 | return; 432 | break; 433 | 434 | case 2: 435 | unrom_access(addr, data); 436 | return; 437 | break; 438 | 439 | case 3: 440 | cnrom_access(addr, data); 441 | return; 442 | break; 443 | 444 | case 4: 445 | mmc3_access(addr, data); 446 | return; 447 | break; 448 | 449 | case 5: 450 | mmc5_access(addr, data); 451 | return; 452 | break; 453 | 454 | case 7: 455 | aorom_access(addr, data); 456 | return; 457 | break; 458 | 459 | case 79: 460 | mapper79_access(addr,data); 461 | return; 462 | break; 463 | 464 | default: 465 | 466 | break; 467 | } 468 | 469 | memory[addr] = data; 470 | } 471 | 472 | int main() { 473 | 474 | INIT_3DS(); 475 | INIT_FileSystem(); 476 | 477 | NES_MAINLOOP(); 478 | 479 | EXIT_3DS(); 480 | return 0; 481 | } 482 | -------------------------------------------------------------------------------- /source/nesPPU.c: -------------------------------------------------------------------------------- 1 | // NES SYSTEM 2 | #include "nesGlobal.h" 3 | #include "nesPPU.h" 4 | #include "nesSystem.h" 5 | #include "nesLoadROM.h" 6 | #include "nes6502.h" 7 | // FONT, PALETTE 8 | #include "gfx/imgdata.h" 9 | #include "palette.h" 10 | 11 | 12 | // TODO: 13 | // TOTAL REWRITE OF PPU 14 | // read documentation and optimize it 15 | // neswiki 16 | 17 | /* ppu control registers */ 18 | u32 ppu_control1 = 0x00; 19 | u32 ppu_control2 = 0x00; 20 | u32 ppu_latch = 0x00; 21 | 22 | /* used to flip between first and second write (0x2006) */ 23 | u32 ppu_addr_h = 0x00; 24 | 25 | u8 nt[4][0x400]; 26 | 27 | /* used for scrolling techniques */ 28 | u32 loopyT = 0x00; 29 | u32 loopyV = 0x00; 30 | u32 loopyX = 0x00; 31 | 32 | u32 ppu_addr = 0x2000; 33 | u32 ppu_addr_tmp = 0x2000; 34 | 35 | /* ppu status/temp registers */ 36 | u32 ppu_status; 37 | u32 ppu_status_tmp = 0x00; 38 | 39 | u32 sprite_address = 0x00; 40 | 41 | /* used to flip between first and second write (0x2005) */ 42 | u32 ppu_bgscr_f = 0x00; 43 | 44 | u8 color_lookup[0x80000]; 45 | 46 | int mirror[4]; 47 | 48 | /* used to export the current scanline for the debugger */ 49 | int current_scanline; 50 | 51 | u32 posCount = 0; 52 | extern u8 memory[65536]; 53 | extern u8 skipFrame; 54 | 55 | void drawBuffers() { 56 | gfxFlushBuffers(); 57 | gfxSwapBuffers(); 58 | 59 | } 60 | 61 | void init_ppu() { 62 | 63 | } 64 | 65 | 66 | void write_PPU_Memory(u32 address,u8 data) { 67 | 68 | if(address == 0x2000) { 69 | // ppu_addr_tmp = data; 70 | 71 | ppu_control1 = data; 72 | 73 | memory[address] = data; 74 | 75 | loopyT &= 0xf3ff; // (0000110000000000) 76 | loopyT |= (data & 3) << 10; // (00000011) 77 | 78 | return; 79 | } 80 | 81 | if(address == 0x2001) { 82 | ppu_addr_tmp = data; 83 | 84 | ppu_control2 = data; 85 | memory[address] = data; 86 | 87 | return; 88 | } 89 | 90 | /* SPRITE_Memory address register */ 91 | if(address == 0x2003) { 92 | ppu_addr_tmp = data; 93 | 94 | sprite_address = data; 95 | memory[address] = data; 96 | 97 | return; 98 | } 99 | 100 | /* SPRITE_Memory i/o register */ 101 | if(address == 0x2004) { 102 | ppu_addr_tmp = data; 103 | 104 | SPRITE_Memory[sprite_address] = data; 105 | sprite_address++; 106 | 107 | memory[address] = data; 108 | return; 109 | } 110 | 111 | /* vram address register #1 (scrolling) */ 112 | if(address == 0x2005) { 113 | ppu_addr_tmp = data; 114 | 115 | if(ppu_bgscr_f == 0x00) { 116 | loopyT &= 0xFFE0; // (0000000000011111) 117 | loopyT |= (data & 0xF8) >> 3; // (11111000) 118 | loopyX = data & 0x07; // (00000111) 119 | 120 | ppu_bgscr_f = 0x01; 121 | 122 | memory[address] = data; 123 | 124 | return; 125 | } 126 | 127 | if(ppu_bgscr_f == 0x01) { 128 | loopyT &= 0xFC1F; // (0000001111100000) 129 | loopyT |= (data & 0xF8) << 2; //(0111000000000000) 130 | loopyT &= 0x8FFF; //(11111000) 131 | loopyT |= (data & 0x07) << 12; // (00000111) 132 | 133 | ppu_bgscr_f = 0x00; 134 | 135 | memory[address] = data; 136 | 137 | return; 138 | } 139 | } 140 | 141 | /* vram address register #2 */ 142 | if(address == 0x2006) { 143 | ppu_addr_tmp = data; 144 | 145 | /* First write -> Store the high byte 6 bits and clear out the last two */ 146 | if(ppu_addr_h == 0x00) { 147 | loopyT &= 0x00FF; // (0011111100000000) 148 | loopyT |= (data & 0x3F) << 8; // (1100000000000000) (00111111) 149 | 150 | ppu_addr_h = 0x01; 151 | 152 | memory[address] = data; 153 | 154 | return; 155 | } 156 | 157 | /* Second write -> Store the low byte 8 bits */ 158 | if(ppu_addr_h == 0x01) { 159 | loopyT &= 0xFF00; // (0000000011111111) 160 | loopyT |= data; // (11111111) 161 | loopyV = loopyT; // v=t 162 | ppu_addr = loopyV; 163 | 164 | ppu_addr_h = 0x00; 165 | 166 | memory[address] = data; 167 | 168 | return; 169 | } 170 | } 171 | 172 | /* vram i/o register */ 173 | if(address == 0x2007) { 174 | /* if the vram_write_flag is on, vram writes should ignored */ 175 | if(vram_write_flag) return; 176 | 177 | ppu_addr_tmp = data; 178 | 179 | PPU_Memory[ppu_addr] = data; 180 | 181 | /* nametable mirroring */ 182 | if((ppu_addr >= 0x2000) && (ppu_addr <= 0x3EFF)) { 183 | if (ppu_addr >= 0x3000) {ppu_addr &= 0xEFFF;} 184 | nt[mirror[(ppu_addr & 0xC00) / 0x400]][ppu_addr & 0x3FF] = data; 185 | } 186 | 187 | /* palette mirror */ 188 | if(ppu_addr == 0x3f10) { 189 | PPU_Memory[0x3f00] = data; 190 | } 191 | 192 | ppu_addr_tmp = ppu_addr; 193 | 194 | if(!increment_32) { 195 | ppu_addr++; 196 | } else { 197 | ppu_addr += 0x20; 198 | } 199 | memory[address] = data; 200 | return; 201 | } 202 | 203 | /* transfer 256 bytes of memory into SPRITE_Memory */ 204 | if(address == 0x4014) {memcpy(SPRITE_Memory, memory + 0x100 * data, 256);} 205 | 206 | return; 207 | } 208 | 209 | 210 | void render_scanline(int scanline) { 211 | current_scanline = scanline; 212 | 213 | if (scanline == 0) { 214 | loopyV = loopyT; 215 | } else { 216 | loopyV &= 0xfbe0; 217 | loopyV |= (loopyT & 0x041f); 218 | } 219 | 220 | //Desenha Background e sprites 221 | // if (sprite_on) {render_sprite(scanline, true);} // Disable Speed Issues 222 | if (background_on && (skipFrame == 0)) {render_background(scanline);} 223 | if (sprite_on) {render_sprite(scanline, false);} 224 | 225 | if((loopyV & 0x7000) == 0x7000) { /* subtile y_offset == 7 */ 226 | loopyV &= 0x8fff; /* subtile y_offset = 0 */ 227 | if((loopyV & 0x03e0) == 0x03a0) { /* nametable line == 29 */ 228 | loopyV ^= 0x0800; /* switch nametables (bit 11) */ 229 | loopyV &= 0xfc1f; /* name table line = 0 */ 230 | } else { 231 | if((loopyV & 0x03e0) == 0x03e0) { /* nametable line == 31 */ 232 | loopyV &= 0xfc1f; /* name table line = 0 */ 233 | } else { 234 | loopyV += 0x0020; 235 | } 236 | } 237 | } else { 238 | loopyV += 0x1000; /* next subtile y_offset */ 239 | } 240 | } 241 | 242 | /* Draw Pixel for NES */ 243 | void draw_pixel(int x, int y, int nescolor) { 244 | /* don't fail on attempts to draw outside the screen. */ 245 | if ((x>=256) || (x<0)) {return;} 246 | if ((y>=240) || (y<0)) {return;} 247 | 248 | 249 | u8* topLeftFB = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); 250 | 251 | y = 240-y; 252 | x = 72+x; 253 | u32 v=(y+x*240)*2; 254 | 255 | topLeftFB[v] = NES_Palette[nescolor].COLOR_1; 256 | topLeftFB[v+1] = NES_Palette[nescolor].COLOR_2; 257 | } 258 | 259 | 260 | /* draw pixel RGB Format */ 261 | void draw_pixel_rgb(int x, int y, u8 r, u8 g, u8 b) { 262 | 263 | 264 | y = 240-y; 265 | x = 72+x; 266 | u32 v=(y+x*240)*2; 267 | 268 | u8* topLeftFB = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); 269 | 270 | topLeftFB[v] = (b >> 3) + ((g & 0x1C) << 3); 271 | topLeftFB[v+1] = ((g & 0xE0) >> 5) + (r & 0xF8); 272 | 273 | } 274 | 275 | 276 | void drawPixelBottom(int x, int y, u8 r, u8 g, u8 b) { 277 | y = 240-y; 278 | x = 72+x; 279 | u32 v=(y+x*240)*2; 280 | 281 | u8* bottomFrameBuffer = gfxGetFramebuffer(GFX_BOTTOM, GFX_BOTTOM, NULL, NULL); 282 | 283 | bottomFrameBuffer[v] = (b >> 3) + ((g & 0x1C) << 3); 284 | bottomFrameBuffer[v+1] = ((g & 0xE0) >> 5) + (r & 0xF8); 285 | } 286 | 287 | void draw_string(int sx, int sy, unsigned char str[]) { 288 | int i; 289 | for (i = 0; i < strlen(str); i++) { 290 | int fntnum = (str[i] - 32) & 0xFF; 291 | int y; 292 | for (y = 0; y < 8; y++) { 293 | int currbyte = fonts[(fntnum * 8) + y]; 294 | 295 | //Desenha sprite de 1BPP 296 | int x; 297 | int mult = 0x80; 298 | for(x = 0; x < 8; x++) { 299 | if ((currbyte & mult) == mult) { 300 | draw_pixel_rgb(sx + x, sy + y, 0xFF, 0xFF, 0xFF); 301 | draw_pixel_rgb(sx + x, sy + y + 1, 0, 0, 0); //Sombra 302 | } 303 | mult /= 2; 304 | } 305 | } 306 | sx += 8; 307 | } 308 | } 309 | 310 | 311 | void draw_image_24bpp(int sx, int sy, int w, int h, char img[]) { 312 | int x, y, i; 313 | i = 0; 314 | for (x = 0; x < w; x++) { 315 | for (y = h; y > 0; y--) { 316 | if (img[i] + img[i + 1] + img[i + 2] != 0) { //Trata preto como transparente 317 | draw_pixel_rgb(sx + x, sy + y, img[i + 2], img[i + 1], img[i]); 318 | } 319 | i += 3; 320 | } 321 | } 322 | } 323 | 324 | /* Draw Select Bar */ 325 | 326 | void draw_select_bar(int x, int y) { 327 | 328 | } 329 | 330 | 331 | 332 | /* Draw Text on the mid */ 333 | void draw_string_c(int sy, unsigned char str[]) { 334 | int sx = (240 / 2) - ((strlen(str) * 8) / 2); 335 | draw_string(sx, sy, str); 336 | } 337 | 338 | /* Render Background */ 339 | void render_background(int scanline) { 340 | 341 | int hscroll = ((loopyV & 31) << 3) + loopyX; 342 | int vscroll = (((loopyV >> 5) & 31) << 3) | ((loopyV / 0x1000) & 7); 343 | 344 | int tilerow = (vscroll >> 3) % 30; 345 | int tileyoffset = vscroll & 7; 346 | 347 | int ptaddr = 0; 348 | if(ppu_control1 & 0x10) ptaddr = 0x1000; 349 | 350 | int nt_addr = 0x2000 + (loopyV & 0xC00); 351 | int nt_num = (nt_addr & 0xC00) / 0x400; 352 | int fPix = 0; 353 | int tilecount; 354 | for (tilecount = (hscroll >> 3); tilecount < 32; tilecount++) { 355 | int tilex = (tilecount << 3) - hscroll + 7; 356 | if (tilex >= 7 && tilex <= 262) { 357 | int offset; 358 | if (tilex < 7) {offset = tilex;} else {offset = 7;} 359 | int tileindex = nt[mirror[nt_num]][tilecount + (tilerow << 5)]; 360 | int lookup = nt[mirror[nt_num]][0x3C0 + (tilecount >> 2) + ((tilerow >> 2) << 3)]; 361 | int bgpal = 0; 362 | switch ((tilecount & 2) | ((tilerow & 2) << 1)) { 363 | case 0: bgpal = (lookup << 2) & 12; break; 364 | case 2: bgpal = lookup & 12; break; 365 | case 4: bgpal = (lookup >> 2) & 12; break; 366 | case 6: bgpal = (lookup >> 4) & 12; break; 367 | } 368 | 369 | int bgtileoffset = ptaddr + (tileindex << 4); 370 | 371 | if (tileyoffset == 0) { 372 | int tiley; 373 | for(tiley = 0; tiley < 8; tiley++) { //Desenho padrão de sprite 2BPP 8x8 374 | unsigned char lowbyte = PPU_Memory[bgtileoffset + tiley]; 375 | unsigned char highbyte = PPU_Memory[bgtileoffset + tiley + 8]; 376 | 377 | int curcol; 378 | for(curcol = 0; curcol <= offset; curcol++) { 379 | int pcolor = 0; 380 | if(curcol == 0) 381 | fPix = 1; 382 | else 383 | fPix = (2 << (curcol - 1)); 384 | 385 | if (lowbyte & fPix) pcolor = 1; else pcolor = 0; 386 | if (highbyte & fPix) {pcolor += 2;} 387 | if ((pcolor & 0x3) != 0) { 388 | draw_pixel(tilex - curcol, scanline, PPU_Memory[0x3F00 + (pcolor | bgpal)]); 389 | } 390 | } 391 | if (tilex <= 61183) {tilex += 256;} 392 | } 393 | } else { 394 | unsigned char lowbyte = PPU_Memory[bgtileoffset + tileyoffset]; 395 | unsigned char highbyte = PPU_Memory[bgtileoffset + tileyoffset + 8]; 396 | 397 | int curcol; 398 | for(curcol = 0; curcol <= offset; curcol++) { 399 | int pcolor = 0; 400 | if(curcol == 0) 401 | fPix = 1; 402 | else 403 | fPix = (2 << (curcol - 1)); 404 | 405 | if (lowbyte & fPix) pcolor = 1; else pcolor = 0; 406 | if (highbyte & fPix) {pcolor += 2;} 407 | if ((pcolor & 0x3) != 0) { 408 | draw_pixel(tilex - curcol, scanline, PPU_Memory[0x3F00 + (pcolor | bgpal)]); 409 | } 410 | } 411 | } 412 | } 413 | } 414 | 415 | nt_addr ^= 0x400; 416 | nt_num = (nt_addr & 0xC00) / 0x400; 417 | 418 | /* FINISHED HERE */ 419 | 420 | for (tilecount = 0; tilecount <= (hscroll >> 3); tilecount++) { 421 | int tilex = (tilecount << 3) + 256 - hscroll + 7; 422 | if (tilex >= 7 && tilex <= 262) { 423 | int offset; 424 | if (tilex > 255) {offset = tilex - 255;} else {offset = 0;} 425 | int tileindex = nt[mirror[nt_num]][tilecount + (tilerow << 5)]; 426 | int lookup = nt[mirror[nt_num]][0x3C0 + (tilecount >> 2) + ((tilerow >> 2) << 3)]; 427 | int bgpal = 0; 428 | switch ((tilecount & 2) | ((tilerow & 2) << 1)) { 429 | case 0: bgpal = (lookup << 2) & 12; break; 430 | case 2: bgpal = lookup & 12; break; 431 | case 4: bgpal = (lookup >> 2) & 12; break; 432 | case 6: bgpal = (lookup >> 4) & 12; break; 433 | } 434 | int bgtileoffset = ptaddr + (tileindex << 4); 435 | if (tileyoffset == 0) { 436 | int tiley; 437 | for(tiley = 0; tiley < 8; tiley++) { //Desenho padrão de sprite 2BPP 8x8 438 | unsigned char lowbyte = PPU_Memory[bgtileoffset + tiley]; 439 | unsigned char highbyte = PPU_Memory[bgtileoffset + tiley + 8]; 440 | 441 | int curcol; 442 | for(curcol = offset; curcol < 8; curcol++) { 443 | int pcolor = 0; 444 | if(curcol == 0) 445 | fPix = 1; 446 | else 447 | fPix = (2 << (curcol - 1)); 448 | 449 | if (lowbyte & fPix) pcolor = 1; else pcolor = 0; 450 | if (highbyte & fPix) {pcolor += 2;} 451 | if ((pcolor & 0x3) != 0) { 452 | draw_pixel(tilex - curcol, scanline, PPU_Memory[0x3F00 + (pcolor | bgpal)]); 453 | } 454 | } 455 | if (tilex <= 61183) {tilex += 256;} 456 | } 457 | } else { 458 | unsigned char lowbyte = PPU_Memory[bgtileoffset + tileyoffset]; 459 | unsigned char highbyte = PPU_Memory[bgtileoffset + tileyoffset + 8]; 460 | 461 | int curcol; 462 | for(curcol = offset; curcol < 8; curcol++) { 463 | int pcolor = 0; 464 | if(curcol == 0) 465 | fPix = 1; 466 | else 467 | fPix = (2 << (curcol - 1)); 468 | 469 | if (lowbyte & fPix) pcolor = 1; else pcolor = 0; 470 | if (highbyte & fPix) {pcolor += 2;} 471 | if ((pcolor & 0x3) != 0) { 472 | draw_pixel(tilex - curcol, scanline, PPU_Memory[0x3F00 + (pcolor | bgpal)]); 473 | } 474 | } 475 | } 476 | } 477 | } 478 | } 479 | 480 | /* render sprites 16x16 8x8 */ 481 | void render_sprite(int scanline, bool foreground) { 482 | int currspr; 483 | for (currspr = 252; currspr >= 0; currspr-=4) { 484 | int spry = SPRITE_Memory[currspr] + 1; 485 | int tileindex = SPRITE_Memory[currspr + 1]; 486 | int attr = SPRITE_Memory[currspr + 2]; 487 | int sprx = SPRITE_Memory[currspr + 3]; 488 | register int fPix = 0; 489 | int ptaddr = 0; 490 | if(sprite_addr_hi) {ptaddr = 0x1000;} 491 | int tileh; 492 | if (sprite_16) {tileh = 16;} else {tileh = 8;} 493 | 494 | // bool ontop = attr & 32; 495 | int sprpal = 16 + ((attr & 3) << 2); 496 | bool vflip = attr & 128; 497 | bool hflip = attr & 64; 498 | 499 | int pcolor; 500 | //&& (ontop == foreground) 501 | if ((spry <= scanline) && (spry + tileh > scanline)) { 502 | if (!sprite_16) { //8x8 503 | int scan_to_draw; 504 | if (!vflip) {scan_to_draw = scanline - spry;} else {scan_to_draw = spry + 7 - scanline;} 505 | 506 | int sproffset = ptaddr + (tileindex * 16); 507 | unsigned char lowbyte = PPU_Memory[sproffset + scan_to_draw]; 508 | unsigned char highbyte = PPU_Memory[sproffset + scan_to_draw + 8]; 509 | int currpix; 510 | if (!hflip) { 511 | sprx += 7; 512 | for (currpix = 7; currpix >= 0; currpix--) { 513 | if(currpix == 0) 514 | fPix = 1; 515 | else 516 | fPix = (2 << (currpix - 1)); 517 | 518 | if (lowbyte & fPix) pcolor = 1; else pcolor = 0; 519 | if (highbyte & fPix) pcolor += 2; 520 | if ((pcolor & 0x3) != 0) { 521 | draw_pixel(sprx - currpix, scanline, PPU_Memory[0x3F00 + (pcolor | sprpal)]); 522 | if (currspr == 0) {ppu_status |= 0x40;} //Sprite 0 Hit Flag 523 | } 524 | } 525 | } else { 526 | for (currpix = 0; currpix < 8; currpix++) { 527 | if(currpix == 0) 528 | fPix = 1; 529 | else 530 | fPix = (2 << (currpix - 1)); 531 | 532 | if (lowbyte & fPix) pcolor = 1; else pcolor = 0; 533 | if (highbyte & fPix) pcolor += 2; 534 | if ((pcolor & 0x3) != 0) { 535 | draw_pixel(sprx + currpix, scanline, PPU_Memory[0x3F00 + (pcolor | sprpal)]); 536 | if (currspr == 0) {ppu_status |= 0x40;} //Sprite 0 Hit Flag 537 | } 538 | } 539 | } 540 | 541 | } else { //8x16 542 | int scan_to_draw; 543 | if (!vflip) {scan_to_draw = scanline - spry;} else {scan_to_draw = spry + 15 - scanline;} 544 | int sproffset; 545 | if (scan_to_draw < 8) { 546 | if (tileindex % 2 == 0) {sproffset = (tileindex << 4);} else {sproffset = 0x1000 + ((tileindex - 1) << 4);} 547 | } else { 548 | scan_to_draw -= 8; 549 | if (tileindex % 2 == 0) {sproffset = ((tileindex + 1) << 4);} else {sproffset = 0x1000 + (tileindex << 4);} 550 | } 551 | unsigned char lowbyte = PPU_Memory[sproffset + scan_to_draw]; 552 | unsigned char highbyte = PPU_Memory[sproffset + scan_to_draw + 8]; 553 | int currpix; 554 | if (!hflip) { 555 | sprx += 7; 556 | for (currpix = 7; currpix >= 0; currpix--) { 557 | if(currpix == 0) 558 | fPix = 1; 559 | else 560 | fPix = (2 << (currpix - 1)); 561 | 562 | if (lowbyte & fPix) pcolor = 1; else pcolor = 0; 563 | if (highbyte & fPix) pcolor += 2; 564 | if ((pcolor & 0x3) != 0) { 565 | draw_pixel(sprx - currpix, scanline, PPU_Memory[0x3F00 + (pcolor | sprpal)]); 566 | if (currspr == 0) {ppu_status |= 0x40;} //Sprite 0 Hit Flag 567 | } 568 | } 569 | } else { 570 | for (currpix = 0; currpix < 8; currpix++) { 571 | if(currpix == 0) 572 | fPix = 1; 573 | else 574 | fPix = (2 << (currpix - 1)); 575 | 576 | 577 | if (lowbyte & fPix) pcolor = 1; else pcolor = 0; 578 | if (highbyte & fPix) pcolor += 2; 579 | if ((pcolor & 0x3) != 0) { 580 | draw_pixel(sprx + currpix, scanline, PPU_Memory[0x3F00 + (pcolor | sprpal)]); 581 | if (currspr == 0) {ppu_status |= 0x40;} //Sprite 0 Hit Flag 582 | } 583 | } 584 | } 585 | } 586 | } 587 | } 588 | } 589 | 590 | 591 | /* Clear background with correct palette */ 592 | void NES_ColorBackground() { 593 | int nescolor = PPU_Memory[0x3f00]; 594 | int x; 595 | 596 | u8* bufAdr = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); 597 | 598 | 599 | for(x = 34560; x < 157440; x+=2){ 600 | bufAdr[x] = NES_Palette[nescolor].COLOR_1; 601 | bufAdr[x+1] = NES_Palette[nescolor].COLOR_2; 602 | } 603 | 604 | 605 | } 606 | 607 | /* draw menu image */ 608 | void drawMenu() { 609 | u8* bufAdr=gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); 610 | memset(bufAdr, 0x0, 0x2EE00); 611 | } 612 | 613 | 614 | void do_mirror(int type) { 615 | switch (type) { 616 | case 0: mirror[0] = 0; mirror[1] = 0; mirror[2] = 1; mirror[3] = 1; break; //H 617 | case 1: mirror[0] = 0; mirror[1] = 1; mirror[2] = 0; mirror[3] = 1; break; //V 618 | case 2: mirror[0] = 0; mirror[1] = 0; mirror[2] = 0; mirror[3] = 0; break; //OS1 619 | case 3: mirror[0] = 1; mirror[1] = 1; mirror[2] = 1; mirror[3] = 1; break; //OS2 620 | case 4: mirror[0] = 0; mirror[1] = 1; mirror[2] = 2; mirror[3] = 3; break; //FS 621 | } 622 | } 623 | 624 | -------------------------------------------------------------------------------- /include/gfx/imgdata.h: -------------------------------------------------------------------------------- 1 | const char fonts[] = { //Fonte 8x8 1BPP 2 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:0 3 | , 0x18, 0x18, 0x18, 0x18, 0x18, 0x0, 0x18, 0x0 //tile:1 4 | , 0x6c, 0x6c, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:2 5 | , 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x0 //tile:3 6 | , 0x18, 0x7e, 0xc0, 0x7c, 0x6, 0xfc, 0x18, 0x0 //tile:4 7 | , 0x0, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x0 //tile:5 8 | , 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x0 //tile:6 9 | , 0x30, 0x30, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:7 10 | , 0xc, 0x18, 0x30, 0x30, 0x30, 0x18, 0xc, 0x0 //tile:8 11 | , 0x30, 0x18, 0xc, 0xc, 0xc, 0x18, 0x30, 0x0 //tile:9 12 | , 0x0, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x0, 0x0 //tile:10 13 | , 0x0, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x0, 0x0 //tile:11 14 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x30 //tile:12 15 | , 0x0, 0x0, 0x0, 0x7e, 0x0, 0x0, 0x0, 0x0 //tile:13 16 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x0 //tile:14 17 | , 0x6, 0xc, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x0 //tile:15 18 | , 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0x7c, 0x0 //tile:16 19 | , 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x0 //tile:17 20 | , 0x7c, 0xc6, 0x6, 0x7c, 0xc0, 0xc0, 0xfe, 0x0 //tile:18 21 | , 0xfc, 0x6, 0x6, 0x3c, 0x6, 0x6, 0xfc, 0x0 //tile:19 22 | , 0xc, 0xcc, 0xcc, 0xcc, 0xfe, 0xc, 0xc, 0x0 //tile:20 23 | , 0xfe, 0xc0, 0xfc, 0x6, 0x6, 0xc6, 0x7c, 0x0 //tile:21 24 | , 0x7c, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x0 //tile:22 25 | , 0xfe, 0x6, 0x6, 0xc, 0x18, 0x30, 0x30, 0x0 //tile:23 26 | , 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x0 //tile:24 27 | , 0x7c, 0xc6, 0xc6, 0x7e, 0x6, 0x6, 0x7c, 0x0 //tile:25 28 | , 0x0, 0x18, 0x18, 0x0, 0x0, 0x18, 0x18, 0x0 //tile:26 29 | , 0x0, 0x18, 0x18, 0x0, 0x0, 0x18, 0x18, 0x30 //tile:27 30 | , 0xc, 0x18, 0x30, 0x60, 0x30, 0x18, 0xc, 0x0 //tile:28 31 | , 0x0, 0x0, 0x7e, 0x0, 0x7e, 0x0, 0x0, 0x0 //tile:29 32 | , 0x30, 0x18, 0xc, 0x6, 0xc, 0x18, 0x30, 0x0 //tile:30 33 | , 0x3c, 0x66, 0xc, 0x18, 0x18, 0x0, 0x18, 0x0 //tile:31 34 | , 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x7e, 0x0 //tile:32 35 | , 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x0 //tile:33 36 | , 0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0x0 //tile:34 37 | , 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x0 //tile:35 38 | , 0xf8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x0 //tile:36 39 | , 0xfe, 0xc0, 0xc0, 0xf8, 0xc0, 0xc0, 0xfe, 0x0 //tile:37 40 | , 0xfe, 0xc0, 0xc0, 0xf8, 0xc0, 0xc0, 0xc0, 0x0 //tile:38 41 | , 0x7c, 0xc6, 0xc0, 0xc0, 0xce, 0xc6, 0x7c, 0x0 //tile:39 42 | , 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x0 //tile:40 43 | , 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x0 //tile:41 44 | , 0x6, 0x6, 0x6, 0x6, 0x6, 0xc6, 0x7c, 0x0 //tile:42 45 | , 0xc6, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0xc6, 0x0 //tile:43 46 | , 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x0 //tile:44 47 | , 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x0 //tile:45 48 | , 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x0 //tile:46 49 | , 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x0 //tile:47 50 | , 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0x0 //tile:48 51 | , 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x6 //tile:49 52 | , 0xfc, 0xc6, 0xc6, 0xfc, 0xd8, 0xcc, 0xc6, 0x0 //tile:50 53 | , 0x7c, 0xc6, 0xc0, 0x7c, 0x6, 0xc6, 0x7c, 0x0 //tile:51 54 | , 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0 //tile:52 55 | , 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0x0 //tile:53 56 | , 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x38, 0x0 //tile:54 57 | , 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x0 //tile:55 58 | , 0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x0 //tile:56 59 | , 0xc6, 0xc6, 0xc6, 0x7c, 0x18, 0x30, 0xe0, 0x0 //tile:57 60 | , 0xfe, 0x6, 0xc, 0x18, 0x30, 0x60, 0xfe, 0x0 //tile:58 61 | , 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x0 //tile:59 62 | , 0xc0, 0x60, 0x30, 0x18, 0xc, 0x6, 0x2, 0x0 //tile:60 63 | , 0x3c, 0xc, 0xc, 0xc, 0xc, 0xc, 0x3c, 0x0 //tile:61 64 | , 0x10, 0x38, 0x6c, 0xc6, 0x0, 0x0, 0x0, 0x0 //tile:62 65 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff //tile:63 66 | , 0x18, 0x18, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:64 67 | , 0x0, 0x0, 0x7c, 0x6, 0x7e, 0xc6, 0x7e, 0x0 //tile:65 68 | , 0xc0, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xfc, 0x0 //tile:66 69 | , 0x0, 0x0, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x0 //tile:67 70 | , 0x6, 0x6, 0x6, 0x7e, 0xc6, 0xc6, 0x7e, 0x0 //tile:68 71 | , 0x0, 0x0, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x0 //tile:69 72 | , 0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x0 //tile:70 73 | , 0x0, 0x0, 0x7e, 0xc6, 0xc6, 0x7e, 0x6, 0xfc //tile:71 74 | , 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x0 //tile:72 75 | , 0x18, 0x0, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x0 //tile:73 76 | , 0x6, 0x0, 0x6, 0x6, 0x6, 0x6, 0xc6, 0x7c //tile:74 77 | , 0xc0, 0xc0, 0xcc, 0xd8, 0xf8, 0xcc, 0xc6, 0x0 //tile:75 78 | , 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x0 //tile:76 79 | , 0x0, 0x0, 0xcc, 0xfe, 0xfe, 0xd6, 0xd6, 0x0 //tile:77 80 | , 0x0, 0x0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x0 //tile:78 81 | , 0x0, 0x0, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x0 //tile:79 82 | , 0x0, 0x0, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0 //tile:80 83 | , 0x0, 0x0, 0x7e, 0xc6, 0xc6, 0x7e, 0x6, 0x6 //tile:81 84 | , 0x0, 0x0, 0xfc, 0xc6, 0xc0, 0xc0, 0xc0, 0x0 //tile:82 85 | , 0x0, 0x0, 0x7e, 0xc0, 0x7c, 0x6, 0xfc, 0x0 //tile:83 86 | , 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0xe, 0x0 //tile:84 87 | , 0x0, 0x0, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x0 //tile:85 88 | , 0x0, 0x0, 0xc6, 0xc6, 0xc6, 0x7c, 0x38, 0x0 //tile:86 89 | , 0x0, 0x0, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x0 //tile:87 90 | , 0x0, 0x0, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x0 //tile:88 91 | , 0x0, 0x0, 0xc6, 0xc6, 0xc6, 0x7e, 0x6, 0xfc //tile:89 92 | , 0x0, 0x0, 0xfe, 0xc, 0x38, 0x60, 0xfe, 0x0 //tile:90 93 | , 0xe, 0x18, 0x18, 0x70, 0x18, 0x18, 0xe, 0x0 //tile:91 94 | , 0x18, 0x18, 0x18, 0x0, 0x18, 0x18, 0x18, 0x0 //tile:92 95 | , 0x70, 0x18, 0x18, 0xe, 0x18, 0x18, 0x70, 0x0 //tile:93 96 | , 0x76, 0xdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:94 97 | , 0x0, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x0 //tile:95 98 | }; 99 | 100 | const char logo[] = { //3DNes / Nes Emulator (64 * 32 * 3) 24BPP 101 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 102 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 103 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 104 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 105 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 106 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 107 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 108 | , 0x0, 0x0, 0x0, 0x40, 0x0, 0x9, 0x85, 0x0, 0x12, 0x8f, 0x0, 0x14, 0x85, 0x0, 0x11, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x84, 0x0, 0x11, 0x8c, 0x0, 0x13, 0x8c, 0x0, 0x13, 0x4f, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x83, 0x0, 0x12, 0x88, 0x0, 0x12, 0x8e, 0x0, 0x13, 0x89, 0x0, 0x13, 0x48, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x8a, 0x0, 0x12, 0x8, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 109 | , 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0x9e, 0x4b, 0x56, 0xbe, 0xa3, 0xa7, 0xc1, 0xbc, 0xbd, 0xbb, 0xbb, 0xbb, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xc0, 0xbe, 0xbd, 0xc1, 0xb0, 0xb3, 0xa5, 0x5d, 0x67, 0x80, 0x0, 0x12, 0x76, 0x0, 0x10, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xbe, 0xbc, 0xbc, 0xc1, 0xbc, 0xbd, 0xbf, 0xab, 0xae, 0xa1, 0x54, 0x5f, 0x80, 0x0, 0x12, 0x8c, 0x0, 0x13, 0x10, 0x0, 0x2, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xbe, 0xbc, 0xbd, 0x83, 0x9, 0x1a, 0x74, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xb9, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 110 | , 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xbd, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbc, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbc, 0xbc, 0xbd, 0xbc, 0xbc, 0xb9, 0x90, 0x95, 0x88, 0x0, 0x12, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xbc, 0xbd, 0xbc, 0xbc, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbc, 0xbd, 0xbd, 0xbc, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbc, 0xbd, 0xc3, 0xb3, 0xb5, 0x87, 0x12, 0x22, 0x8f, 0x0, 0x14, 0x1, 0x0, 0x0, 0x80, 0x0, 0x12, 0xbc, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xb7, 0x8d, 0x93, 0x88, 0x0, 0x12, 0x10, 0x0, 0x2, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xbd, 0xbc, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 111 | , 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xc5, 0xc0, 0xc1, 0xb8, 0x8d, 0x93, 0x9b, 0x44, 0x50, 0x85, 0xe, 0x1f, 0x85, 0xd, 0x1d, 0x9b, 0x41, 0x4e, 0xc4, 0xb2, 0xb5, 0xc0, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc4, 0xc2, 0xc3, 0x87, 0x0, 0x12, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xbf, 0xbf, 0xc0, 0xbf, 0xc0, 0xc0, 0xbf, 0xc0, 0xbf, 0x80, 0x0, 0x12, 0x82, 0x6, 0x17, 0x92, 0x2d, 0x3b, 0xb5, 0x82, 0x89, 0xc4, 0xc2, 0xc3, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc6, 0xbd, 0xbd, 0x80, 0x1, 0x13, 0x64, 0x0, 0xe, 0x80, 0x0, 0x12, 0xc0, 0xbf, 0xc0, 0xbf, 0xbf, 0xc0, 0xc0, 0xbf, 0xbf, 0xc0, 0xc0, 0xbf, 0xc3, 0xc2, 0xc2, 0x87, 0x12, 0x22, 0x7c, 0x0, 0x11, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xc0, 0xc0, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x5a, 0x0, 0xc, 0x8f, 0x0, 0x13, 0x89, 0x0, 0x12, 0x82, 0x0, 0x12, 0x82, 0x0, 0x12, 0x82, 0x0, 0x12, 0x87, 0x0, 0x12, 0x8f, 0x0, 0x13, 0x61, 0x0, 0xd, 0x4, 0x0, 0x0, 0x74, 0x0, 0x10, 0x8e, 0x0, 0x13, 0x87, 0x0, 0x12, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x85, 0x0, 0x11, 0x8f, 0x0, 0x14, 0x83, 0x0, 0x11, 0x3e, 0x0, 0x8, 0x0, 0x0, 0x0 112 | , 0x0, 0x0, 0x0, 0x8e, 0x0, 0x14, 0x8e, 0x0, 0x14, 0x8e, 0x0, 0x14, 0x73, 0x0, 0xf, 0x3a, 0x0, 0x8, 0x3c, 0x0, 0x8, 0x8b, 0x0, 0x12, 0x8c, 0x1f, 0x2f, 0xc2, 0xc3, 0xc3, 0xc2, 0xc3, 0xc2, 0xc4, 0xc5, 0xc5, 0x87, 0x0, 0x12, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xc3, 0xc2, 0xc3, 0xc3, 0xc2, 0xc3, 0xc3, 0xc3, 0xc2, 0x80, 0x0, 0x12, 0x26, 0x0, 0x5, 0x6b, 0x0, 0xe, 0x8c, 0x0, 0x13, 0x8c, 0x1d, 0x2d, 0xc8, 0xc6, 0xc6, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xb2, 0x7a, 0x82, 0x8f, 0x0, 0x14, 0x80, 0x0, 0x12, 0xc3, 0xc3, 0xc3, 0xc2, 0xc3, 0xc2, 0xc3, 0xc3, 0xc3, 0xc9, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xbe, 0x9c, 0xa0, 0x87, 0x0, 0x12, 0x18, 0x0, 0x3, 0x80, 0x0, 0x12, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc3, 0x80, 0x0, 0x12, 0x88, 0x0, 0x13, 0x80, 0x0, 0x12, 0xac, 0x6c, 0x75, 0xc8, 0xbc, 0xbe, 0xc7, 0xc5, 0xc6, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc9, 0xc0, 0xc1, 0xb0, 0x77, 0x7f, 0x80, 0x0, 0x12, 0x89, 0x0, 0x13, 0x81, 0x4, 0x16, 0xba, 0x90, 0x96, 0xc9, 0xc2, 0xc2, 0xc5, 0xc5, 0xc5, 0xc2, 0xc3, 0xc3, 0xc5, 0xc5, 0xc4, 0xc9, 0xc4, 0xc4, 0xc2, 0xa6, 0xa9, 0x9f, 0x4a, 0x56, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0 113 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x87, 0x12, 0x23, 0x9e, 0x48, 0x54, 0xc9, 0xb7, 0xba, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc4, 0xa9, 0xad, 0x87, 0x0, 0x12, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x0, 0x3, 0x8c, 0x0, 0x13, 0xb4, 0x7f, 0x86, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xcb, 0xc1, 0xc2, 0x88, 0x0, 0x12, 0x80, 0x0, 0x12, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xa5, 0x59, 0x63, 0xc6, 0xc6, 0xc6, 0xc8, 0xc8, 0xc8, 0x8b, 0x1c, 0x2b, 0x83, 0x0, 0x11, 0x80, 0x0, 0x12, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x80, 0x0, 0x12, 0x80, 0x1, 0x13, 0xc7, 0xb2, 0xb5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xb2, 0xb5, 0x80, 0x0, 0x12, 0xc6, 0xaf, 0xb2, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0 114 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xba, 0x8b, 0x92, 0x80, 0x1, 0x13, 0x83, 0x0, 0x12, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xc9, 0xc9, 0xc9, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x66, 0x0, 0xe, 0x90, 0x26, 0x35, 0xc9, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xcb, 0xca, 0xca, 0x82, 0x0, 0x12, 0x80, 0x0, 0x12, 0xc9, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0x80, 0x0, 0x12, 0xcd, 0xc0, 0xc3, 0xc9, 0xc9, 0xc9, 0xc6, 0xaa, 0xae, 0x85, 0x0, 0x12, 0x80, 0x0, 0x12, 0xc9, 0xca, 0xc9, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0x80, 0x0, 0x12, 0xb9, 0x88, 0x8f, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xce, 0xcb, 0xcb, 0xa8, 0x5e, 0x69, 0x86, 0x10, 0x21, 0x99, 0x3c, 0x49, 0xcd, 0xc4, 0xc5, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xb7, 0x84, 0x8b, 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xca, 0xc9, 0xc9, 0xc9, 0xb6, 0x7f, 0x87, 0x86, 0x10, 0x21, 0x86, 0x10, 0x21, 0x9f, 0x4a, 0x56, 0xbe, 0x97, 0x9c, 0xcd, 0xc8, 0xc9, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0 115 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xd1, 0xcd, 0xce, 0x96, 0x34, 0x42, 0x8e, 0x0, 0x13, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x0, 0x4, 0x83, 0x8, 0x19, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcc, 0xcc, 0xcc, 0x82, 0x0, 0x12, 0x80, 0x0, 0x12, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0x80, 0x0, 0x12, 0x9c, 0x41, 0x4e, 0xcd, 0xcc, 0xcd, 0xce, 0xcd, 0xcd, 0x91, 0x28, 0x37, 0x80, 0x0, 0x12, 0xcd, 0xcc, 0xcc, 0xcc, 0xcd, 0xcc, 0xcd, 0xcd, 0xcd, 0x80, 0x0, 0x12, 0xd0, 0xcb, 0xcc, 0xcd, 0xcc, 0xcc, 0xcd, 0xcc, 0xcd, 0xa7, 0x5a, 0x65, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x93, 0x2c, 0x3b, 0xcc, 0xcc, 0xcc, 0xcd, 0xcc, 0xcc, 0xd0, 0xca, 0xcb, 0xcf, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xa9, 0x5f, 0x6a, 0x80, 0x1, 0x13, 0x84, 0x0, 0x12, 0x8e, 0x0, 0x13, 0x8e, 0x0, 0x13, 0x8e, 0x0, 0x13, 0x8e, 0x0, 0x13, 0x0, 0x0, 0x0 116 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x8d, 0x1e, 0x2e, 0xad, 0x68, 0x72, 0xd3, 0xcd, 0xce, 0xcf, 0xd0, 0xcf, 0xd0, 0xcf, 0xd0, 0xd2, 0xc5, 0xc7, 0x87, 0x0, 0x12, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xd0, 0xcf, 0xcf, 0xcf, 0xd0, 0xcf, 0xcf, 0xd0, 0xd0, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x0, 0xe, 0x91, 0x28, 0x37, 0xd0, 0xcf, 0xd0, 0xd0, 0xcf, 0xd0, 0xd2, 0xd0, 0xd0, 0x82, 0x0, 0x12, 0x80, 0x0, 0x12, 0xcf, 0xd0, 0xd0, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0x80, 0x0, 0x12, 0x81, 0x0, 0x12, 0xce, 0xbb, 0xbd, 0xd0, 0xd0, 0xd0, 0xcb, 0xb6, 0xb9, 0x80, 0x0, 0x12, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xd0, 0xcf, 0xd0, 0xd0, 0x80, 0x0, 0x12, 0xd0, 0xd1, 0xd1, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xd0, 0xd0, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xc8, 0xad, 0xb0, 0xd0, 0xd0, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd0, 0xd0, 0xd4, 0xd0, 0xd0, 0xcf, 0xbc, 0xbf, 0xb2, 0x74, 0x7c, 0x80, 0x0, 0x12, 0x80, 0x0, 0x11, 0x0, 0x0, 0x0 117 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x0, 0x3, 0x53, 0x0, 0xb, 0x8e, 0x0, 0x14, 0x98, 0x37, 0x45, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd4, 0xd4, 0xd3, 0x84, 0x0, 0x11, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd3, 0xd3, 0xd3, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x0, 0x3, 0x8c, 0x0, 0x13, 0xba, 0x86, 0x8d, 0xd2, 0xd3, 0xd3, 0xd3, 0xd2, 0xd3, 0xd4, 0xc9, 0xcb, 0x87, 0x0, 0x12, 0x80, 0x0, 0x12, 0xd3, 0xd3, 0xd2, 0xd3, 0xd3, 0xd2, 0xd3, 0xd3, 0xd3, 0x80, 0x0, 0x12, 0x8a, 0x0, 0x13, 0x93, 0x2d, 0x3b, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0x97, 0x35, 0x43, 0xd3, 0xd2, 0xd3, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd3, 0x80, 0x0, 0x12, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0x80, 0x2, 0x14, 0xbc, 0x8c, 0x92, 0xd4, 0xcb, 0xcc, 0xd5, 0xd3, 0xd4, 0xd3, 0xd3, 0xd2, 0xd3, 0xd2, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xc9, 0xab, 0xaf, 0x89, 0x0, 0x12, 0x0, 0x0, 0x0 118 | , 0x0, 0x0, 0x0, 0x8e, 0x0, 0x14, 0x8e, 0x0, 0x14, 0x8e, 0x0, 0x14, 0x71, 0x0, 0xf, 0x35, 0x0, 0x7, 0x49, 0x0, 0xa, 0x8f, 0x0, 0x13, 0x96, 0x32, 0x40, 0xd6, 0xd6, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0x84, 0x0, 0x11, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0x80, 0x0, 0x12, 0x25, 0x0, 0x5, 0x6b, 0x0, 0xe, 0x8b, 0x0, 0x13, 0x8d, 0x1f, 0x2e, 0xd8, 0xd5, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xb9, 0x81, 0x89, 0x8f, 0x0, 0x14, 0x80, 0x0, 0x12, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0x80, 0x0, 0x12, 0x25, 0x0, 0x5, 0x84, 0x0, 0x12, 0xcc, 0xb0, 0xb4, 0xd6, 0xd6, 0xd6, 0xd2, 0xc1, 0xc3, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0x80, 0x0, 0x12, 0xd8, 0xd2, 0xd3, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xa0, 0x48, 0x54, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x8f, 0x0, 0x13, 0x87, 0x0, 0x12, 0x80, 0x0, 0x12, 0x8a, 0x17, 0x27, 0xb9, 0x83, 0x8a, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd8, 0xd7, 0xd7, 0x86, 0x0, 0x12, 0x0, 0x0, 0x0 119 | , 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xda, 0xd5, 0xd6, 0xc3, 0x95, 0x9c, 0x9d, 0x43, 0x4f, 0x85, 0xd, 0x1e, 0x88, 0x14, 0x24, 0xa9, 0x5d, 0x68, 0xda, 0xd3, 0xd5, 0xda, 0xd9, 0xda, 0xda, 0xd9, 0xd9, 0xd8, 0xcc, 0xce, 0x84, 0x0, 0x11, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xd9, 0xd9, 0xda, 0xda, 0xd9, 0xd9, 0xda, 0xd9, 0xd9, 0x80, 0x0, 0x12, 0x81, 0x4, 0x16, 0x94, 0x2e, 0x3c, 0xbf, 0x8d, 0x93, 0xdc, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xce, 0xcf, 0x80, 0x1, 0x13, 0x64, 0x0, 0xe, 0x80, 0x0, 0x12, 0xd9, 0xda, 0xd9, 0xda, 0xd9, 0xd9, 0xda, 0xd9, 0xd9, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x83, 0x0, 0x11, 0x8c, 0x1b, 0x2b, 0xda, 0xda, 0xda, 0xd9, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xda, 0xda, 0xd9, 0xda, 0xda, 0xda, 0x80, 0x0, 0x12, 0xbd, 0x8a, 0x91, 0xd9, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xdb, 0xd7, 0xd9, 0xb1, 0x6d, 0x77, 0x8b, 0x19, 0x29, 0x82, 0x6, 0x18, 0x92, 0x29, 0x38, 0xae, 0x68, 0x72, 0xcc, 0xad, 0xb1, 0xdb, 0xd7, 0xd8, 0xdb, 0xd3, 0xd5, 0xc1, 0x93, 0x99, 0x9e, 0x43, 0x4f, 0x85, 0xd, 0x1e, 0x85, 0xd, 0x1e, 0xb8, 0x7e, 0x86, 0xd9, 0xd9, 0xd9, 0xda, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0x86, 0x0, 0x12, 0x0, 0x0, 0x0 120 | , 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xdc, 0xdd, 0xdc, 0xdd, 0xdc, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdd, 0xdc, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xdd, 0xdc, 0xdd, 0xdd, 0xdd, 0x9a, 0x3b, 0x48, 0x8e, 0x0, 0x14, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xdd, 0xdd, 0xdc, 0xdc, 0xdd, 0xdc, 0xdc, 0xdd, 0xdc, 0xdd, 0xdc, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdd, 0xdc, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdd, 0xdc, 0xdc, 0xd8, 0xc8, 0xc9, 0x88, 0x13, 0x24, 0x8f, 0x0, 0x14, 0x1, 0x0, 0x0, 0x80, 0x0, 0x12, 0xdd, 0xdc, 0xdc, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x16, 0x0, 0x3, 0x87, 0x0, 0x12, 0xc9, 0xa2, 0xa7, 0xdd, 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xdd, 0xdc, 0xdd, 0xdc, 0xdd, 0xdd, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0xd1, 0xb7, 0xba, 0xdc, 0xdd, 0xdd, 0xdd, 0xdc, 0xdd, 0xdd, 0xdd, 0xdc, 0xdd, 0xdd, 0xdc, 0xdd, 0xdd, 0xdc, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdd, 0xdd, 0xdc, 0xdd, 0xdc, 0xdc, 0xdd, 0xdc, 0xdd, 0xdc, 0xdc, 0xdd, 0xdd, 0xdc, 0xdd, 0xdd, 0xdc, 0xdc, 0xdd, 0xdd, 0xdc, 0xdc, 0xdd, 0xdc, 0xdc, 0xdd, 0xdc, 0xdd, 0xdc, 0xdd, 0xdc, 0xd0, 0xb6, 0xb9, 0x86, 0x0, 0x12, 0x0, 0x0, 0x0 121 | , 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xa9, 0x5c, 0x67, 0xd6, 0xc0, 0xc3, 0xe1, 0xdd, 0xdd, 0xdf, 0xe0, 0xdf, 0xe0, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xd7, 0xd8, 0xcc, 0xa8, 0xad, 0x8b, 0x1a, 0x2a, 0x8b, 0x0, 0x12, 0x2f, 0x0, 0x6, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xdf, 0xe0, 0xdf, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xe0, 0xdf, 0xe0, 0xdf, 0xe0, 0xe0, 0xe0, 0xdf, 0xe0, 0xe0, 0xdb, 0xdb, 0xd6, 0xc2, 0xc5, 0xaa, 0x5d, 0x67, 0x80, 0x0, 0x12, 0x8c, 0x0, 0x13, 0x10, 0x0, 0x2, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x0, 0x10, 0x85, 0xc, 0x1d, 0xe0, 0xde, 0xdf, 0xdf, 0xe0, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0x80, 0x0, 0x12, 0x84, 0x0, 0x12, 0x80, 0x0, 0x12, 0xac, 0x61, 0x6c, 0xda, 0xc9, 0xcb, 0xe1, 0xdd, 0xde, 0xe0, 0xe0, 0xe1, 0xe0, 0xdf, 0xdf, 0xe1, 0xdf, 0xe0, 0xde, 0xd6, 0xd7, 0xcf, 0xb1, 0xb5, 0xa3, 0x4d, 0x59, 0xa5, 0x52, 0x5e, 0xd3, 0xba, 0xbe, 0xe0, 0xdb, 0xdb, 0xe0, 0xe0, 0xe0, 0xdf, 0xe0, 0xdf, 0xe0, 0xe1, 0xe0, 0xdf, 0xd7, 0xd8, 0xc3, 0x94, 0x9b, 0x80, 0x1, 0x13, 0x83, 0x0, 0x12, 0x0, 0x0, 0x0 122 | , 0x0, 0x0, 0x0, 0x47, 0x0, 0x9, 0x88, 0x0, 0x13, 0x8d, 0x0, 0x13, 0x84, 0x0, 0x12, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x87, 0x0, 0x12, 0x8f, 0x0, 0x13, 0x7c, 0x0, 0x11, 0x15, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x82, 0x0, 0x12, 0x88, 0x0, 0x12, 0x8e, 0x0, 0x13, 0x89, 0x0, 0x13, 0x48, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x1, 0x8a, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x80, 0x0, 0x12, 0x0, 0x0, 0x0, 0x4c, 0x0, 0xa, 0x8b, 0x0, 0x13, 0x8c, 0x0, 0x13, 0x84, 0x0, 0x12, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x88, 0x0, 0x12, 0x8e, 0x0, 0x13, 0x80, 0x0, 0x11, 0x85, 0x0, 0x12, 0x8e, 0x0, 0x13, 0x84, 0x0, 0x11, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x81, 0x0, 0x12, 0x87, 0x0, 0x12, 0x8f, 0x0, 0x13, 0x6f, 0x0, 0xf, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 123 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 124 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 125 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xd1, 0xd1, 0xd1, 0x5, 0x5, 0x5, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 126 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x81, 0x81, 0x81, 0x71, 0x71, 0x71, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x3b, 0x3b, 0x3b, 0xdb, 0xdb, 0xdb, 0xe8, 0xe8, 0xe8, 0x4c, 0x4c, 0x4c, 0x0, 0x0, 0x0, 0x7a, 0x7a, 0x7a, 0xea, 0xea, 0xea, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b, 0x3b, 0x3b, 0xdb, 0xdb, 0xdb, 0xe8, 0xe8, 0xe8, 0x4c, 0x4c, 0x4c, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x95, 0x95, 0x95, 0xf5, 0xf5, 0xf5, 0x6d, 0x6d, 0x6d, 0x9e, 0x9e, 0x9e, 0xf2, 0xf2, 0xf2, 0x73, 0x73, 0x73, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x43, 0x43, 0x43, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0x43, 0x43, 0x43, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x91, 0x91, 0x91, 0xf9, 0xf9, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 127 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xc, 0xc, 0xc, 0xd7, 0xd7, 0xd7, 0x10, 0x10, 0x10, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xcf, 0xcf, 0xcf, 0x49, 0x49, 0x49, 0x31, 0x31, 0x31, 0xd9, 0xd9, 0xd9, 0x0, 0x0, 0x0, 0xf1, 0xf1, 0xf1, 0x5d, 0x5d, 0x5d, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xcf, 0xcf, 0x49, 0x49, 0x49, 0x31, 0x31, 0x31, 0xd9, 0xd9, 0xd9, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x4b, 0x4b, 0x4b, 0x2f, 0x2f, 0x2f, 0xfb, 0xfb, 0xfb, 0x4b, 0x4b, 0x4b, 0x2f, 0x2f, 0x2f, 0xe9, 0xe9, 0xe9, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x31, 0x31, 0xe1, 0xe1, 0xe1, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd4, 0xd4, 0xd4, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0xd3, 0xd3, 0xd3, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x5d, 0x5d, 0x5d, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 128 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x6b, 0x6b, 0x6b, 0x8d, 0x8d, 0x8d, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xf6, 0xf6, 0xf6, 0xfb, 0xfb, 0xfb, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0x0, 0x0, 0x0, 0x59, 0x59, 0x59, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0x12, 0x12, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf6, 0xf6, 0xf6, 0xfb, 0xfb, 0xfb, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x7a, 0x7a, 0x7a, 0xec, 0xec, 0xec, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf7, 0xf7, 0xf7, 0x5, 0x5, 0x5, 0x6, 0x6, 0x6, 0xf6, 0xf6, 0xf6, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 129 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0xd4, 0xd4, 0xd4, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xce, 0xce, 0xce, 0x4b, 0x4b, 0x4b, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0xc4, 0xc4, 0xc4, 0x54, 0x54, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xce, 0xce, 0xce, 0x4b, 0x4b, 0x4b, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xeb, 0xeb, 0xeb, 0x30, 0x30, 0x30, 0x4d, 0x4d, 0x4d, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xf3, 0xf3, 0xf3, 0x38, 0x38, 0x38, 0x3e, 0x3e, 0x3e, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xf5, 0xf5, 0xf5, 0x18, 0x18, 0x18, 0x0, 0x0, 0x0, 0xd4, 0xd4, 0xd4, 0x48, 0x48, 0x48, 0x4a, 0x4a, 0x4a, 0xd4, 0xd4, 0xd4, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 130 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x35, 0x35, 0x35, 0xd2, 0xd2, 0xd2, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xc2, 0xc2, 0x11, 0x11, 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x35, 0x35, 0x35, 0xd2, 0xd2, 0xd2, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x77, 0x77, 0x77, 0xf3, 0xf3, 0xf3, 0x93, 0x93, 0x93, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x97, 0x97, 0x97, 0xf1, 0xf1, 0xf1, 0x92, 0x92, 0x92, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x8b, 0x8b, 0x8b, 0xf2, 0xf2, 0xf2, 0xff, 0xff, 0xff, 0x45, 0x45, 0x45, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0x45, 0x45, 0x45, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 131 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 132 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 133 | }; 134 | --------------------------------------------------------------------------------