├── .gitignore ├── GUI_ControlPage.c ├── GUI_ControlPage.h ├── GUI_Credits.c ├── GUI_Credits.h ├── GUI_FileBrowser.c ├── GUI_FileBrowser.h ├── GUI_GUIPage.c ├── GUI_GUIPage.h ├── GUI_Help.c ├── GUI_Help.h ├── GUI_MainMenu.c ├── GUI_MainMenu.h ├── GUI_SystemPage.c ├── GUI_SystemPage.h ├── GUI_VideoPage.c ├── GUI_VideoPage.h ├── K6502.c ├── K6502.h ├── K6502_rw.c ├── K6502_rw.h ├── Makefile ├── Mapper.c ├── Mapper.h ├── Mapper_0.c ├── Mapper_0.h ├── Mapper_1.c ├── Mapper_1.h ├── Mapper_11.c ├── Mapper_11.h ├── Mapper_111.c ├── Mapper_111.h ├── Mapper_119.c ├── Mapper_119.h ├── Mapper_2.c ├── Mapper_2.h ├── Mapper_21.c ├── Mapper_21.h ├── Mapper_22.c ├── Mapper_22.h ├── Mapper_23.c ├── Mapper_23.h ├── Mapper_24.c ├── Mapper_24.h ├── Mapper_25.c ├── Mapper_25.h ├── Mapper_26.c ├── Mapper_26.h ├── Mapper_3.c ├── Mapper_3.h ├── Mapper_30.c ├── Mapper_30.h ├── Mapper_4.c ├── Mapper_4.h ├── Mapper_5.c ├── Mapper_5.h ├── Mapper_64.c ├── Mapper_64.h ├── Mapper_66.c ├── Mapper_66.h ├── Mapper_67.c ├── Mapper_67.h ├── Mapper_68.c ├── Mapper_68.h ├── Mapper_69.c ├── Mapper_69.h ├── Mapper_7.c ├── Mapper_7.h ├── Mapper_73.c ├── Mapper_73.h ├── Mapper_75.c ├── Mapper_75.h ├── Mapper_85.c ├── Mapper_85.h ├── Mapper_9.c ├── Mapper_9.h ├── README.md ├── ROMLoad.c ├── ROMLoad.h ├── TextWindow.c ├── TextWindow.h ├── aica_fw.c ├── aica_fw.h ├── font.c ├── font.h ├── input_recorder.c ├── input_recorder.h ├── macros.h ├── nes_apu.c ├── nes_apu.h ├── nes_exsound.c ├── nes_exsound.h ├── pNesX.c ├── pNesX.h ├── pNesX_DrawLine_BG_C.c ├── pNesX_DrawLine_BG_C.h ├── pNesX_DrawLine_BG_C_Map9.c ├── pNesX_DrawLine_BG_C_Map9.h ├── pNesX_DrawLine_Spr_C.c ├── pNesX_DrawLine_Spr_C.h ├── pNesX_DrawLine_Spr_C_Map9.c ├── pNesX_PPU_DC.c ├── pNesX_PPU_DC.h ├── pNesX_Sound_APU.c ├── pNesX_Sound_APU.h ├── pNesX_System.h ├── pNesX_System_DC.c ├── pNesX_System_DC.h ├── profile.c ├── profile.h ├── romdisk ├── nes.pal ├── neuro.fnt ├── neuro_0.png └── neuro_1.png ├── sound_tables ├── make_lineartable.c ├── make_logtable.c ├── tbl │ ├── lineartable.h │ └── logtable.h └── tbl_param.h ├── utarray.h ├── uthash.h ├── utlist.h ├── utstring.h └── vmu_icons.h /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.DS_Store 3 | *.o 4 | *.img 5 | *.sh 6 | 7 | release 8 | debug 9 | 10 | romdisk/*.nes 11 | romdisk/ROMS 12 | romdisk/tests 13 | 14 | -------------------------------------------------------------------------------- /GUI_ControlPage.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_ControlPage.h : GUI Page for Control Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef GUI_CONTROLPAGE 11 | #define GUI_CONTROLPAGE 12 | 13 | #include 14 | #include "TextWindow.h" 15 | 16 | #include "GUI_MainMenu.h" 17 | 18 | //Function Definitions 19 | void setup_control_options_screen(); 20 | void Generate_Control_Options_List(); 21 | void Handle_Control_Interface(cont_state_t* my_state); 22 | 23 | //External Variables Required 24 | extern Window_Style mystyle; 25 | extern Window_Data mydata; 26 | extern Window_Style helpstyle; 27 | extern Window_Data helpdata; 28 | 29 | extern int keyhit; 30 | extern int invalida; 31 | extern int xkeyhit; 32 | extern int menuscreen; 33 | extern const int MAX_CLIP_PIXELS; 34 | extern const int title_offset_y; 35 | extern const int Max_Frameskip; 36 | 37 | extern char* Main_Keys[]; 38 | extern char* Options_Keys[]; 39 | extern const int Num_Options_Keys; 40 | 41 | typedef struct __attribute__ ((packed, aligned(4))) ControllerSettings_s { 42 | bool analogEnabled; 43 | uint8 selectKey; 44 | uint8 aKey; 45 | uint8 bKey; 46 | } ControllerSettings_t; 47 | 48 | #define DC_CONTROLLER_BUTTON_A 0 49 | #define DC_CONTROLLER_BUTTON_B 1 50 | #define DC_CONTROLLER_BUTTON_X 2 51 | #define DC_CONTROLLER_BUTTON_Y 3 52 | #define DC_CONTROLLER_BUTTON_LTRIG 4 53 | 54 | extern ControllerSettings_t controllerSettings[]; 55 | 56 | #endif -------------------------------------------------------------------------------- /GUI_Credits.c: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_ControlPage.c : GUI Page for Control Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #include "GUI_Credits.h" 11 | #include "macros.h" 12 | 13 | #include "pNesX_System_DC.h" 14 | 15 | //About Screen Comments 16 | char* About_Text[] = { 17 | "FrNES is a NES emulator for", 18 | "Sega Dreamcast. It was based", 19 | "on the first release of", 20 | "Racoons NES emulator for", 21 | "Playstation, pNesX.", 22 | "Now it has so much new", 23 | "code in it, it cannot", 24 | "truly be considered a", 25 | "port of the original", 26 | "", 27 | "This final version of", 28 | "0.6 includes new code", 29 | "for the PPU renderer", 30 | "written in assembly", 31 | "language. As well, new", 32 | "code was introduced for", 33 | "mappers 7 and 9, with", 34 | "many more on their way", 35 | "", 36 | "", 37 | "", 38 | "Credits:", 39 | " ReGex - Emulator Code", 40 | " - Tools + GUI", 41 | " Miss Soy Beansprout", 42 | " - Art", 43 | " Racoon - PS Version", 44 | " Matt Conte - Sound Code", 45 | " Marat - 6502 Emulator", 46 | " Dan Potter", 47 | " Marcus Comstedt", 48 | " Jordan DeLong", 49 | " And Many More", 50 | " Kallistios", 51 | "", 52 | "Do not distribute this", 53 | "with ROM images!" 54 | }; 55 | 56 | const int Num_About_Text = 36; 57 | 58 | void setup_credits_screen() 59 | { 60 | //Set Up Window Data Features 61 | mydata.x = 208.0f; 62 | mydata.y = 32.0f; 63 | mydata.width = 400.0f; 64 | mydata.height = 416.0f; 65 | mydata.font = font; 66 | mydata.Header_Text = "FrNES Credits";//Main_Options[6]; 67 | mydata.Data_Strings = About_Text; 68 | mydata.Num_Strings = Num_About_Text; 69 | mydata.Highlighted_Index = 0; 70 | mydata.Top_Index = 0; 71 | 72 | //Set Up Window Style Features 73 | mystyle.Header_Text_Scale = 1.0f; 74 | mystyle.Text_Scale = 0.60f; 75 | mystyle.Border_Thickness = 5.0f; 76 | mystyle.Border_Color = GUI_OutsideWindowColor; // MakeRGB(8, 20, 10); 77 | mystyle.Inside_Color = GUI_InsideWindowColor; //MakeRGB(8, 20, 32); 78 | mystyle.Left_Margin = 15; 79 | mystyle.Line_Spacing = 0.0f; 80 | mystyle.Header_Text_Color = GUI_TextColor; //0x8000; 81 | mystyle.Text_Color = GUI_TextColor; 82 | mystyle.Max_Items = (mydata.height - (mydata.font -> fontHeight * mystyle.Header_Text_Scale)) / ((float)mydata.font -> fontHeight * mystyle.Text_Scale); 83 | mystyle.Selected_Text_Color = GUI_SelectedTextColor; 84 | mystyle.Selected_Background_Color = GUI_SelectedTextColor; //MakeRGB(8, 18, 32); 85 | 86 | 87 | //Set Up Window Data Features 88 | helpdata.x = 32.0f; 89 | helpdata.y = 300.0f; 90 | helpdata.width = 160.0f; 91 | helpdata.height = 148.0f; 92 | helpdata.font = font; 93 | helpdata.Header_Text = " "; 94 | helpdata.Data_Strings = Main_Keys; 95 | helpdata.Num_Strings = Num_Main_Keys; 96 | helpdata.Highlighted_Index = Num_Main_Keys; 97 | helpdata.Top_Index = 0; 98 | 99 | //Set Up Window Style Features 100 | helpstyle.Border_Thickness = 5.0f; 101 | helpstyle.Border_Color = GUI_OutsideWindowColor; 102 | helpstyle.Inside_Color = GUI_InsideWindowColor; 103 | helpstyle.Left_Margin = 15; 104 | helpstyle.Line_Spacing = 0.0f; 105 | helpstyle.Header_Text_Color = GUI_TextColor; 106 | helpstyle.Text_Color = GUI_TextColor; 107 | helpstyle.Text_Scale = 0.40f; 108 | helpstyle.Max_Items = 10; 109 | helpstyle.Selected_Text_Color = GUI_SelectedTextColor; 110 | helpstyle.Selected_Background_Color = GUI_SelectedTextColor;//MakeRGB(31, 18, 8); 111 | } 112 | 113 | void Handle_Credits_Interface(cont_state_t* my_state) 114 | { 115 | //printf("main loop: handling credits controller\n"); 116 | //Down Key Hit and Key is Ready to be hit 117 | if ((my_state -> buttons & CONT_DPAD_DOWN) && 118 | (mydata.Highlighted_Index < Num_About_Text)) 119 | { 120 | mydata.Highlighted_Index++; 121 | if ((mydata.Highlighted_Index - mydata.Top_Index) >= mystyle.Max_Items) 122 | mydata.Top_Index++; 123 | keyhit = 1; 124 | } 125 | 126 | //Up Key Hit and Key is Ready to be hit 127 | if ((my_state -> buttons & CONT_DPAD_UP) && 128 | (mydata.Highlighted_Index > 0)) 129 | { 130 | mydata.Highlighted_Index--; 131 | if (mydata.Top_Index > mydata.Highlighted_Index) 132 | mydata.Top_Index--; 133 | keyhit = 1; 134 | } 135 | 136 | // Handle Return to Main Menu 137 | if ((my_state -> buttons & CONT_B) && 138 | (keyhit == 0)) 139 | { 140 | setup_main_menu_screen(); 141 | menuscreen = MENUNUM_MAIN; 142 | } 143 | } -------------------------------------------------------------------------------- /GUI_Credits.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_ControlPage.h : GUI Page for Control Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef GUI_CREDITS 11 | #define GUI_CREDITS 12 | 13 | #include 14 | #include "TextWindow.h" 15 | 16 | #include "GUI_MainMenu.h" 17 | 18 | //Function Definitions 19 | void setup_credits_screen(); 20 | void Handle_Credits_Interface(cont_state_t* my_state); 21 | 22 | //External Variables Required 23 | extern Window_Style mystyle; 24 | extern Window_Data mydata; 25 | extern Window_Style helpstyle; 26 | extern Window_Data helpdata; 27 | 28 | extern int keyhit; 29 | extern int invalida; 30 | extern int xkeyhit; 31 | extern int romselstatus; 32 | extern const int MAX_CLIP_PIXELS; 33 | extern const int title_offset_y; 34 | extern const int Max_Frameskip; 35 | 36 | extern char* Main_Keys[]; 37 | extern const int Num_Main_Keys; 38 | extern char* Options_Keys[]; 39 | extern const int Num_Options_Keys; 40 | 41 | #endif -------------------------------------------------------------------------------- /GUI_FileBrowser.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_VideoPage.h : GUI Page for Video Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef GUI_FILEBROWSER 11 | #define GUI_FILEBROWSER 12 | 13 | #include 14 | #include "TextWindow.h" 15 | 16 | #include "GUI_MainMenu.h" 17 | 18 | //Function Definitions 19 | void setup_file_browser_screen(); 20 | void Handle_File_Browser_Interface(cont_state_t* my_state); 21 | 22 | //External Variables Required 23 | extern Window_Style mystyle; 24 | extern Window_Data mydata; 25 | extern Window_Style helpstyle; 26 | extern Window_Data helpdata; 27 | 28 | extern int keyhit; 29 | extern int invalida; 30 | extern int xkeyhit; 31 | extern int disable_trigs; 32 | extern int menuscreen; 33 | extern const int MAX_CLIP_PIXELS; 34 | extern const int title_offset_y; 35 | 36 | extern unsigned char* ROM; 37 | extern unsigned char* VROM; 38 | extern uint32 SRAM_Enabled; 39 | 40 | #endif -------------------------------------------------------------------------------- /GUI_GUIPage.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_GUIPage.h : GUI Page for GUI Custom Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef GUI_GUIPAGE 11 | #define GUI_GUIPAGE 12 | 13 | #include 14 | #include "TextWindow.h" 15 | 16 | #include "GUI_MainMenu.h" 17 | 18 | //Function Definitions 19 | void setup_gui_options_screen(); 20 | void Generate_GUI_Options_List(); 21 | void Handle_GUI_Interface(cont_state_t* my_state); 22 | void Allocate_GUI_Options(); 23 | void Free_GUI_Options(); 24 | 25 | //External Variables Required 26 | extern Window_Style mystyle; 27 | extern Window_Data mydata; 28 | extern Window_Style helpstyle; 29 | extern Window_Data helpdata; 30 | 31 | extern int keyhit; 32 | extern int invalida; 33 | extern int xkeyhit; 34 | extern int menuscreen; 35 | extern const int MAX_CLIP_PIXELS; 36 | extern const int title_offset_y; 37 | extern const int Max_Frameskip; 38 | 39 | extern char* Main_Keys[]; 40 | extern char* Options_Keys[]; 41 | extern const int Num_Options_Keys; 42 | 43 | extern const char Tag_Slider[]; 44 | extern const char SLIDERBOX_MAX[]; 45 | extern const char SLIDERBOX_MIN[]; 46 | extern const char SLIDERBOX_VALUE[]; 47 | 48 | #endif -------------------------------------------------------------------------------- /GUI_Help.c: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_ControlPage.c : GUI Page for Control Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #include "GUI_Help.h" 11 | #include "macros.h" 12 | 13 | #include "pNesX_System_DC.h" 14 | 15 | //Help Screen Comments 16 | char* Help_Text[] = { 17 | "At the Options Screen", 18 | " Left and Right on DPad", 19 | " change Options and move", 20 | " sliders", 21 | "", 22 | " A Toggles Checkboxes", 23 | "", 24 | "Inside the Emu", 25 | " LTrig and RTrig - Exit", 26 | "", 27 | "Otherwise:", 28 | " 2 Players are supported", 29 | " As long as the controllers", 30 | " Have been scanned at boot", 31 | " or at the menu option." 32 | }; 33 | 34 | const int Num_Help_Text = 14; 35 | 36 | //Generic help for other text/screens 37 | char* Text_Keys[] = { 38 | "Keys", 39 | "A - Choose", 40 | "DPAD - Move" 41 | }; 42 | const int Num_Text_Keys = 3; 43 | 44 | void setup_help_screen() 45 | { 46 | //Set Up Window Data Features 47 | mydata.x = 208.0f; 48 | mydata.y = 32.0f; 49 | mydata.width = 400.0f; 50 | mydata.height = 416.0f; 51 | mydata.font = font; 52 | mydata.Header_Text = "Help";//Main_Options[5]; 53 | mydata.Data_Strings = Help_Text; 54 | mydata.Num_Strings = Num_Help_Text; 55 | mydata.Highlighted_Index = 0; 56 | mydata.Top_Index = 0; 57 | 58 | //Set Up Window Style Features 59 | mystyle.Header_Text_Scale = 1.0f; 60 | mystyle.Text_Scale = 0.40f; 61 | mystyle.Border_Thickness = 5.0f; 62 | mystyle.Border_Color = GUI_OutsideWindowColor; // MakeRGB(8, 20, 10); 63 | mystyle.Inside_Color = GUI_InsideWindowColor; //MakeRGB(8, 20, 32); 64 | mystyle.Left_Margin = 15; 65 | mystyle.Line_Spacing = 0.0f; 66 | mystyle.Header_Text_Color = GUI_TextColor; //0x8000; 67 | mystyle.Text_Color = GUI_TextColor; 68 | mystyle.Max_Items = (mydata.height - (mydata.font -> fontHeight * mystyle.Header_Text_Scale)) / ((float)mydata.font -> fontHeight * mystyle.Text_Scale); 69 | mystyle.Selected_Text_Color = GUI_SelectedTextColor; 70 | mystyle.Selected_Background_Color = GUI_SelectedTextColor; //MakeRGB(8, 18, 32); 71 | 72 | //Set Up Window Data Features 73 | helpdata.x = 32.0f; 74 | helpdata.y = 300.0f; 75 | helpdata.width = 160.0f; 76 | helpdata.height = 148.0f; 77 | helpdata.font = font; 78 | helpdata.Header_Text = ""; 79 | helpdata.Data_Strings = Text_Keys; 80 | helpdata.Num_Strings = Num_Text_Keys; 81 | helpdata.Highlighted_Index = 0; 82 | helpdata.Top_Index = 0; 83 | 84 | //Set Up Window Style Features 85 | helpstyle.Border_Thickness = 5.0f; 86 | helpstyle.Border_Color = GUI_OutsideWindowColor; 87 | helpstyle.Inside_Color = GUI_InsideWindowColor; 88 | helpstyle.Left_Margin = 15; 89 | helpstyle.Line_Spacing = 0.0f; 90 | helpstyle.Header_Text_Color = GUI_TextColor; 91 | helpstyle.Text_Color = GUI_TextColor; 92 | helpstyle.Max_Items = 10; 93 | helpstyle.Selected_Text_Color = GUI_SelectedTextColor; 94 | helpstyle.Selected_Background_Color = GUI_SelectedTextColor;//MakeRGB(31, 18, 8); 95 | } 96 | 97 | void Handle_Help_Interface(cont_state_t* my_state) 98 | { 99 | //printf("main loop: handling help controller\n"); 100 | //Down Key Hit and Key is Ready to be hit 101 | if ((my_state -> buttons & CONT_DPAD_DOWN) && 102 | (mydata.Highlighted_Index < Num_Help_Text)) 103 | { 104 | mydata.Highlighted_Index++; 105 | if ((mydata.Highlighted_Index - mydata.Top_Index) >= mystyle.Max_Items) 106 | mydata.Top_Index++; 107 | keyhit = 1; 108 | } 109 | 110 | //Up Key Hit and Key is Ready to be hit 111 | if ((my_state -> buttons & CONT_DPAD_UP) && 112 | (mydata.Highlighted_Index > 0)) 113 | { 114 | mydata.Highlighted_Index--; 115 | if (mydata.Top_Index > mydata.Highlighted_Index) 116 | mydata.Top_Index--; 117 | keyhit = 1; 118 | } 119 | 120 | // Handle Return to Main Menu 121 | if ((my_state -> buttons & CONT_B) && 122 | (keyhit == 0)) 123 | { 124 | setup_main_menu_screen(); 125 | menuscreen = MENUNUM_MAIN; 126 | } 127 | } -------------------------------------------------------------------------------- /GUI_Help.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_ControlPage.h : GUI Page for Control Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef GUI_HELP 11 | #define GUI_HELP 12 | 13 | #include 14 | #include "TextWindow.h" 15 | 16 | #include "GUI_MainMenu.h" 17 | 18 | //Function Definitions 19 | void setup_help_screen(); 20 | void Handle_Help_Interface(cont_state_t* my_state); 21 | 22 | //External Variables Required 23 | extern Window_Style mystyle; 24 | extern Window_Data mydata; 25 | extern Window_Style helpstyle; 26 | extern Window_Data helpdata; 27 | 28 | extern int keyhit; 29 | extern int invalida; 30 | extern int xkeyhit; 31 | extern int romselstatus; 32 | extern const int MAX_CLIP_PIXELS; 33 | extern const int title_offset_y; 34 | extern const int Max_Frameskip; 35 | 36 | extern char* Main_Keys[]; 37 | extern const int Num_Main_Keys; 38 | extern char* Options_Keys[]; 39 | extern const int Num_Options_Keys; 40 | 41 | #endif -------------------------------------------------------------------------------- /GUI_MainMenu.c: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_ControlPage.c : GUI Page for Control Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #include "GUI_MainMenu.h" 11 | #include "macros.h" 12 | 13 | #include "pNesX_System_DC.h" 14 | 15 | extern void setup_file_browser_screen(); 16 | extern void setup_credits_screen(); 17 | extern void setup_control_options_screen(); 18 | extern void Generate_Control_Options_List(); 19 | extern void setup_system_options_screen(); 20 | extern void Generate_System_Options_List(); 21 | extern void setup_help_screen(); 22 | extern void setup_video_options_screen(); 23 | extern void Generate_Video_Options_List(); 24 | extern void setup_gui_options_screen(); 25 | extern void Generate_GUI_Options_List(); 26 | 27 | char Main_Menu[] = "Main Menu"; 28 | char* Main_Options[] = { 29 | "Select A Rom", 30 | "Video Options", 31 | "Control Options", 32 | "System Options", 33 | "GUI Options", 34 | "Help", 35 | "FrNES Credits" 36 | }; 37 | const int Num_Main = 7; 38 | 39 | //Help for the Main screen 40 | char* Main_Keys[] = { 41 | "Main", 42 | "A - Choose", 43 | "DPAD - Move" 44 | }; 45 | const int Num_Main_Keys = 3; 46 | 47 | void setup_main_menu_screen() 48 | { 49 | //Set Up Window Data Features 50 | mydata.x = 208.0f; 51 | mydata.y = 32.0f; 52 | mydata.width = 400.0f; 53 | mydata.height = 416.0f; 54 | mydata.font = font; 55 | mydata.Header_Text = Main_Menu; 56 | mydata.Data_Strings = Main_Options; 57 | mydata.Num_Strings = Num_Main; 58 | mydata.Highlighted_Index = 0; 59 | mydata.Top_Index = 0; 60 | 61 | //Set Up Window Style Features 62 | mystyle.Header_Text_Scale = 1.0f; 63 | mystyle.Text_Scale = 0.60f; 64 | mystyle.Border_Thickness = 5.0f; 65 | mystyle.Border_Color = GUI_OutsideWindowColor; // MakeRGB(8, 20, 10); 66 | mystyle.Inside_Color = GUI_InsideWindowColor; //MakeRGB(8, 20, 32); 67 | mystyle.Left_Margin = 15; 68 | mystyle.Line_Spacing = 0.0f; 69 | mystyle.Header_Text_Color = GUI_TextColor; //0x8000; 70 | mystyle.Text_Color = GUI_TextColor; 71 | mystyle.Max_Items = (mydata.height - (mydata.font -> fontHeight * mystyle.Header_Text_Scale)) / ((float)mydata.font -> fontHeight * mystyle.Text_Scale); 72 | mystyle.Selected_Text_Color = GUI_SelectedTextColor; 73 | mystyle.Selected_Background_Color = GUI_SelectedTextColor; //MakeRGB(8, 18, 32); 74 | 75 | //Set Up Window Data Features 76 | helpdata.x = 32.0f; 77 | helpdata.y = 300.0f; 78 | helpdata.width = 160.0f; 79 | helpdata.height = 148.0f; 80 | helpdata.font = font; 81 | helpdata.Header_Text = " "; 82 | helpdata.Data_Strings = Main_Keys; 83 | helpdata.Num_Strings = Num_Main_Keys; 84 | helpdata.Highlighted_Index = Num_Main_Keys; 85 | helpdata.Top_Index = 0; 86 | 87 | //Set Up Window Style Features 88 | helpstyle.Header_Text_Scale = 0.5f; 89 | helpstyle.Text_Scale = 0.5f; 90 | helpstyle.Border_Thickness = 5.0f; 91 | helpstyle.Border_Color = GUI_OutsideWindowColor; 92 | helpstyle.Inside_Color = GUI_InsideWindowColor; 93 | helpstyle.Left_Margin = 15; 94 | helpstyle.Line_Spacing = 0.0f; 95 | helpstyle.Header_Text_Color = GUI_TextColor; 96 | helpstyle.Text_Color = GUI_TextColor; 97 | helpstyle.Max_Items = 10; 98 | helpstyle.Selected_Text_Color = GUI_SelectedTextColor; 99 | helpstyle.Selected_Background_Color = GUI_SelectedTextColor;//MakeRGB(31, 18, 8); 100 | } 101 | 102 | void Handle_Main_Menu_Interface(cont_state_t* my_state) 103 | { 104 | if ((my_state -> buttons & CONT_DPAD_DOWN) && 105 | (mydata.Highlighted_Index < (Num_Main - 1)) && 106 | (keyhit == 0)) 107 | { 108 | mydata.Highlighted_Index++; 109 | keyhit = 1; 110 | } 111 | 112 | //Up Key Hit and Key is Ready to be hit 113 | if ((my_state -> buttons & CONT_DPAD_UP) && 114 | (mydata.Highlighted_Index > 0) && 115 | (keyhit == 0)) 116 | { 117 | mydata.Highlighted_Index--; 118 | 119 | keyhit = 1; 120 | } 121 | 122 | //Choose and setup another page 123 | if ((my_state -> buttons & CONT_A) && 124 | (invalida == 0)) 125 | { 126 | switch (mydata.Highlighted_Index) 127 | { 128 | case PAGE_ROMSELECT: 129 | //Menu Screen = Romselect 130 | menuscreen = MENUNUM_ROMSELECT; 131 | romselstatus = 0; 132 | disable_rom_interface = 0; 133 | setup_file_browser_screen(); 134 | break; 135 | 136 | case PAGE_CREDITS: 137 | //Menu Screen = About 138 | menuscreen = MENUNUM_CREDITS; 139 | setup_credits_screen(); 140 | break; 141 | 142 | case PAGE_CONTROLOPTIONS: 143 | //Menu Screen = Options 144 | menuscreen = MENUNUM_CONTROLOPTIONS; 145 | setup_control_options_screen(); 146 | Generate_Control_Options_List(); 147 | break; 148 | 149 | case PAGE_SYSTEMOPTIONS: 150 | //Menu Screen = Options 151 | menuscreen = MENUNUM_SYSTEMOPTIONS; 152 | setup_system_options_screen(); 153 | Generate_System_Options_List(); 154 | break; 155 | 156 | case PAGE_HELP: 157 | //Menu Screen = Help 158 | menuscreen = MENUNUM_HELP; 159 | setup_help_screen(); 160 | break; 161 | 162 | case PAGE_VIDEOOPTIONS: 163 | menuscreen = MENUNUM_VIDEOOPTIONS; 164 | setup_video_options_screen(); 165 | Generate_Video_Options_List(); 166 | break; 167 | 168 | case PAGE_GUIOPTIONS: 169 | menuscreen = MENUNUM_GUIOPTIONS; 170 | setup_gui_options_screen(); 171 | Generate_GUI_Options_List(); 172 | break; 173 | 174 | default: 175 | break; 176 | } 177 | invalida = 1; 178 | } 179 | } -------------------------------------------------------------------------------- /GUI_MainMenu.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_ControlPage.h : GUI Page for Control Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef GUI_MAINMENU 11 | #define GUI_MAINMENU 12 | 13 | #include 14 | #include "TextWindow.h" 15 | #include "font.h" 16 | 17 | extern Font* font; 18 | 19 | //Function Definitions 20 | void setup_main_menu_screen(); 21 | void Handle_Main_Menu_Interface(cont_state_t* my_state); 22 | 23 | //External Variables Required 24 | extern Window_Style mystyle; 25 | extern Window_Data mydata; 26 | extern Window_Style helpstyle; 27 | extern Window_Data helpdata; 28 | 29 | extern int keyhit; 30 | extern int invalida; 31 | extern int xkeyhit; 32 | extern int romselstatus; 33 | extern int disable_rom_interface; 34 | extern int menuscreen; 35 | extern const int MAX_CLIP_PIXELS; 36 | extern const int title_offset_y; 37 | extern const int Max_Frameskip; 38 | 39 | extern char* Main_Keys[]; 40 | extern const int Num_Main_Keys; 41 | extern char* Options_Keys[]; 42 | extern const int Num_Options_Keys; 43 | 44 | extern uint32 GUI_BGColor; 45 | extern uint32 GUI_OutsideWindowColor; 46 | extern uint32 GUI_InsideWindowColor; 47 | extern uint32 GUI_TextColor; 48 | extern uint32 GUI_SelectedTextColor; 49 | 50 | #endif -------------------------------------------------------------------------------- /GUI_SystemPage.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_SystemPage.h : GUI Page for System Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef GUI_SYSTEMPAGE 11 | #define GUI_SYSTEMPAGE 12 | 13 | #include 14 | #include "TextWindow.h" 15 | 16 | #include "GUI_MainMenu.h" 17 | 18 | //Function Definitions 19 | void setup_system_options_screen(); 20 | void Generate_System_Options_List(); 21 | void Handle_System_Interface(cont_state_t* my_state); 22 | 23 | //External Variables Required 24 | extern Window_Style mystyle; 25 | extern Window_Data mydata; 26 | extern Window_Style helpstyle; 27 | extern Window_Data helpdata; 28 | 29 | extern int keyhit; 30 | extern int invalida; 31 | extern int xkeyhit; 32 | extern int menuscreen; 33 | extern const int MAX_CLIP_PIXELS; 34 | extern const int title_offset_y; 35 | extern const int Max_Frameskip; 36 | 37 | extern char* Main_Keys[]; 38 | extern char* Options_Keys[]; 39 | extern const int Num_Options_Keys; 40 | 41 | extern maple_device_t* VMUs[]; 42 | 43 | //Options Variables 44 | extern uint16 opt_SoundEnabled; 45 | extern uint16 opt_FrameSkip; 46 | extern uint16 opt_AutoFrameSkip; 47 | extern uint16 opt_ShowFrameRate; 48 | extern int16 opt_VMUPort; 49 | extern uint16 opt_SRAM; 50 | 51 | #endif -------------------------------------------------------------------------------- /GUI_VideoPage.c: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_VideoPage.c : GUI Page for Video Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #include "GUI_VideoPage.h" 11 | #include "macros.h" 12 | 13 | #include "pNesX_System_DC.h" 14 | 15 | uint16 opt_Stretch; 16 | uint16 opt_Filter; 17 | uint8 opt_ClipVars[4]; 18 | 19 | char ClipLX_Buffer[50]; 20 | char ClipRX_Buffer[50]; 21 | char ClipTX_Buffer[50]; 22 | char ClipBX_Buffer[50]; 23 | 24 | const int MAX_CLIP_PIXELS = 64; 25 | 26 | //Video Options Text 27 | char Options_Video[] = "Video Options"; 28 | char Options_Stretch_Checked[] = "Stretch Video,CBC_CHECKED"; 29 | char Options_Stretch_Unchecked[] = "Stretch Video,CBC_UNCHECKED"; 30 | char Options_Filter_Checked[] = "Bilinear Filter,CBC_CHECKED"; 31 | char Options_Filter_Unchecked[] = "Bilinear Filter,CBC_UNCHECKED"; 32 | char Options_Clip_Left[] = "Clip Left Pixels"; 33 | char Options_Clip_Right[] = "Clip Right Pixels"; 34 | char Options_Clip_Top[] = "Clip Top Pixels"; 35 | char Options_Clip_Bottom[] = "Clip Bottom Pixels"; 36 | char* Video_Options[6]; 37 | const int Num_Video_Options = 6; 38 | 39 | void setup_video_options_screen() { 40 | //Set Up Window Data Features 41 | mydata.x = 208.0f; 42 | mydata.y = 32.0f; 43 | mydata.width = 400.0f; 44 | mydata.height = 416.0f; 45 | mydata.font = font; 46 | mydata.Header_Text = Options_Video; 47 | mydata.Data_Strings = Video_Options; 48 | mydata.Num_Strings = Num_Video_Options; 49 | mydata.Highlighted_Index = 0; 50 | mydata.Top_Index = 0; 51 | 52 | //Set Up Window Style Features 53 | mystyle.Header_Text_Scale = 1.0f; 54 | mystyle.Text_Scale = 0.60f; 55 | mystyle.Border_Thickness = 5.0f; 56 | mystyle.Border_Color = GUI_OutsideWindowColor; // MakeRGB(8, 20, 10); 57 | mystyle.Inside_Color = GUI_InsideWindowColor; //MakeRGB(8, 20, 32); 58 | mystyle.Left_Margin = 15; 59 | mystyle.Line_Spacing = 2.0f; 60 | mystyle.Header_Text_Color = GUI_TextColor; //0x8000; 61 | mystyle.Text_Color = GUI_TextColor; 62 | mystyle.Max_Items = (mydata.height - (mydata.font -> fontHeight * mystyle.Header_Text_Scale)) / ((float)mydata.font -> fontHeight * mystyle.Text_Scale); 63 | mystyle.Selected_Text_Color = GUI_SelectedTextColor; 64 | mystyle.Selected_Background_Color = GUI_SelectedTextColor; //MakeRGB(8, 18, 32); 65 | 66 | //Set Up Window Data Features 67 | helpdata.x = 32.0f; 68 | helpdata.y = 300.0f; 69 | helpdata.width = 160.0f; 70 | helpdata.height = 148.0f; 71 | helpdata.font = font; 72 | helpdata.Header_Text = " "; 73 | helpdata.Data_Strings = Options_Keys; 74 | helpdata.Num_Strings = Num_Options_Keys; 75 | helpdata.Highlighted_Index = Num_Options_Keys; 76 | helpdata.Top_Index = 0; 77 | 78 | //Set Up Window Style Features 79 | helpstyle.Border_Thickness = 5.0f; 80 | helpstyle.Border_Color = GUI_OutsideWindowColor; 81 | helpstyle.Inside_Color = GUI_InsideWindowColor; 82 | helpstyle.Left_Margin = 15; 83 | helpstyle.Line_Spacing = 0.0f; 84 | helpstyle.Header_Text_Color = GUI_TextColor; 85 | helpstyle.Text_Color = GUI_TextColor; 86 | helpstyle.Max_Items = 10; 87 | helpstyle.Selected_Text_Color = GUI_SelectedTextColor; 88 | helpstyle.Selected_Background_Color = GUI_SelectedTextColor;//MakeRGB(31, 18, 8); 89 | } 90 | 91 | //Generates the Options GUI info from the variables in memory 92 | void Generate_Video_Options_List() { 93 | switch(opt_Stretch) { 94 | case 0: 95 | Video_Options[0] = Options_Stretch_Unchecked; 96 | break; 97 | case 1: 98 | Video_Options[0] = Options_Stretch_Checked; 99 | break; 100 | } 101 | switch(opt_Filter) { 102 | case 0: 103 | Video_Options[1] = Options_Filter_Unchecked; 104 | break; 105 | case 1: 106 | Video_Options[1] = Options_Filter_Checked; 107 | break; 108 | } 109 | 110 | snprintf(ClipLX_Buffer, 50, "%s,%u", Options_Clip_Left, opt_ClipVars[0]); 111 | Video_Options[2] = ClipLX_Buffer; 112 | 113 | snprintf(ClipRX_Buffer, 50, "%s,%u", Options_Clip_Right, opt_ClipVars[1]); 114 | Video_Options[3] = ClipRX_Buffer; 115 | 116 | snprintf(ClipTX_Buffer, 50, "%s,%u", Options_Clip_Top, opt_ClipVars[2]); 117 | Video_Options[4] = ClipTX_Buffer; 118 | 119 | snprintf(ClipBX_Buffer, 50, "%s,%u", Options_Clip_Bottom, opt_ClipVars[3]); 120 | Video_Options[5] = ClipBX_Buffer; 121 | } 122 | 123 | void Handle_Video_Interface(cont_state_t* my_state) { 124 | //Down Key Hit and Key is Ready to be hit 125 | if ((my_state -> buttons & CONT_DPAD_DOWN) && 126 | (mydata.Highlighted_Index < Num_Video_Options) && 127 | (keyhit == 0)) { 128 | mydata.Highlighted_Index++; 129 | if ((mydata.Highlighted_Index - mydata.Top_Index) >= mystyle.Max_Items) 130 | mydata.Top_Index++; 131 | keyhit = 1; 132 | } 133 | 134 | //Up Key Hit and Key is Ready to be hit 135 | if ((my_state -> buttons & CONT_DPAD_UP) && 136 | (mydata.Highlighted_Index > 0) && 137 | (keyhit == 0)) { 138 | mydata.Highlighted_Index--; 139 | if (mydata.Top_Index > mydata.Highlighted_Index) 140 | mydata.Top_Index--; 141 | keyhit = 1; 142 | } 143 | 144 | //Handle the toggle boxes 145 | if ((my_state -> buttons & CONT_A) && 146 | (invalida == 0)) { 147 | switch(mydata.Highlighted_Index) { 148 | case 0: 149 | opt_Stretch = 1 - opt_Stretch; 150 | Generate_Video_Options_List(); 151 | invalida = 1; 152 | break; 153 | case 1: 154 | opt_Filter = 1 - opt_Filter; 155 | Generate_Video_Options_List(); 156 | invalida = 1; 157 | break; 158 | } 159 | } 160 | 161 | //Handle the modify boxes 162 | if ((my_state -> buttons & CONT_DPAD_LEFT) && 163 | (xkeyhit == 0)) { 164 | switch(mydata.Highlighted_Index) { 165 | case 2: 166 | if (opt_ClipVars[0] > 0) { 167 | (opt_ClipVars[0]) -= 8; 168 | Generate_Video_Options_List(); 169 | xkeyhit = 1; 170 | } 171 | break; 172 | case 3: 173 | if (opt_ClipVars[1] > 0) { 174 | (opt_ClipVars[1]) -= 8; 175 | Generate_Video_Options_List(); 176 | xkeyhit = 1; 177 | } 178 | break; 179 | case 4: 180 | if (opt_ClipVars[2] > 0) { 181 | (opt_ClipVars[2]) -= 8; 182 | Generate_Video_Options_List(); 183 | xkeyhit = 1; 184 | } 185 | break; 186 | case 5: 187 | if (opt_ClipVars[3] > 0) { 188 | (opt_ClipVars[3]) -= 8; 189 | Generate_Video_Options_List(); 190 | xkeyhit = 1; 191 | } 192 | break; 193 | } 194 | } 195 | 196 | if ((my_state -> buttons & CONT_DPAD_RIGHT) && 197 | (xkeyhit == 0)) { 198 | switch(mydata.Highlighted_Index) { 199 | case 2: 200 | if (opt_ClipVars[0] < MAX_CLIP_PIXELS) { 201 | (opt_ClipVars[0]) += 8; 202 | Generate_Video_Options_List(); 203 | xkeyhit = 1; 204 | } 205 | break; 206 | case 3: 207 | if (opt_ClipVars[1] < MAX_CLIP_PIXELS) { 208 | (opt_ClipVars[1]) += 8; 209 | Generate_Video_Options_List(); 210 | xkeyhit = 1; 211 | } 212 | break; 213 | case 4: 214 | if (opt_ClipVars[2] < MAX_CLIP_PIXELS) { 215 | (opt_ClipVars[2]) += 8; 216 | Generate_Video_Options_List(); 217 | xkeyhit = 1; 218 | } 219 | break; 220 | case 5: 221 | if (opt_ClipVars[3] < MAX_CLIP_PIXELS) { 222 | (opt_ClipVars[3]) += 8; 223 | Generate_Video_Options_List(); 224 | xkeyhit = 1; 225 | } 226 | break; 227 | } 228 | } 229 | 230 | // Handle Return to Main Menu 231 | if ((my_state -> buttons & CONT_B) && 232 | (keyhit == 0)) { 233 | setup_main_menu_screen(); 234 | menuscreen = MENUNUM_MAIN; 235 | } 236 | } -------------------------------------------------------------------------------- /GUI_VideoPage.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* GUI_VideoPage.h : GUI Page for Video Settings */ 4 | /* Interface, Variables, and Event Handling */ 5 | /* */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef GUI_VIDEOPAGE 11 | #define GUI_VIDEOPAGE 12 | 13 | #include 14 | #include "TextWindow.h" 15 | 16 | #include "GUI_MainMenu.h" 17 | 18 | //Function Definitions 19 | void setup_video_options_screen(); 20 | void Generate_Video_Options_List(); 21 | void Handle_Video_Interface(cont_state_t* my_state); 22 | 23 | //External Variables Required 24 | extern Window_Style mystyle; 25 | extern Window_Data mydata; 26 | extern Window_Style helpstyle; 27 | extern Window_Data helpdata; 28 | 29 | extern int keyhit; 30 | extern int invalida; 31 | extern int xkeyhit; 32 | extern int menuscreen; 33 | extern const int MAX_CLIP_PIXELS; 34 | extern const int title_offset_y; 35 | 36 | extern char* Main_Keys[]; 37 | extern char* Options_Keys[]; 38 | extern const int Num_Options_Keys; 39 | 40 | //Interface for Local Variables 41 | extern char Options_Video[]; 42 | extern char* Video_Options[]; 43 | extern char ClipLX_Buffer[]; 44 | extern char ClipRX_Buffer[]; 45 | extern char ClipBX_Buffer[]; 46 | extern char ClipTX_Buffer[]; 47 | 48 | extern char Options_Filter_Checked[]; 49 | extern char Options_Filter_Unchecked[]; 50 | extern char Options_Stretch_Checked[]; 51 | extern char Options_Stretch_Unchecked[]; 52 | extern char Options_Clip_Left[]; 53 | extern char Options_Clip_Right[]; 54 | extern char Options_Clip_Top[]; 55 | extern char Options_Clip_Bottom[]; 56 | extern const int Num_Video_Options; 57 | 58 | extern uint16 opt_Stretch; 59 | extern uint16 opt_Filter; 60 | extern uint8 opt_ClipVars[]; 61 | 62 | #endif -------------------------------------------------------------------------------- /K6502.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* K6502.h : NES 6502 header */ 4 | /* */ 5 | /* 1999/11/03 Racoon New preparation */ 6 | /* 2001/12/22 ReGex 0.60 Final Release */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef K6502_H_INCLUDED 11 | #define K6502_H_INCLUDED 12 | 13 | #include 14 | #include "K6502_rw.h" 15 | // Type definition 16 | 17 | /* 6502 Flags */ 18 | #define FLAG_C 0x01 19 | #define FLAG_Z 0x02 20 | #define FLAG_I 0x04 21 | #define FLAG_D 0x08 22 | #define FLAG_B 0x10 23 | #define FLAG_R 0x20 24 | #define FLAG_V 0x40 25 | #define FLAG_N 0x80 26 | 27 | /* Stack Address */ 28 | #define BASE_STACK 0x100 29 | 30 | /* Interrupt Vectors */ 31 | #define VECTOR_NMI 0xfffa 32 | #define VECTOR_RESET 0xfffc 33 | #define VECTOR_IRQ 0xfffe 34 | 35 | // NMI Request 36 | #define NMI_REQ NMI_State = 0; 37 | 38 | // IRQ Request 39 | #define IRQ_REQ IRQ_State = 0; 40 | 41 | // Emulator Operation 42 | void K6502_Init(); 43 | void K6502_Reset(); 44 | void K6502_Set_Int_Wiring( unsigned char byNMI_Wiring, unsigned char byIRQ_Wiring ); 45 | void K6502_Step( register uint16 wClocks ); 46 | void K6502_Burn(uint16 wClocks); 47 | uint32 K6502_GetCycles(); 48 | 49 | void K6502_DoNMI(); 50 | void K6502_DoIRQ(); 51 | 52 | // The state of the IRQ pin 53 | extern unsigned char IRQ_State; 54 | 55 | // The state of the NMI pin 56 | extern unsigned char NMI_State; 57 | 58 | extern unsigned char* BankTable[8]; 59 | 60 | extern unsigned char HALT; 61 | 62 | #ifdef DEBUG 63 | void EndTracing(); 64 | #endif 65 | 66 | #endif /* !K6502_H_INCLUDED */ -------------------------------------------------------------------------------- /K6502_rw.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* K6502_RW.h : 6502 Reading/Writing Operation for NES */ 4 | /* This file is included in K6502.cpp */ 5 | /* */ 6 | /* 1999/11/03 Racoon New preparation */ 7 | /* 2000/02/27 Brice Some correction. See below */ 8 | /* 2000/04/21 Racoon Add Bank Table Setting to K6502_Write() */ 9 | /*===================================================================*/ 10 | 11 | #ifndef K6502_RW_H_INCLUDED 12 | #define K6502_RW_H_INCLUDED 13 | 14 | /*-------------------------------------------------------------------*/ 15 | /* Include files */ 16 | /*-------------------------------------------------------------------*/ 17 | 18 | #include "pNesX.h" 19 | #include "pNesX_System.h" 20 | #include "K6502.h" 21 | 22 | // I/O Operation (User definition) 23 | unsigned char K6502_Read( uint16 wAddr); 24 | uint16 K6502_ReadW( uint16 wAddr ); 25 | unsigned char K6502_ReadZp( unsigned char byAddr ); 26 | uint16 K6502_ReadZpW( unsigned char byAddr ); 27 | unsigned char K6502_ReadAbsX(); 28 | unsigned char K6502_ReadAbsY(); 29 | unsigned char K6502_ReadIY(); 30 | 31 | void K6502_Write( uint16 wAddr, unsigned char byData ); 32 | void K6502_WriteW( uint16 wAddr, uint16 wData ); 33 | 34 | extern uint16 PC; 35 | extern unsigned char* pPC; 36 | extern unsigned char* pPC_Offset; 37 | extern unsigned char* BankTable[8]; 38 | extern uint16 BankMask[8]; 39 | 40 | #define REALPC pPC_Offset = BankTable[ PC >> 13 ] - ( PC & BankMask[ PC >> 13 ] ); pPC = pPC_Offset + PC; 41 | #define VIRPC PC = pPC - pPC_Offset; 42 | 43 | #endif /* !K6502_RW_H_INCLUDED */ 44 | 45 | /* REVISION 46 | 02/27/2000 47 | In K6502_Write, correction: 0x2002 is not writable ( confirmed by Marat's 48 | doc 2.2 and Yoshi's doc 2.0 ). 49 | In K6502_Read, correction: when a register is not readable the upper half 50 | address is returned ( tip from Marat ). This seems to apply to sound 51 | registers too ( the ones < 0x4016 ). This will solve your Dragon Quest 52 | problem because it will return 0x40 = 01000000b, where bit number 6 is set 53 | if bits are 76543210. In Yoshi's doc 0x4015 is readable, in Marat's doc it 54 | is not. 55 | In K6502_Read, correction: added mirroring for values in 0x2000-0x3FFF. 56 | */ 57 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # KallistiOS 2.0.0 2 | # 3 | # FrNES/Makefile 4 | # (c)2000-2022 Matt Slevinsky 5 | # 6 | 7 | KOS_ROMDISK_DIR = romdisk 8 | include $(KOS_BASE)/Makefile.rules 9 | 10 | SRCS = nes_apu.c nes_exsound.c aica_fw.c font.c input_recorder.c GUI_MainMenu.c GUI_Credits.c GUI_FileBrowser.c GUI_Help.c GUI_ControlPage.c GUI_GUIPage.c GUI_SystemPage.c GUI_VideoPage.c K6502_rw.c K6502.c pNesX_DrawLine_BG_C_Map9.c pNesX_DrawLine_BG_C.c pNesX_DrawLine_Spr_C_Map9.c pNesX_DrawLine_Spr_C.c Mapper.c Mapper_0.c Mapper_1.c Mapper_2.c Mapper_3.c Mapper_4.c Mapper_5.c Mapper_7.c Mapper_9.c Mapper_11.c Mapper_21.c Mapper_22.c Mapper_23.c Mapper_24.c Mapper_25.c Mapper_26.c Mapper_30.c Mapper_64.c Mapper_66.c Mapper_67.c Mapper_68.c Mapper_69.c Mapper_73.c Mapper_75.c Mapper_85.c Mapper_111.c Mapper_119.c pNesX_PPU_DC.c pNesX_Sound_APU.c pNesX_System_DC.c pNesX.c ROMLoad.c TextWindow.c profile.c 11 | 12 | ASMS = 13 | OBJS = $(SRCS:.c=.o) $(ASMS:.s=.o) romdisk.o 14 | PROJECTNAME = FrNES 15 | ELFFILE = $(PROJECTNAME).elf 16 | BINFILE = $(PROJECTNAME).bin 17 | 18 | #DEBUG BUILD SETTINGS 19 | DBGDIR = debug 20 | DBGEXE = $(DBGDIR)/$(ELFFILE) 21 | DBGOBJS = $(addprefix $(DBGDIR)/, $(OBJS)) 22 | DBGCFLAGS = -g -O3 -DDEBUG 23 | 24 | #RELEASE BUILD SETTINGS 25 | RELDIR = release 26 | RELEXE = $(RELDIR)/$(ELFFILE) 27 | RELBIN = $(RELDIR)/$(BINFILE) 28 | RELOBJS = $(addprefix $(RELDIR)/, $(OBJS)) 29 | 30 | #CDI BUILD SETTINGS 31 | ISODIR = iso 32 | ISOBIN = $(ISODIR)/1ST_READ.BIN 33 | CDIDIR = cdi 34 | CDIISO = $(CDIDIR)/$(PROJECTNAME).iso 35 | CDIIPBIN = $(CDIDIR)/IP.BIN 36 | CDIBOOTSTRAPISO = $(CDIDIR)/$(PROJECTNAME)-bootstrap.iso 37 | CDIFILE = $(CDIDIR)/$(PROJECTNAME).cdi 38 | 39 | .DEFAULT_GOAL := release 40 | 41 | prepdbgdir: 42 | @mkdir -p $(DBGDIR) 43 | 44 | prepreldir: 45 | @mkdir -p $(RELDIR) 46 | 47 | prepcdidir: 48 | @mkdir -p $(CDIDIR) $(ISODIR) 49 | 50 | debug: $(DBGEXE) 51 | 52 | $(DBGEXE): $(DBGOBJS) 53 | $(KOS_CC) $(KOS_CFLAGS) $(DBGCFLAGS) $(KOS_LDFLAGS) $(KOS_START) -o $(DBGEXE) $^ -lpng -lz -lm -lbz2 -lkosfat $(KOS_LIBS) 54 | 55 | $(DBGDIR)/%.o: %.c | prepdbgdir 56 | $(KOS_CC) -c $(KOS_CFLAGS) $(DBGCFLAGS) $(KOS_LDFLAGS) -o $@ $< 57 | 58 | $(DBGDIR)/%.o: %.s | prepdbgdir 59 | $(KOS_CC) -c $(KOS_CFLAGS) $(DBGCFLAGS) $(KOS_LDFLAGS) -o $@ $< 60 | 61 | $(DBGDIR)/romdisk.o: romdisk.o 62 | cp romdisk.o $(DBGDIR)/romdisk.o 63 | 64 | release: $(RELEXE) 65 | 66 | $(RELEXE): $(RELOBJS) 67 | $(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) $(KOS_START) -o $(RELEXE) $^ -lpng -lz -lm -lbz2 -lkosfat $(KOS_LIBS) 68 | $(KOS_STRIP) $(RELEXE) 69 | $(KOS_OBJCOPY) -R .stack -O binary $(RELEXE) $(RELBIN) 70 | 71 | $(RELDIR)/%.o: %.c | prepreldir 72 | $(KOS_CC) -c $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $@ $< 73 | 74 | $(RELDIR)/%.o: %.s | prepreldir 75 | $(KOS_CC) -c $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $@ $< 76 | 77 | $(RELDIR)/romdisk.o: romdisk.o 78 | cp romdisk.o $(RELDIR)/romdisk.o 79 | 80 | cdi: release | prepcdidir 81 | /opt/toolchains/dc/kos/utils/scramble/scramble $(RELBIN) $(ISOBIN) 82 | mkisofs -V $(PROJECTNAME) -l -C 0,11702 -o $(CDIISO) ./$(ISODIR) 83 | makeip ip.txt $(CDIIPBIN) 84 | ( cat $(CDIIPBIN); dd if=$(CDIISO) bs=2048 skip=16 ) > $(CDIBOOTSTRAPISO) 85 | cdi4dc $(CDIBOOTSTRAPISO) $(CDIFILE) 86 | 87 | clean: 88 | rm -rf debug release cdi iso romdisk.* 89 | 90 | -------------------------------------------------------------------------------- /Mapper.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* Mapper.h : Mapper Function */ 4 | /* */ 5 | /* 1999/11/03 Racoon New preparation */ 6 | /* 2001/12/22 maslevin 0.60 Final Release */ 7 | /* Mapper fixes + 7 + 9 initial drivers */ 8 | /* 2024/07/24 maslevin Fully rework mapper framework */ 9 | /* */ 10 | /*===================================================================*/ 11 | 12 | #ifndef _MAPPER_H 13 | #define _MAPPER_H 14 | 15 | /*-------------------------------------------------------------------*/ 16 | /* Include files */ 17 | /*-------------------------------------------------------------------*/ 18 | #include 19 | #include "pNesX.h" 20 | #include "pNesX_System_DC.h" 21 | #include "K6502.h" 22 | 23 | /*-------------------------------------------------------------------*/ 24 | /* Mapper Configuration */ 25 | /*-------------------------------------------------------------------*/ 26 | typedef struct __attribute__ ((packed, aligned(4))) Mapper_s { 27 | void (*init)(); 28 | void (*write)( uint16 wAddr, unsigned char byData ); 29 | unsigned char (*read)( uint16 wAddr ); 30 | void (*vsync)(); 31 | void (*hsync)(); 32 | } Mapper; 33 | 34 | typedef struct __attribute__ ((packed, aligned(4))) MapperTable_s { 35 | int nMapperNo; 36 | Mapper * mapper; 37 | } MapperTable; 38 | 39 | extern MapperTable Mappers[]; 40 | 41 | /*-------------------------------------------------------------------*/ 42 | /* Macros */ 43 | /*-------------------------------------------------------------------*/ 44 | 45 | /* The address of 8Kbytes unit of the ROM */ 46 | #define ROMPAGE(a) &ROM[ (a) * 0x2000 ] 47 | /* From behind the ROM, the address of 8kbytes unit */ 48 | #define ROMLASTPAGE(a) &ROM[ NesHeader.byRomSize * 0x4000 - ( (a) + 1 ) * 0x2000 ] 49 | /* The address of 1Kbytes unit of the VROM */ 50 | #define VROMPAGE(a) &VROM[ (a) * 0x400 ] 51 | 52 | #endif -------------------------------------------------------------------------------- /Mapper_0.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_0.h" 2 | 3 | /*===================================================================*/ 4 | /* */ 5 | /* Mapper 0 */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | /*-------------------------------------------------------------------*/ 10 | /* Initialize Mapper 0 */ 11 | /*-------------------------------------------------------------------*/ 12 | void Mapper_0_Init() { 13 | int nPage; 14 | 15 | /* Set ROM Banks */ 16 | if ((NesHeader.byRomSize * 2) > 3) { 17 | ROMBANK0 = ROMPAGE( 0 ); 18 | ROMBANK1 = ROMPAGE( 1 ); 19 | ROMBANK2 = ROMPAGE( 2 ); 20 | ROMBANK3 = ROMPAGE( 3 ); 21 | } else if ((NesHeader.byRomSize * 2) > 1) { 22 | ROMBANK0 = ROMPAGE( 0 ); 23 | ROMBANK1 = ROMPAGE( 1 ); 24 | ROMBANK2 = ROMPAGE( 0 ); 25 | ROMBANK3 = ROMPAGE( 1 ); 26 | } else { 27 | ROMBANK0 = ROMPAGE( 0 ); 28 | ROMBANK1 = ROMPAGE( 0 ); 29 | ROMBANK2 = ROMPAGE( 0 ); 30 | ROMBANK3 = ROMPAGE( 0 ); 31 | } 32 | 33 | /* Set PPU Banks */ 34 | // if ( NesHeader.byVRomSize > 0 ) { 35 | for ( nPage = 0; nPage < 8; ++nPage ) 36 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 37 | // } 38 | 39 | /* Set up wiring of the interrupt pin */ 40 | K6502_Set_Int_Wiring( 1, 1 ); 41 | } 42 | 43 | /*-------------------------------------------------------------------*/ 44 | /* Mapper 0 Write Function */ 45 | /*-------------------------------------------------------------------*/ 46 | unsigned char Mapper_0_Read( uint16 wAddr ) { 47 | return (wAddr >> 8); 48 | } 49 | 50 | /*-------------------------------------------------------------------*/ 51 | /* Mapper 0 Write Function */ 52 | /*-------------------------------------------------------------------*/ 53 | void Mapper_0_Write( uint16 wAddr, unsigned char byData ) 54 | { 55 | /* 56 | * Dummy Write to Mapper 57 | * 58 | */ 59 | } 60 | 61 | /*-------------------------------------------------------------------*/ 62 | /* Mapper 0 V-Sync Function */ 63 | /*-------------------------------------------------------------------*/ 64 | void Mapper_0_VSync() 65 | { 66 | /* 67 | * Dummy Callback at VSync 68 | * 69 | */ 70 | } 71 | 72 | /*-------------------------------------------------------------------*/ 73 | /* Mapper 0 H-Sync Function */ 74 | /*-------------------------------------------------------------------*/ 75 | void Mapper_0_HSync() 76 | { 77 | /* 78 | * Dummy Callback at HSync 79 | * 80 | */ 81 | } -------------------------------------------------------------------------------- /Mapper_0.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_0_H 2 | #define _MAPPER_0_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_0_Init(); 7 | unsigned char Mapper_0_Read( uint16 wAddr ); 8 | void Mapper_0_Write( uint16 wAddr, unsigned char byData ); 9 | void Mapper_0_VSync(); 10 | void Mapper_0_HSync(); 11 | 12 | #endif -------------------------------------------------------------------------------- /Mapper_1.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_1_H 2 | #define _MAPPER_1_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_1_Init(); 7 | void Mapper_1_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_11.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_11.h" 2 | 3 | void Mapper_11_Init() { 4 | ROMBANK0 = ROMPAGE( 0 ); 5 | ROMBANK1 = ROMPAGE( 1 ); 6 | ROMBANK2 = ROMPAGE( 2 ); 7 | ROMBANK3 = ROMPAGE( 3 ); 8 | 9 | /* Set PPU Banks */ 10 | for ( int nPage = 0; nPage < 8; ++nPage ) 11 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 12 | 13 | pNesX_Mirroring(MIRRORING_VERTICAL); 14 | } 15 | 16 | void Mapper_11_Write( uint16 wAddr, unsigned char byData ) { 17 | uint8 prg_bank = byData & 0x01; 18 | uint8 chr_bank = (byData & 0x70) >> 4; 19 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 20 | uint32 num_1k_VROM_banks = NesHeader.byVRomSize * 8; 21 | 22 | ROMBANK0 = ROMPAGE((prg_bank * 4) % num_8k_ROM_banks); 23 | ROMBANK1 = ROMPAGE(((prg_bank * 4) + 1) % num_8k_ROM_banks); 24 | ROMBANK2 = ROMPAGE(((prg_bank * 4) + 2) % num_8k_ROM_banks); 25 | ROMBANK3 = ROMPAGE(((prg_bank * 4) + 3) % num_8k_ROM_banks); 26 | 27 | for ( int nPage = 0; nPage < 8; ++nPage ) { 28 | PPUBANK[ nPage ] = &VROM[ (((chr_bank * 8) + nPage) % num_1k_VROM_banks) * 0x400 ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Mapper_11.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_11_H 2 | #define _MAPPER_11_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_11_Init(); 7 | void Mapper_11_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_111.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_111.h" 2 | 3 | // Mapper 111 support ported from NesterDC 4 | 5 | void set_gtrom_bank(uint8 prg) { 6 | ROMBANK0 = ROMPAGE(prg * 4); 7 | ROMBANK1 = ROMPAGE((prg * 4) + 1); 8 | ROMBANK2 = ROMPAGE((prg * 4) + 2); 9 | ROMBANK3 = ROMPAGE((prg * 4) + 3); 10 | } 11 | 12 | void Mapper_111_Init() { 13 | set_gtrom_bank(0); 14 | pNesX_Mirroring(MIRRORING_FOUR_SCREEN); 15 | } 16 | 17 | /* 18 | The register is mapped to the CPU addresses $4999-$5FFF and $7000-$7FFF 19 | 6 bit 0 20 | ---- ---- 21 | GRNC PPPP 22 | |||| |||| 23 | |||| ++++- Select 31 KB PRG ROM bank for CPU $8000-$FFFF 24 | |||+------ Select 7 KB CHR RAM bank for PPU $0000-$1FFF 25 | ||+------- Select 7 KB nametable for PPU $2000-$3EFF 26 | |+-------- Red LED - -1=On; 1=Off 27 | +--------- Green LED - -1=On; 1=Off 28 | */ 29 | void Mapper_111_Write(uint16 addr, uint8 data) { 30 | if (!( 31 | (addr >= 0x5000 && addr <= 0x5fff) || 32 | (addr >= 0x7000 && addr <= 0x7fff) 33 | )) { 34 | return; 35 | } 36 | 37 | uint8 prg = data & 0xf; 38 | uint8 chr = ((data & 0x10) >> 4) << 3; 39 | uint8 nametable = (data & 0x20) >> 5; 40 | 41 | set_gtrom_bank(prg); 42 | 43 | for (int i = 0; i < 8; i++) { 44 | PPUBANK[ i ] = &VROM[(i + chr) * 0x400]; 45 | } 46 | 47 | nametable <<= 3; 48 | PPUBANK[8] = &PPURAM[(NAME_TABLE0 + nametable) * 0x400]; 49 | PPUBANK[9] = &PPURAM[(NAME_TABLE0 + nametable + 1) * 0x400]; 50 | PPUBANK[10] = &PPURAM[(NAME_TABLE0 + nametable + 2) * 0x400]; 51 | PPUBANK[11] = &PPURAM[(NAME_TABLE0 + nametable + 3) * 0x400]; 52 | PPUBANK[12] = &PPURAM[(NAME_TABLE0 + nametable + 4) * 0x400]; 53 | PPUBANK[13] = &PPURAM[(NAME_TABLE0 + nametable + 5) * 0x400]; 54 | PPUBANK[14] = &PPURAM[(NAME_TABLE0 + nametable + 6) * 0x400]; 55 | PPUBANK[15] = &PPURAM[(NAME_TABLE0 + nametable + 7) * 0x400]; 56 | } 57 | -------------------------------------------------------------------------------- /Mapper_111.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_111_H 2 | #define _MAPPER_111_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_111_Init(); 7 | void Mapper_111_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_119.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_119.h" 2 | 3 | uint8 Mapper_119_regs[8]; 4 | 5 | uint32 Mapper_119_prg0,Mapper_119_prg1; 6 | uint32 Mapper_119_chr01,Mapper_119_chr23,Mapper_119_chr4,Mapper_119_chr5,Mapper_119_chr6,Mapper_119_chr7; 7 | 8 | bool chr_swap() { return Mapper_119_regs[0] & 0x80; } 9 | bool prg_swap() { return Mapper_119_regs[0] & 0x40; } 10 | 11 | uint8 Mapper_119_irq_enabled; // IRQs enabled 12 | uint8 Mapper_119_irq_counter; // IRQ scanline counter, decreasing 13 | uint8 Mapper_119_irq_latch; // IRQ scanline counter latch 14 | 15 | void Mapper_119_MMC3_set_CPU_banks() { 16 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 17 | if (prg_swap()) { 18 | //printf("Setting Prg Bank1 to page [%u] and Bank2 to page [%u]\n",Mapper_119_prg1,Mapper_119_prg0); 19 | ROMBANK0 = ROMLASTPAGE(1); 20 | ROMBANK1 = ROMPAGE(Mapper_119_prg1 % num_8k_ROM_banks); 21 | ROMBANK2 = ROMPAGE(Mapper_119_prg0 % num_8k_ROM_banks); 22 | ROMBANK3 = ROMLASTPAGE(0); 23 | } else { 24 | //printf("Setting Prg Bank0 to page [%u] and Bank1 to page [%u]\n",Mapper_119_prg0,Mapper_119_prg1); 25 | ROMBANK0 = ROMPAGE(Mapper_119_prg0 % num_8k_ROM_banks); 26 | ROMBANK1 = ROMPAGE(Mapper_119_prg1 % num_8k_ROM_banks); 27 | ROMBANK2 = ROMLASTPAGE(1); 28 | ROMBANK3 = ROMLASTPAGE(0); 29 | } 30 | } 31 | 32 | void Mapper_119_MMC3_set_PPU_banks() { 33 | uint8 chr_bank[8]; 34 | 35 | if (chr_swap()) { 36 | chr_bank[0] = Mapper_119_chr4; 37 | chr_bank[1] = Mapper_119_chr5; 38 | chr_bank[2] = Mapper_119_chr6; 39 | chr_bank[3] = Mapper_119_chr7; 40 | chr_bank[4] = Mapper_119_chr01+0; 41 | chr_bank[5] = Mapper_119_chr01+1; 42 | chr_bank[6] = Mapper_119_chr23+0; 43 | chr_bank[7] = Mapper_119_chr23+1; 44 | } else { 45 | chr_bank[0] = Mapper_119_chr01+0; 46 | chr_bank[1] = Mapper_119_chr01+1; 47 | chr_bank[2] = Mapper_119_chr23+0; 48 | chr_bank[3] = Mapper_119_chr23+1; 49 | chr_bank[4] = Mapper_119_chr4; 50 | chr_bank[5] = Mapper_119_chr5; 51 | chr_bank[6] = Mapper_119_chr6; 52 | chr_bank[7] = Mapper_119_chr7; 53 | } 54 | 55 | if (chr_bank[0] & 0x40) { 56 | PPUBANK[0] = &VRAM[(chr_bank[0] & 0x07) * 0x400]; 57 | } else { 58 | PPUBANK[0] = &VROM[chr_bank[0] * 0x400]; 59 | } 60 | 61 | if (chr_bank[1] & 0x40) { 62 | PPUBANK[1] = &VRAM[(chr_bank[1] & 0x07) * 0x400]; 63 | } else { 64 | PPUBANK[1] = &VROM[chr_bank[1] * 0x400]; 65 | } 66 | 67 | if (chr_bank[2] & 0x40) { 68 | PPUBANK[2] = &VRAM[(chr_bank[2] & 0x07) * 0x400]; 69 | } else { 70 | PPUBANK[2] = &VROM[chr_bank[2] * 0x400]; 71 | } 72 | 73 | if (chr_bank[3] & 0x40) { 74 | PPUBANK[3] = &VRAM[(chr_bank[3] & 0x07) * 0x400]; 75 | } else { 76 | PPUBANK[3] = &VROM[chr_bank[3] * 0x400]; 77 | } 78 | 79 | if (chr_bank[4] & 0x40) { 80 | PPUBANK[4] = &VRAM[(chr_bank[4] & 0x07) * 0x400]; 81 | } else { 82 | PPUBANK[4] = &VROM[chr_bank[4] * 0x400]; 83 | } 84 | 85 | if (chr_bank[5] & 0x40) { 86 | PPUBANK[5] = &VRAM[(chr_bank[5] & 0x07) * 0x400]; 87 | } else { 88 | PPUBANK[5] = &VROM[chr_bank[5] * 0x400]; 89 | } 90 | 91 | if (chr_bank[6] & 0x40) { 92 | PPUBANK[6] = &VRAM[(chr_bank[6] & 0x07) * 0x400]; 93 | } else { 94 | PPUBANK[6] = &VROM[chr_bank[6] * 0x400]; 95 | } 96 | 97 | if (chr_bank[7] & 0x40) { 98 | PPUBANK[7] = &VRAM[(chr_bank[7] & 0x07) * 0x400]; 99 | } else { 100 | PPUBANK[7] = &VROM[chr_bank[7] * 0x400]; 101 | } 102 | } 103 | 104 | void Mapper_119_Init() { 105 | for(int i = 0; i < 8; i++) Mapper_119_regs[i] = 0x00; 106 | 107 | // set CPU bank pointers 108 | Mapper_119_prg0 = 0; 109 | Mapper_119_prg1 = 1; 110 | Mapper_119_MMC3_set_CPU_banks(); 111 | 112 | // set VROM banks 113 | Mapper_119_chr01 = 0; 114 | Mapper_119_chr23 = 2; 115 | Mapper_119_chr4 = 4; 116 | Mapper_119_chr5 = 5; 117 | Mapper_119_chr6 = 6; 118 | Mapper_119_chr7 = 7; 119 | Mapper_119_MMC3_set_PPU_banks(); 120 | 121 | Mapper_119_irq_enabled = 0; 122 | Mapper_119_irq_counter = 0; 123 | Mapper_119_irq_latch = 0; 124 | 125 | K6502_Set_Int_Wiring( 1, 1 ); 126 | } 127 | 128 | void Mapper_119_Write(uint16 addr, uint8 data) { 129 | switch (addr & 0xE001) { 130 | case 0x8000: { 131 | Mapper_119_regs[0] = data; 132 | Mapper_119_MMC3_set_PPU_banks(); 133 | Mapper_119_MMC3_set_CPU_banks(); 134 | } break; 135 | 136 | case 0x8001: { 137 | uint32 bank_num; 138 | 139 | Mapper_119_regs[1] = data; 140 | bank_num = Mapper_119_regs[1]; 141 | 142 | switch (Mapper_119_regs[0] & 0x07) { 143 | case 0x00: { 144 | if (NesHeader.byRomSize > 0) { 145 | bank_num &= 0xfe; 146 | Mapper_119_chr01 = bank_num; 147 | Mapper_119_MMC3_set_PPU_banks(); 148 | } 149 | } break; 150 | 151 | case 0x01: { 152 | if (NesHeader.byRomSize > 0) { 153 | bank_num &= 0xfe; 154 | Mapper_119_chr23 = bank_num; 155 | Mapper_119_MMC3_set_PPU_banks(); 156 | } 157 | } break; 158 | 159 | case 0x02: { 160 | if (NesHeader.byRomSize > 0) { 161 | Mapper_119_chr4 = bank_num; 162 | Mapper_119_MMC3_set_PPU_banks(); 163 | } 164 | } break; 165 | 166 | case 0x03: { 167 | if (NesHeader.byRomSize > 0) { 168 | Mapper_119_chr5 = bank_num; 169 | Mapper_119_MMC3_set_PPU_banks(); 170 | } 171 | } break; 172 | 173 | case 0x04: { 174 | if (NesHeader.byRomSize > 0) { 175 | Mapper_119_chr6 = bank_num; 176 | Mapper_119_MMC3_set_PPU_banks(); 177 | } 178 | } break; 179 | 180 | case 0x05: { 181 | if (NesHeader.byRomSize > 0) { 182 | Mapper_119_chr7 = bank_num; 183 | Mapper_119_MMC3_set_PPU_banks(); 184 | } 185 | } break; 186 | 187 | case 0x06: { 188 | Mapper_119_prg0 = bank_num; 189 | Mapper_119_MMC3_set_CPU_banks(); 190 | } break; 191 | 192 | case 0x07: { 193 | Mapper_119_prg1 = bank_num; 194 | Mapper_119_MMC3_set_CPU_banks(); 195 | } break; 196 | } 197 | } break; 198 | 199 | case 0xA000: { 200 | Mapper_119_regs[2] = data; 201 | 202 | if (ROM_Mirroring != MIRRORING_FOUR_SCREEN) { 203 | if (data & 0x01) { 204 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 205 | } else { 206 | pNesX_Mirroring(MIRRORING_VERTICAL); 207 | } 208 | } 209 | } break; 210 | 211 | case 0xA001: { 212 | Mapper_119_regs[3] = data; 213 | } break; 214 | 215 | case 0xC000: { 216 | Mapper_119_regs[4] = data; 217 | Mapper_119_irq_counter = Mapper_119_regs[4]; 218 | } break; 219 | 220 | case 0xC001: { 221 | Mapper_119_regs[5] = data; 222 | Mapper_119_irq_latch = Mapper_119_regs[5]; 223 | } break; 224 | 225 | case 0xE000: { 226 | Mapper_119_regs[6] = data; 227 | Mapper_119_irq_enabled = 0; 228 | } break; 229 | 230 | case 0xE001: { 231 | Mapper_119_regs[7] = data; 232 | Mapper_119_irq_enabled = 1; 233 | } break; 234 | } 235 | } 236 | 237 | void Mapper_119_HSync() { 238 | if (Mapper_119_irq_enabled) { 239 | if ((ppuinfo.PPU_Scanline >= 0) && (ppuinfo.PPU_Scanline <= 239)) { 240 | if (PPU_R1 & (R1_SHOW_SCR | R1_SHOW_SP )) { 241 | if (Mapper_119_irq_counter == 0) { 242 | Mapper_119_irq_counter = Mapper_119_irq_latch; 243 | IRQ_REQ; 244 | } 245 | Mapper_119_irq_counter--; 246 | } 247 | } 248 | } 249 | } -------------------------------------------------------------------------------- /Mapper_119.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_119_H 2 | #define _MAPPER_119_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_119_Init(); 7 | void Mapper_119_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_119_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_2.c: -------------------------------------------------------------------------------- 1 | #include "Mapper.h" 2 | #include "Mapper_2.h" 3 | 4 | /*===================================================================*/ 5 | /* */ 6 | /* Mapper 2 (UNROM) */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | /*-------------------------------------------------------------------*/ 11 | /* Initialize Mapper 2 */ 12 | /*-------------------------------------------------------------------*/ 13 | void Mapper_2_Init() { 14 | /* Set ROM Banks */ 15 | ROMBANK0 = ROMPAGE( 0 ); 16 | ROMBANK1 = ROMPAGE( 1 ); 17 | ROMBANK2 = ROMLASTPAGE( 1 ); 18 | ROMBANK3 = ROMLASTPAGE( 0 ); 19 | 20 | /* Set up wiring of the interrupt pin */ 21 | K6502_Set_Int_Wiring( 1, 1 ); 22 | } 23 | 24 | /*-------------------------------------------------------------------*/ 25 | /* Mapper 2 Write Function */ 26 | /*-------------------------------------------------------------------*/ 27 | void Mapper_2_Write( uint16 wAddr, unsigned char byData ) { 28 | if (wAddr & 0x8000) { 29 | /* Set ROM Banks */ 30 | byData %= NesHeader.byRomSize; 31 | byData <<= 1; 32 | // printf("Write [$%04X]: Setting ROMBANK0 to [%u] and ROMBANK1 to [%u]\n", wAddr, byData, byData + 1); 33 | 34 | ROMBANK0 = ROMPAGE( byData ); 35 | ROMBANK1 = ROMPAGE( byData + 1 ); 36 | } 37 | } -------------------------------------------------------------------------------- /Mapper_2.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_2_H 2 | #define _MAPPER_2_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_2_Init(); 7 | void Mapper_2_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_21.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_21.h" 2 | 3 | uint8 Mapper_21_regs[9]; 4 | uint8 Mapper_21_irq_enabled; 5 | uint8 Mapper_21_irq_counter; 6 | uint8 Mapper_21_irq_latch; 7 | 8 | void Mapper_21_Init() { 9 | ROMBANK0 = ROMPAGE(0); 10 | ROMBANK1 = ROMPAGE(1); 11 | ROMBANK2 = ROMLASTPAGE(1); 12 | ROMBANK3 = ROMLASTPAGE(0); 13 | 14 | Mapper_21_regs[0] = 0; 15 | Mapper_21_regs[1] = 1; 16 | Mapper_21_regs[2] = 2; 17 | Mapper_21_regs[3] = 3; 18 | Mapper_21_regs[4] = 4; 19 | Mapper_21_regs[5] = 5; 20 | Mapper_21_regs[6] = 6; 21 | Mapper_21_regs[7] = 7; 22 | Mapper_21_regs[8] = 0; 23 | 24 | Mapper_21_irq_enabled = 0; 25 | Mapper_21_irq_counter = 0; 26 | Mapper_21_irq_latch = 0; 27 | } 28 | 29 | void Mapper_21_Write(uint16 addr, uint8 data) { 30 | switch (addr & 0xF0CF) { 31 | case 0x8000: { 32 | if (Mapper_21_regs[8] & 0x02) { 33 | ROMBANK2 = ROMPAGE(data); 34 | } else { 35 | ROMBANK0 = ROMPAGE(data); 36 | } 37 | } break; 38 | 39 | case 0xA000: { 40 | ROMBANK1 = ROMPAGE(data); 41 | } break; 42 | 43 | case 0x9000: { 44 | data &= 0x03; 45 | if (data == 0) { 46 | pNesX_Mirroring(MIRRORING_VERTICAL); 47 | } else if(data == 1) { 48 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 49 | } else if(data == 2) { 50 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 51 | } else { 52 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 53 | } 54 | } break; 55 | 56 | case 0x9002: 57 | case 0x9080: { 58 | Mapper_21_regs[8] = data; 59 | } break; 60 | 61 | case 0xB000: { 62 | Mapper_21_regs[0] = (Mapper_21_regs[0] & 0xF0) | (data & 0x0F); 63 | PPUBANK[0] = &VROM[Mapper_21_regs[0] * 0x400]; 64 | } break; 65 | 66 | case 0xB002: 67 | case 0xB040: { 68 | Mapper_21_regs[0] = (Mapper_21_regs[0] & 0x0F) | ((data & 0x0F) << 4); 69 | PPUBANK[0] = &VROM[Mapper_21_regs[0] * 0x400]; 70 | } break; 71 | 72 | case 0xB001: 73 | case 0xB004: 74 | case 0xB080: { 75 | Mapper_21_regs[1] = (Mapper_21_regs[1] & 0xF0) | (data & 0x0F); 76 | PPUBANK[1] = &VROM[Mapper_21_regs[1] * 0x400]; 77 | } break; 78 | 79 | case 0xB003: 80 | case 0xB006: 81 | case 0xB0C0: { 82 | Mapper_21_regs[1] = (Mapper_21_regs[1] & 0x0F) | ((data & 0x0F) << 4); 83 | PPUBANK[1] = &VROM[Mapper_21_regs[1] * 0x400]; 84 | } break; 85 | 86 | case 0xC000: { 87 | Mapper_21_regs[2] = (Mapper_21_regs[2] & 0xF0) | (data & 0x0F); 88 | PPUBANK[2] = &VROM[Mapper_21_regs[2] * 0x400]; 89 | } break; 90 | 91 | case 0xC002: 92 | case 0xC040: { 93 | Mapper_21_regs[2] = (Mapper_21_regs[2] & 0x0F) | ((data & 0x0F) << 4); 94 | PPUBANK[2] = &VROM[Mapper_21_regs[2] * 0x400]; 95 | } break; 96 | 97 | case 0xC001: 98 | case 0xC004: 99 | case 0xC080: { 100 | Mapper_21_regs[3] = (Mapper_21_regs[3] & 0xF0) | (data & 0x0F); 101 | PPUBANK[3] = &VROM[Mapper_21_regs[3] * 0x400]; 102 | } break; 103 | 104 | case 0xC003: 105 | case 0xC006: 106 | case 0xC0C0: { 107 | Mapper_21_regs[3] = (Mapper_21_regs[3] & 0x0F) | ((data & 0x0F) << 4); 108 | PPUBANK[3] = &VROM[Mapper_21_regs[3] * 0x400]; 109 | } break; 110 | 111 | case 0xD000: { 112 | Mapper_21_regs[4] = (Mapper_21_regs[4] & 0xF0) | (data & 0x0F); 113 | PPUBANK[4] = &VROM[Mapper_21_regs[4] * 0x400]; 114 | } break; 115 | 116 | case 0xD002: 117 | case 0xD040: { 118 | Mapper_21_regs[4] = (Mapper_21_regs[4] & 0x0F) | ((data & 0x0F) << 4); 119 | PPUBANK[4] = &VROM[Mapper_21_regs[4] * 0x400]; 120 | } break; 121 | 122 | case 0xD001: 123 | case 0xD004: 124 | case 0xD080: { 125 | Mapper_21_regs[5] = (Mapper_21_regs[5] & 0xF0) | (data & 0x0F); 126 | PPUBANK[5] = &VROM[Mapper_21_regs[5] * 0x400]; 127 | } break; 128 | 129 | case 0xD003: 130 | case 0xD006: 131 | case 0xD0C0: { 132 | Mapper_21_regs[5] = (Mapper_21_regs[5] & 0x0F) | ((data & 0x0F) << 4); 133 | PPUBANK[5] = &VROM[Mapper_21_regs[5] * 0x400]; 134 | } break; 135 | 136 | case 0xE000: { 137 | Mapper_21_regs[6] = (Mapper_21_regs[6] & 0xF0) | (data & 0x0F); 138 | PPUBANK[6] = &VROM[Mapper_21_regs[6] * 0x400]; 139 | } break; 140 | 141 | case 0xE002: 142 | case 0xE040: { 143 | Mapper_21_regs[6] = (Mapper_21_regs[6] & 0x0F) | ((data & 0x0F) << 4); 144 | PPUBANK[6] = &VROM[Mapper_21_regs[6] * 0x400]; 145 | } break; 146 | 147 | case 0xE001: 148 | case 0xE004: 149 | case 0xE080: { 150 | Mapper_21_regs[7] = (Mapper_21_regs[7] & 0xF0) | (data & 0x0F); 151 | PPUBANK[7] = &VROM[Mapper_21_regs[7] * 0x400]; 152 | } break; 153 | 154 | case 0xE003: 155 | case 0xE006: 156 | case 0xE0C0: { 157 | Mapper_21_regs[7] = (Mapper_21_regs[7] & 0x0F) | ((data & 0x0F) << 4); 158 | PPUBANK[7] = &VROM[Mapper_21_regs[7] * 0x400]; 159 | } break; 160 | 161 | case 0xF000: { 162 | Mapper_21_irq_latch = (Mapper_21_irq_latch & 0xF0) | (data & 0x0F); 163 | } break; 164 | 165 | case 0xF002: 166 | case 0xF040: { 167 | Mapper_21_irq_latch = (Mapper_21_irq_latch & 0x0F) | ((data & 0x0F) << 4); 168 | } break; 169 | 170 | case 0xF003: 171 | case 0xF0C0: { 172 | Mapper_21_irq_enabled = (Mapper_21_irq_enabled & 0x01) * 3; 173 | } break; 174 | 175 | case 0xF004: 176 | case 0xF080: { 177 | Mapper_21_irq_enabled = data & 0x03; 178 | if (Mapper_21_irq_enabled & 0x02) { 179 | Mapper_21_irq_counter = Mapper_21_irq_latch; 180 | } 181 | } break; 182 | } 183 | } 184 | 185 | void Mapper_21_HSync() { 186 | if (Mapper_21_irq_enabled & 0x02) { 187 | if (Mapper_21_irq_counter == 0xFF) { 188 | Mapper_21_irq_counter = Mapper_21_irq_latch; 189 | Mapper_21_irq_enabled = (Mapper_21_irq_enabled & 0x01) * 3; 190 | IRQ_REQ; 191 | } else { 192 | Mapper_21_irq_counter++; 193 | } 194 | } 195 | } -------------------------------------------------------------------------------- /Mapper_21.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_21_H 2 | #define _MAPPER_21_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_21_Init(); 7 | void Mapper_21_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_21_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_22.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_22.h" 2 | 3 | void Mapper_22_Init() { 4 | ROMBANK0 = ROMPAGE(0); 5 | ROMBANK1 = ROMPAGE(1); 6 | ROMBANK2 = ROMLASTPAGE(1); 7 | ROMBANK3 = ROMLASTPAGE(0); 8 | 9 | for ( int nPage = 0; nPage < 8; ++nPage ) 10 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 11 | } 12 | 13 | void Mapper_22_Write(uint16 addr, uint8 data) { 14 | switch (addr) { 15 | case 0x8000: { 16 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 17 | ROMBANK0 = ROMPAGE(data % num_8k_ROM_banks); 18 | } break; 19 | 20 | case 0x9000: { 21 | data &= 0x03; 22 | if (data == 0) { 23 | pNesX_Mirroring(MIRRORING_VERTICAL); 24 | } else if(data == 1) { 25 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 26 | } else if(data == 2) { 27 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 28 | } else { 29 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 30 | } 31 | } break; 32 | 33 | case 0xA000: { 34 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 35 | ROMBANK1 = ROMPAGE(data % num_8k_ROM_banks); 36 | } break; 37 | 38 | case 0xB000: { 39 | PPUBANK[0] = &VROM[(data >> 1) * 0x400]; 40 | } break; 41 | 42 | case 0xB001: { 43 | PPUBANK[1] = &VROM[(data >> 1) * 0x400]; 44 | } break; 45 | 46 | case 0xC000: { 47 | PPUBANK[2] = &VROM[(data >> 1) * 0x400]; 48 | } break; 49 | 50 | case 0xC001: { 51 | PPUBANK[3] = &VROM[(data >> 1) * 0x400]; 52 | } break; 53 | 54 | case 0xD000: { 55 | PPUBANK[4] = &VROM[(data >> 1) * 0x400]; 56 | } break; 57 | 58 | case 0xD001: { 59 | PPUBANK[5] = &VROM[(data >> 1) * 0x400]; 60 | } break; 61 | 62 | case 0xE000: { 63 | PPUBANK[6] = &VROM[(data >> 1) * 0x400]; 64 | } break; 65 | 66 | case 0xE001: { 67 | PPUBANK[7] = &VROM[(data >> 1) * 0x400]; 68 | } break; 69 | } 70 | } -------------------------------------------------------------------------------- /Mapper_22.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_22_H 2 | #define _MAPPER_22_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_22_Init(); 7 | void Mapper_22_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_23.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_23.h" 2 | 3 | extern uint32 currentCRC32; 4 | 5 | uint16 Mapper_23_patch; 6 | uint8 Mapper_23_regs[9]; 7 | uint8 Mapper_23_irq_enabled; 8 | uint8 Mapper_23_irq_counter; 9 | uint8 Mapper_23_irq_latch; 10 | 11 | void Mapper_23_Init() { 12 | 13 | // Akumajou Special - Boku Dracula Kun 14 | // ... need to look up the translation of this as well 15 | if ((currentCRC32 == 0x93794634) || 16 | (currentCRC32 == 0xc1fbf659)) { 17 | Mapper_23_patch = 0xF00C; 18 | } else { 19 | Mapper_23_patch = 0xFFFF; 20 | } 21 | 22 | ROMBANK0 = ROMPAGE(0); 23 | ROMBANK1 = ROMPAGE(1); 24 | ROMBANK2 = ROMLASTPAGE(1); 25 | ROMBANK3 = ROMLASTPAGE(0); 26 | 27 | Mapper_23_regs[0] = 0; 28 | Mapper_23_regs[1] = 1; 29 | Mapper_23_regs[2] = 2; 30 | Mapper_23_regs[3] = 3; 31 | Mapper_23_regs[4] = 4; 32 | Mapper_23_regs[5] = 5; 33 | Mapper_23_regs[6] = 6; 34 | Mapper_23_regs[7] = 7; 35 | Mapper_23_regs[8] = 0; 36 | 37 | Mapper_23_irq_enabled = 0; 38 | Mapper_23_irq_counter = 0; 39 | Mapper_23_irq_latch = 0; 40 | } 41 | 42 | void Mapper_23_Write(uint16 addr, uint8 data) { 43 | switch (addr & Mapper_23_patch) { 44 | case 0x8000: 45 | case 0x8004: 46 | case 0x8008: 47 | case 0x800C: { 48 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 49 | if (Mapper_23_regs[8]) { 50 | ROMBANK2 = ROMPAGE(data % num_8k_ROM_banks); 51 | } else { 52 | ROMBANK0 = ROMPAGE(data % num_8k_ROM_banks); 53 | } 54 | } break; 55 | 56 | case 0x9000: { 57 | if (data != 0xFF) { 58 | data &= 0x03; 59 | if (data == 0) { 60 | pNesX_Mirroring(MIRRORING_VERTICAL); 61 | } else if(data == 1) { 62 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 63 | } else if(data == 2) { 64 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 65 | } else { 66 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 67 | } 68 | } 69 | } break; 70 | 71 | case 0x9008: { 72 | Mapper_23_regs[8] = data & 0x02; 73 | } break; 74 | 75 | case 0xA000: 76 | case 0xA004: 77 | case 0xA008: 78 | case 0xA00C: { 79 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 80 | ROMBANK1 = ROMPAGE(data % num_8k_ROM_banks); 81 | } break; 82 | 83 | case 0xB000: { 84 | Mapper_23_regs[0] = (Mapper_23_regs[0] & 0xF0) | (data & 0x0F); 85 | PPUBANK[0] = &VROM[Mapper_23_regs[0] * 0x400]; 86 | } break; 87 | 88 | case 0xB001: 89 | case 0xB004: { 90 | Mapper_23_regs[0] = (Mapper_23_regs[0] & 0x0F) | ((data & 0x0F) << 4); 91 | PPUBANK[0] = &VROM[Mapper_23_regs[0] * 0x400]; 92 | } break; 93 | 94 | case 0xB002: 95 | case 0xB008: { 96 | Mapper_23_regs[1] = (Mapper_23_regs[1] & 0xF0) | (data & 0x0F); 97 | PPUBANK[1] = &VROM[Mapper_23_regs[1] * 0x400]; 98 | } break; 99 | 100 | case 0xB003: 101 | case 0xB00C: { 102 | Mapper_23_regs[1] = (Mapper_23_regs[1] & 0x0F) | ((data & 0x0F) << 4); 103 | PPUBANK[1] = &VROM[Mapper_23_regs[1] * 0x400]; 104 | } break; 105 | 106 | case 0xC000: { 107 | Mapper_23_regs[2] = (Mapper_23_regs[2] & 0xF0) | (data & 0x0F); 108 | PPUBANK[2] = &VROM[Mapper_23_regs[2] * 0x400]; 109 | } break; 110 | 111 | case 0xC001: 112 | case 0xC004: { 113 | Mapper_23_regs[2] = (Mapper_23_regs[2] & 0x0F) | ((data & 0x0F) << 4); 114 | PPUBANK[2] = &VROM[Mapper_23_regs[2] * 0x400]; 115 | } break; 116 | 117 | case 0xC002: 118 | case 0xC008: { 119 | Mapper_23_regs[3] = (Mapper_23_regs[3] & 0xF0) | (data & 0x0F); 120 | PPUBANK[3] = &VROM[Mapper_23_regs[3] * 0x400]; 121 | } break; 122 | 123 | case 0xC003: 124 | case 0xC00C: { 125 | Mapper_23_regs[3] = (Mapper_23_regs[3] & 0x0F) | ((data & 0x0F) << 4); 126 | PPUBANK[3] = &VROM[Mapper_23_regs[3] * 0x400]; 127 | } break; 128 | 129 | case 0xD000: { 130 | Mapper_23_regs[4] = (Mapper_23_regs[4] & 0xF0) | (data & 0x0F); 131 | PPUBANK[4] = &VROM[Mapper_23_regs[4] * 0x400]; 132 | } break; 133 | 134 | case 0xD001: 135 | case 0xD004: { 136 | Mapper_23_regs[4] = (Mapper_23_regs[4] & 0x0F) | ((data & 0x0F) << 4); 137 | PPUBANK[4] = &VROM[Mapper_23_regs[4] * 0x400]; 138 | } break; 139 | 140 | case 0xD002: 141 | case 0xD008: { 142 | Mapper_23_regs[5] = (Mapper_23_regs[5] & 0xF0) | (data & 0x0F); 143 | PPUBANK[5] = &VROM[Mapper_23_regs[5] * 0x400]; 144 | } break; 145 | 146 | case 0xD003: 147 | case 0xD00C: { 148 | Mapper_23_regs[5] = (Mapper_23_regs[5] & 0x0F) | ((data & 0x0F) << 4); 149 | PPUBANK[5] = &VROM[Mapper_23_regs[5] * 0x400]; 150 | } break; 151 | 152 | case 0xE000: { 153 | Mapper_23_regs[6] = (Mapper_23_regs[6] & 0xF0) | (data & 0x0F); 154 | PPUBANK[6] = &VROM[Mapper_23_regs[6] * 0x400]; 155 | } break; 156 | 157 | case 0xE001: 158 | case 0xE004: { 159 | Mapper_23_regs[6] = (Mapper_23_regs[6] & 0x0F) | ((data & 0x0F) << 4); 160 | PPUBANK[6] = &VROM[Mapper_23_regs[6] * 0x400]; 161 | } break; 162 | 163 | case 0xE002: 164 | case 0xE008: { 165 | Mapper_23_regs[7] = (Mapper_23_regs[7] & 0xF0) | (data & 0x0F); 166 | PPUBANK[7] = &VROM[Mapper_23_regs[7] * 0x400]; 167 | } break; 168 | 169 | case 0xE003: 170 | case 0xE00C: { 171 | Mapper_23_regs[7] = (Mapper_23_regs[7] & 0x0F) | ((data & 0x0F) << 4); 172 | PPUBANK[7] = &VROM[Mapper_23_regs[7] * 0x400]; 173 | } break; 174 | 175 | case 0xF000: { 176 | Mapper_23_irq_latch = (Mapper_23_irq_latch & 0xF0) | (data & 0x0F); 177 | } break; 178 | 179 | case 0xF004: { 180 | Mapper_23_irq_latch = (Mapper_23_irq_latch & 0x0F) | ((data & 0x0F) << 4); 181 | } break; 182 | 183 | case 0xF008: { 184 | Mapper_23_irq_enabled = data & 0x03; 185 | if (Mapper_23_irq_enabled & 0x02) { 186 | Mapper_23_irq_counter = Mapper_23_irq_latch; 187 | } 188 | } break; 189 | 190 | case 0xF00C: { 191 | Mapper_23_irq_enabled = (Mapper_23_irq_enabled & 0x01) * 3; 192 | } break; 193 | } 194 | } 195 | 196 | void Mapper_23_HSync() { 197 | if (Mapper_23_irq_enabled & 0x02) { 198 | if (Mapper_23_irq_counter == 0xFF) { 199 | Mapper_23_irq_counter = Mapper_23_irq_latch; 200 | Mapper_23_irq_enabled = (Mapper_23_irq_enabled & 0x01) * 3; 201 | IRQ_REQ; 202 | } else { 203 | Mapper_23_irq_counter++; 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /Mapper_23.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_23_H 2 | #define _MAPPER_23_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_23_Init(); 7 | void Mapper_23_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_23_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_24.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_24.h" 2 | 3 | #include "nes_apu.h" 4 | 5 | unsigned char Mapper_24_irq_enabled_l; 6 | unsigned char Mapper_24_irq_enabled_h; 7 | unsigned char Mapper_24_irq_counter; 8 | unsigned char Mapper_24_irq_latch; 9 | 10 | void Mapper_24_Init() { 11 | apu_set_exsound(NES_APU_EXSOUND_VRC6); 12 | 13 | // set CPU bank pointers 14 | ROMBANK0 = ROMPAGE(0); 15 | ROMBANK1 = ROMPAGE(1); 16 | ROMBANK2 = ROMLASTPAGE(1); 17 | ROMBANK3 = ROMLASTPAGE(0); 18 | 19 | if ( NesHeader.byVRomSize > 0 ) { 20 | for ( int nPage = 0; nPage < 8; ++nPage ) 21 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 22 | } 23 | 24 | Mapper_24_irq_enabled_l = 0; 25 | Mapper_24_irq_enabled_h = 0; 26 | Mapper_24_irq_counter = 0; 27 | Mapper_24_irq_latch = 0; 28 | } 29 | 30 | void Mapper_24_Write(uint16 addr, unsigned char data) { 31 | switch(addr) { 32 | case 0x8000: { 33 | ROMBANK0 = ROMPAGE(data << 1); 34 | ROMBANK1 = ROMPAGE((data << 1) + 1); 35 | } break; 36 | 37 | case 0xB003: { 38 | data &= 0x0C; 39 | if(data == 0x00) { 40 | pNesX_Mirroring(MIRRORING_VERTICAL); 41 | } else if(data == 0x04) { 42 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 43 | } else if(data == 0x08) { 44 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 45 | } else if(data == 0x0C) { 46 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 47 | } 48 | } break; 49 | 50 | case 0xC000: { 51 | ROMBANK2 = ROMPAGE(data); 52 | } break; 53 | 54 | case 0xD000 ... 0xD003: { 55 | PPUBANK[(addr & 0xf003) - 0xd000] = VROMPAGE(data); 56 | } break; 57 | 58 | case 0xE000 ... 0xE003: { 59 | PPUBANK[(addr & 0xf003) - 0xe000 + 4] = VROMPAGE(data); 60 | } break; 61 | 62 | case 0xF000: { 63 | Mapper_24_irq_latch = data; 64 | } break; 65 | 66 | case 0xF001: { 67 | Mapper_24_irq_enabled_l = data & 0x1; 68 | Mapper_24_irq_enabled_h = data & 0x2; 69 | if (Mapper_24_irq_enabled_h) { 70 | Mapper_24_irq_counter = Mapper_24_irq_latch; 71 | } 72 | } break; 73 | 74 | case 0xF002: { 75 | Mapper_24_irq_enabled_h = Mapper_24_irq_enabled_l; 76 | } break; 77 | } 78 | 79 | ex_write(addr, data); 80 | } 81 | 82 | void Mapper_24_HSync() { 83 | if (Mapper_24_irq_enabled_h) { 84 | if (Mapper_24_irq_counter == 0xff) { 85 | IRQ_REQ; 86 | Mapper_24_irq_counter = Mapper_24_irq_latch; 87 | } else { 88 | Mapper_24_irq_counter++; 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Mapper_24.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_24_H 2 | #define _MAPPER_24_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_24_Init(); 7 | void Mapper_24_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_24_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_25.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_25.h" 2 | 3 | extern uint32 currentCRC32; 4 | 5 | uint8 Mapper_25_patch; 6 | uint8 Mapper_25_regs[11]; 7 | uint8 Mapper_25_irq_enabled; 8 | uint8 Mapper_25_irq_counter; 9 | uint8 Mapper_25_irq_latch; 10 | 11 | void Mapper_25_Init() { 12 | ROMBANK0 = ROMPAGE(0); 13 | ROMBANK1 = ROMPAGE(1); 14 | ROMBANK2 = ROMLASTPAGE(1); 15 | ROMBANK3 = ROMLASTPAGE(0); 16 | 17 | if (NesHeader.byVRomSize > 0) { 18 | for ( int nPage = 0; nPage < 8; ++nPage ) 19 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 20 | } 21 | 22 | for(int i = 0; i < 8; i++) 23 | Mapper_25_regs[i] = 0; 24 | 25 | Mapper_25_regs[8] = 0; 26 | Mapper_25_regs[9] = (NesHeader.byRomSize * 2) - 2; 27 | Mapper_25_regs[10] = 0; 28 | 29 | Mapper_25_irq_enabled = 0; 30 | Mapper_25_irq_counter = 0; 31 | Mapper_25_irq_latch = 0; 32 | } 33 | 34 | void Mapper_25_Write(uint16 addr, uint8 data) { 35 | switch (addr & 0xF000) { 36 | case 0x8000: { 37 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 38 | if (Mapper_25_regs[10] & 0x02) { 39 | Mapper_25_regs[9] = data; 40 | ROMBANK2 = ROMPAGE(data % num_8k_ROM_banks); 41 | } else { 42 | Mapper_25_regs[8] = data; 43 | ROMBANK0 = ROMPAGE(data % num_8k_ROM_banks); 44 | } 45 | } break; 46 | 47 | case 0xA000: { 48 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 49 | ROMBANK1 = ROMPAGE(data % num_8k_ROM_banks); 50 | } break; 51 | } 52 | 53 | switch (addr & 0xF00F) { 54 | case 0x9000: { 55 | data &= 0x03; 56 | if (data == 0) { 57 | pNesX_Mirroring(MIRRORING_VERTICAL); 58 | } else if(data == 1) { 59 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 60 | } else if(data == 2) { 61 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 62 | } else { 63 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 64 | } 65 | } break; 66 | 67 | case 0x9001: 68 | case 0x9004: { 69 | if ((Mapper_25_regs[10] & 0x02) != (data & 0x02)) { 70 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 71 | uint8 swap = Mapper_25_regs[8]; 72 | Mapper_25_regs[8] = Mapper_25_regs[9]; 73 | Mapper_25_regs[9] = swap; 74 | ROMBANK0 = ROMPAGE(Mapper_25_regs[8] % num_8k_ROM_banks); 75 | ROMBANK2 = ROMPAGE(Mapper_25_regs[9] % num_8k_ROM_banks); 76 | } 77 | Mapper_25_regs[10] = data; 78 | } 79 | break; 80 | 81 | case 0xB000: { 82 | Mapper_25_regs[0] = (Mapper_25_regs[0] & 0xF0) | (data & 0x0F); 83 | PPUBANK[0] = &VROM[Mapper_25_regs[0] * 0x400]; 84 | } break; 85 | 86 | case 0xB001: 87 | case 0xB004: { 88 | Mapper_25_regs[1] = (Mapper_25_regs[1] & 0xF0) | (data & 0x0F); 89 | PPUBANK[1] = &VROM[Mapper_25_regs[1] * 0x400]; 90 | } break; 91 | 92 | case 0xB002: 93 | case 0xB008: { 94 | Mapper_25_regs[0] = (Mapper_25_regs[0] & 0x0F) | ((data & 0x0F) << 4); 95 | PPUBANK[0] = &VROM[Mapper_25_regs[0] * 0x400]; 96 | } break; 97 | 98 | case 0xB003: 99 | case 0xB00C: { 100 | Mapper_25_regs[1] = (Mapper_25_regs[1] & 0x0F) | ((data & 0x0F) << 4); 101 | PPUBANK[1] = &VROM[Mapper_25_regs[1] * 0x400]; 102 | } break; 103 | 104 | case 0xC000: { 105 | Mapper_25_regs[2] = (Mapper_25_regs[2] & 0xF0) | (data & 0x0F); 106 | PPUBANK[2] = &VROM[Mapper_25_regs[2] * 0x400]; 107 | } break; 108 | 109 | case 0xC001: 110 | case 0xC004: { 111 | Mapper_25_regs[3] = (Mapper_25_regs[3] & 0xF0) | (data & 0x0F); 112 | PPUBANK[3] = &VROM[Mapper_25_regs[3] * 0x400]; 113 | } break; 114 | 115 | case 0xC002: 116 | case 0xC008: { 117 | Mapper_25_regs[2] = (Mapper_25_regs[2] & 0x0F) | ((data & 0x0F) << 4); 118 | PPUBANK[2] = &VROM[Mapper_25_regs[2] * 0x400]; 119 | } break; 120 | 121 | case 0xC003: 122 | case 0xC00C: { 123 | Mapper_25_regs[3] = (Mapper_25_regs[3] & 0x0F) | ((data & 0x0F) << 4); 124 | PPUBANK[3] = &VROM[Mapper_25_regs[3] * 0x400]; 125 | } break; 126 | 127 | case 0xD000: { 128 | Mapper_25_regs[4] = (Mapper_25_regs[4] & 0xF0) | (data & 0x0F); 129 | PPUBANK[4] = &VROM[Mapper_25_regs[4] * 0x400]; 130 | } break; 131 | 132 | case 0xD001: 133 | case 0xD004: { 134 | Mapper_25_regs[5] = (Mapper_25_regs[5] & 0xF0) | (data & 0x0F); 135 | PPUBANK[5] = &VROM[Mapper_25_regs[5] * 0x400]; 136 | } break; 137 | 138 | case 0xD002: 139 | case 0xD008: { 140 | Mapper_25_regs[4] = (Mapper_25_regs[4] & 0x0F) | ((data & 0x0F) << 4); 141 | PPUBANK[4] = &VROM[Mapper_25_regs[4] * 0x400]; 142 | } break; 143 | 144 | case 0xD003: 145 | case 0xD00C: { 146 | Mapper_25_regs[5] = (Mapper_25_regs[5] & 0x0F) | ((data & 0x0F) << 4); 147 | PPUBANK[5] = &VROM[Mapper_25_regs[5] * 0x400]; 148 | } break; 149 | 150 | case 0xE000: { 151 | Mapper_25_regs[6] = (Mapper_25_regs[6] & 0xF0) | (data & 0x0F); 152 | PPUBANK[6] = &VROM[Mapper_25_regs[6] * 0x400]; 153 | } break; 154 | 155 | case 0xE001: 156 | case 0xE004: { 157 | Mapper_25_regs[7] = (Mapper_25_regs[7] & 0xF0) | (data & 0x0F); 158 | PPUBANK[7] = &VROM[Mapper_25_regs[7] * 0x400]; 159 | } break; 160 | 161 | case 0xE002: 162 | case 0xE008: { 163 | Mapper_25_regs[6] = (Mapper_25_regs[6] & 0x0F) | ((data & 0x0F) << 4); 164 | PPUBANK[6] = &VROM[Mapper_25_regs[6] * 0x400]; 165 | } break; 166 | 167 | case 0xE003: 168 | case 0xE00C: { 169 | Mapper_25_regs[7] = (Mapper_25_regs[7] & 0x0F) | ((data & 0x0F) << 4); 170 | PPUBANK[7] = &VROM[Mapper_25_regs[7] * 0x400]; 171 | } break; 172 | 173 | case 0xF000: { 174 | Mapper_25_irq_latch = (Mapper_25_irq_latch & 0xF0) | (data & 0x0F); 175 | } break; 176 | 177 | case 0xF001: 178 | case 0xF004: { 179 | Mapper_25_irq_enabled = data & 0x03; 180 | if (Mapper_25_irq_enabled & 0x02) { 181 | Mapper_25_irq_counter = Mapper_25_irq_latch; 182 | } 183 | } break; 184 | 185 | case 0xF002: 186 | case 0xF008: { 187 | Mapper_25_irq_latch = (Mapper_25_irq_latch & 0x0F) | ((data & 0x0F) << 4); 188 | } break; 189 | 190 | case 0xF003: 191 | case 0xF00C: { 192 | Mapper_25_irq_enabled = (Mapper_25_irq_enabled & 0x01) * 3; 193 | } break; 194 | } 195 | } 196 | 197 | void Mapper_25_HSync() { 198 | if (Mapper_25_irq_enabled & 0x02) { 199 | if(!Mapper_25_patch && Mapper_25_irq_counter == 0xFF) { 200 | Mapper_25_irq_counter = Mapper_25_irq_latch; 201 | IRQ_REQ; 202 | } else if(Mapper_25_patch && Mapper_25_irq_counter == 0x00) { 203 | Mapper_25_irq_counter = Mapper_25_irq_latch; 204 | IRQ_REQ; 205 | } else { 206 | Mapper_25_irq_counter++; 207 | } 208 | } 209 | } -------------------------------------------------------------------------------- /Mapper_25.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_25_H 2 | #define _MAPPER_25_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_25_Init(); 7 | void Mapper_25_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_25_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_26.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_26.h" 2 | 3 | #include "nes_apu.h" 4 | 5 | unsigned char Mapper_26_irq_enabled; 6 | unsigned char Mapper_26_irq_counter; 7 | unsigned char Mapper_26_irq_latch; 8 | 9 | void Mapper_26_Init() { 10 | apu_set_exsound(NES_APU_EXSOUND_VRC6); 11 | 12 | // set CPU bank pointers 13 | ROMBANK0 = ROMPAGE(0); 14 | ROMBANK1 = ROMPAGE(1); 15 | ROMBANK2 = ROMLASTPAGE(1); 16 | ROMBANK3 = ROMLASTPAGE(0); 17 | 18 | if ( NesHeader.byVRomSize > 0 ) { 19 | for ( int nPage = 0; nPage < 8; ++nPage ) 20 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 21 | } 22 | 23 | Mapper_26_irq_enabled = 0; 24 | Mapper_26_irq_counter = 0; 25 | } 26 | 27 | void Mapper_26_Write(uint16 addr, unsigned char data) { 28 | switch(addr) { 29 | case 0x8000: { 30 | ROMBANK0 = ROMPAGE(data << 1); 31 | ROMBANK1 = ROMPAGE((data << 1) + 1); 32 | } break; 33 | 34 | case 0xB003: { 35 | data = data & 0x7F; 36 | if (data == 0x08 || data == 0x2C) { 37 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 38 | } else if(data == 0x20) { 39 | pNesX_Mirroring(MIRRORING_VERTICAL); 40 | } else if(data == 0x24) { 41 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 42 | } else if(data == 0x28) { 43 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 44 | } 45 | } break; 46 | 47 | case 0xC000: { 48 | ROMBANK2 = ROMPAGE(data); 49 | } break; 50 | 51 | case 0xD000: { 52 | PPUBANK[0] = VROMPAGE(data); 53 | } break; 54 | 55 | case 0xD001: { 56 | PPUBANK[2] = VROMPAGE(data); 57 | } break; 58 | 59 | case 0xD002: { 60 | PPUBANK[1] = VROMPAGE(data); 61 | } break; 62 | 63 | case 0xD003: { 64 | PPUBANK[3] = VROMPAGE(data); 65 | } break; 66 | 67 | case 0xE000: { 68 | PPUBANK[4] = VROMPAGE(data); 69 | } break; 70 | 71 | case 0xE001: { 72 | PPUBANK[6] = VROMPAGE(data); 73 | } break; 74 | 75 | case 0xE002: { 76 | PPUBANK[5] = VROMPAGE(data); 77 | } break; 78 | 79 | case 0xE003: { 80 | PPUBANK[7] = VROMPAGE(data); 81 | } break; 82 | 83 | case 0xF000: { 84 | Mapper_26_irq_latch = data; 85 | } break; 86 | 87 | case 0xF001: { 88 | Mapper_26_irq_enabled = data & 0x01; 89 | } break; 90 | 91 | case 0xF002: { 92 | Mapper_26_irq_enabled = data & 0x03; 93 | if (Mapper_26_irq_enabled & 0x02) { 94 | Mapper_26_irq_counter = Mapper_26_irq_latch; 95 | } 96 | } break; 97 | } 98 | 99 | addr = (addr & 0xfffc) | ((addr & 1) << 1) | ((addr & 2) >> 1); 100 | ex_write(addr, data); 101 | } 102 | 103 | void Mapper_26_HSync() { 104 | if (Mapper_26_irq_enabled & 0x03) { 105 | if(Mapper_26_irq_counter >= 0xFE) { 106 | IRQ_REQ; 107 | Mapper_26_irq_counter = Mapper_26_irq_latch; 108 | Mapper_26_irq_enabled = 0; 109 | } else { 110 | Mapper_26_irq_counter++; 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /Mapper_26.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_26_H 2 | #define _MAPPER_26_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_26_Init(); 7 | void Mapper_26_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_26_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_3.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_3.h" 2 | 3 | /*===================================================================*/ 4 | /* */ 5 | /* Mapper 3 (VROM Switch) */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | /*-------------------------------------------------------------------*/ 10 | /* Initialize Mapper 3 */ 11 | /*-------------------------------------------------------------------*/ 12 | void Mapper_3_Init() { 13 | int nPage; 14 | 15 | /* Set ROM Banks */ 16 | if ((NesHeader.byRomSize * 2) > 2) { 17 | ROMBANK0 = ROMPAGE( 0 ); 18 | ROMBANK1 = ROMPAGE( 1 ); 19 | ROMBANK2 = ROMPAGE( 2 ); 20 | ROMBANK3 = ROMPAGE( 3 ); 21 | } else { 22 | ROMBANK0 = ROMPAGE( 0 ); 23 | ROMBANK1 = ROMPAGE( 1 ); 24 | ROMBANK2 = ROMPAGE( 0 ); 25 | ROMBANK3 = ROMPAGE( 1 ); 26 | } 27 | 28 | /* Set PPU Banks */ 29 | for ( nPage = 0; nPage < 8; ++nPage ) 30 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 31 | } 32 | 33 | /*-------------------------------------------------------------------*/ 34 | /* Mapper 3 Write Function */ 35 | /*-------------------------------------------------------------------*/ 36 | void Mapper_3_Write( uint16 wAddr, unsigned char byData ) { 37 | if (wAddr & 0x8000) { 38 | //printf("Map3: Setting PPU banks to page [%u]\n", byData); 39 | uint16 base = (byData % NesHeader.byVRomSize) * 8; 40 | 41 | PPUBANK[0] = &VROM[ (base * 0x400) ]; 42 | PPUBANK[1] = &VROM[ ((base + 1) * 0x400) ]; 43 | PPUBANK[2] = &VROM[ ((base + 2) * 0x400) ]; 44 | PPUBANK[3] = &VROM[ ((base + 3) * 0x400) ]; 45 | PPUBANK[4] = &VROM[ ((base + 4) * 0x400) ]; 46 | PPUBANK[5] = &VROM[ ((base + 5) * 0x400) ]; 47 | PPUBANK[6] = &VROM[ ((base + 6) * 0x400) ]; 48 | PPUBANK[7] = &VROM[ ((base + 7) * 0x400) ]; 49 | } 50 | } -------------------------------------------------------------------------------- /Mapper_3.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_3_H 2 | #define _MAPPER_3_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_3_Init(); 7 | void Mapper_3_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_30.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_30.h" 2 | 3 | void Mapper_30_Init() { 4 | ROMBANK0 = ROMPAGE( 0 ); 5 | ROMBANK1 = ROMPAGE( 1 ); 6 | ROMBANK2 = ROMLASTPAGE(1); 7 | ROMBANK3 = ROMLASTPAGE(0); 8 | 9 | for ( int nPage = 0; nPage < 8; ++nPage ) 10 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 11 | } 12 | 13 | void Mapper_30_Write( uint16 wAddr, unsigned char byData ) { 14 | // printf("Map30_Write: $%04X, %02X\n", wAddr, byData); 15 | if ((wAddr >= 0x8000) && (wAddr <= 0xFFFF)) { 16 | unsigned char prg = byData & 0x1f; 17 | unsigned char chr = (byData & 0x60) >> 5; 18 | 19 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 20 | ROMBANK0 = ROMPAGE( (prg * 2) % num_8k_ROM_banks ); 21 | ROMBANK1 = ROMPAGE( ((prg * 2) + 1) % num_8k_ROM_banks ); 22 | 23 | unsigned char c = chr * 8; 24 | for ( int nPage = 0; nPage < 8; nPage++) 25 | PPUBANK[ nPage ] = &VROM[(nPage + c) * 0x400 ]; 26 | } 27 | } -------------------------------------------------------------------------------- /Mapper_30.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_30_H 2 | #define _MAPPER_30_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_30_Init(); 7 | void Mapper_30_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_4.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_4.h" 2 | 3 | /*===================================================================*/ 4 | /* */ 5 | /* Mapper 4 (MMC3) */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | unsigned char Map4_VROM_Base; 10 | unsigned char Map4_ROM_Base; 11 | unsigned char Map4_Cmd; 12 | unsigned char Map4_Banks_Reg[ 8 ]; 13 | unsigned char Map4_IRQ_Cnt; 14 | unsigned char Map4_IRQ_Set; 15 | unsigned char Map4_IRQ_Enable; 16 | 17 | void Mapper_4_Set_PPU_banks() { 18 | /* Set VROM Banks */ 19 | if ( NesHeader.byVRomSize > 0 ) { 20 | if ( Map4_VROM_Base ) { 21 | PPUBANK[ 0 ] = VROMPAGE( Map4_Banks_Reg[ 2 ] ); 22 | PPUBANK[ 1 ] = VROMPAGE( Map4_Banks_Reg[ 3 ] ); 23 | PPUBANK[ 2 ] = VROMPAGE( Map4_Banks_Reg[ 4 ] ); 24 | PPUBANK[ 3 ] = VROMPAGE( Map4_Banks_Reg[ 5 ] ); 25 | PPUBANK[ 4 ] = VROMPAGE( Map4_Banks_Reg[ 0 ] ); 26 | PPUBANK[ 5 ] = VROMPAGE( Map4_Banks_Reg[ 0 ] + 1 ); 27 | PPUBANK[ 6 ] = VROMPAGE( Map4_Banks_Reg[ 1 ] ); 28 | PPUBANK[ 7 ] = VROMPAGE( Map4_Banks_Reg[ 1 ] + 1 ); 29 | } else { 30 | PPUBANK[ 0 ] = VROMPAGE( Map4_Banks_Reg[ 0 ] ); 31 | PPUBANK[ 1 ] = VROMPAGE( Map4_Banks_Reg[ 0 ] + 1 ); 32 | PPUBANK[ 2 ] = VROMPAGE( Map4_Banks_Reg[ 1 ] ); 33 | PPUBANK[ 3 ] = VROMPAGE( Map4_Banks_Reg[ 1 ] + 1 ); 34 | PPUBANK[ 4 ] = VROMPAGE( Map4_Banks_Reg[ 2 ] ); 35 | PPUBANK[ 5 ] = VROMPAGE( Map4_Banks_Reg[ 3 ] ); 36 | PPUBANK[ 6 ] = VROMPAGE( Map4_Banks_Reg[ 4 ] ); 37 | PPUBANK[ 7 ] = VROMPAGE( Map4_Banks_Reg[ 5 ] ); 38 | } 39 | } 40 | } 41 | 42 | void Mapper_4_Set_CPU_banks() { 43 | if ( Map4_ROM_Base ) { 44 | ROMBANK0 = ROMLASTPAGE( 1 ); 45 | ROMBANK1 = ROMPAGE( Map4_Banks_Reg[ 7 ] ); 46 | ROMBANK2 = ROMPAGE( Map4_Banks_Reg[ 6 ] ); 47 | ROMBANK3 = ROMLASTPAGE( 0 ); 48 | } else { 49 | ROMBANK0 = ROMPAGE( Map4_Banks_Reg[ 6 ] ); 50 | ROMBANK1 = ROMPAGE( Map4_Banks_Reg[ 7 ] ); 51 | ROMBANK2 = ROMLASTPAGE( 1 ); 52 | ROMBANK3 = ROMLASTPAGE( 0 ); 53 | } 54 | } 55 | 56 | /*-------------------------------------------------------------------*/ 57 | /* Mapper 4 Write Function */ 58 | /*-------------------------------------------------------------------*/ 59 | void Mapper_4_Write( uint16 wAddr, unsigned char byData ) { 60 | uint16 wMapAddr; 61 | 62 | wMapAddr = wAddr & 0xe001; 63 | 64 | switch ( wMapAddr ) { 65 | case 0xa000: 66 | // Name Table Mirroring - But only if 4 Screen Mirroring is not enabled 67 | if (!(NesHeader.byInfo1 & 0x08)) { 68 | if (byData & 0x1) { 69 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 70 | } else { 71 | pNesX_Mirroring(MIRRORING_VERTICAL); 72 | } 73 | } 74 | break; 75 | 76 | case 0xa001: 77 | // Enable/Disable SRAM - Not Emulated 78 | break; 79 | 80 | case 0xc000: 81 | Map4_IRQ_Cnt = byData; 82 | break; 83 | 84 | case 0xc001: 85 | Map4_IRQ_Set = byData; 86 | break; 87 | 88 | case 0xe000: 89 | Map4_IRQ_Enable = 0; 90 | break; 91 | 92 | case 0xe001: 93 | Map4_IRQ_Enable = 1; 94 | break; 95 | 96 | case 0x8000: 97 | Map4_VROM_Base = ( byData >> 7 ) & 0x1; 98 | Map4_ROM_Base = ( byData >> 6 ) & 0x1; 99 | Map4_Cmd = byData & 0x7; 100 | Mapper_4_Set_CPU_banks(); 101 | Mapper_4_Set_PPU_banks(); 102 | break; 103 | 104 | case 0x8001: 105 | if ( Map4_Cmd >= 6 ) { 106 | byData %= ( NesHeader.byRomSize << 1 ); 107 | Map4_Banks_Reg[ Map4_Cmd ] = byData; 108 | Mapper_4_Set_CPU_banks(); 109 | } else if ( NesHeader.byVRomSize > 0 ) { 110 | if ( Map4_Cmd < 2 ) 111 | byData = ( byData & 0xfe ) % ( NesHeader.byVRomSize << 3 ); 112 | else if ( Map4_Cmd < 6 ) 113 | byData %= ( NesHeader.byVRomSize << 3 ); 114 | Map4_Banks_Reg[ Map4_Cmd ] = byData; 115 | Mapper_4_Set_PPU_banks(); 116 | } 117 | break; 118 | } 119 | } 120 | 121 | /*-------------------------------------------------------------------*/ 122 | /* Initialize Mapper 4 */ 123 | /*-------------------------------------------------------------------*/ 124 | void Mapper_4_Init() { 125 | Map4_VROM_Base = Map4_ROM_Base = Map4_Cmd = Map4_IRQ_Cnt = Map4_IRQ_Set = Map4_IRQ_Enable = 0; 126 | 127 | //Banks Registers 6 + 7 are program rom registers 128 | Map4_Banks_Reg[ 6 ] = 0; 129 | Map4_Banks_Reg[ 7 ] = 1; 130 | 131 | if (NesHeader.byVRomSize) { 132 | Map4_Banks_Reg[ 0 ] = 0; 133 | Map4_Banks_Reg[ 1 ] = 2; 134 | Map4_Banks_Reg[ 2 ] = 4; 135 | Map4_Banks_Reg[ 3 ] = 5; 136 | Map4_Banks_Reg[ 4 ] = 6; 137 | Map4_Banks_Reg[ 5 ] = 7; 138 | } else { 139 | Map4_Banks_Reg[ 0 ] = 0; 140 | Map4_Banks_Reg[ 1 ] = 0; 141 | Map4_Banks_Reg[ 2 ] = 0; 142 | Map4_Banks_Reg[ 3 ] = 0; 143 | Map4_Banks_Reg[ 4 ] = 0; 144 | Map4_Banks_Reg[ 5 ] = 0; 145 | } 146 | 147 | Mapper_4_Write( 0x8000, 0 ); 148 | Mapper_4_Write( 0x8001, 0 ); 149 | 150 | /* Set up wiring of the interrupt pin */ 151 | K6502_Set_Int_Wiring( 1, 1 ); 152 | 153 | Map4_IRQ_Enable = 0; 154 | Map4_IRQ_Set = 0; 155 | Map4_IRQ_Cnt = 0; 156 | } 157 | 158 | /*-------------------------------------------------------------------*/ 159 | /* Mapper 4 V-Sync Function */ 160 | /*-------------------------------------------------------------------*/ 161 | void Mapper_4_VSync() { 162 | Map4_IRQ_Cnt = Map4_IRQ_Set; 163 | } 164 | 165 | /*-------------------------------------------------------------------*/ 166 | /* Mapper 4 H-Sync Function */ 167 | /*-------------------------------------------------------------------*/ 168 | void Mapper_4_HSync() { 169 | if (Map4_IRQ_Enable) { 170 | if ((ppuinfo.PPU_Scanline >= 0) && (ppuinfo.PPU_Scanline <= 239)) { 171 | if (PPU_R1 & (R1_SHOW_SCR | R1_SHOW_SP )) { 172 | Map4_IRQ_Cnt--; 173 | if (Map4_IRQ_Cnt == 0) { 174 | Map4_IRQ_Cnt = Map4_IRQ_Set; 175 | IRQ_REQ; 176 | } 177 | } 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /Mapper_4.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_4_H 2 | #define _MAPPER_4_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_4_Init(); 7 | void Mapper_4_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_4_HSync(); 9 | void Mapper_4_VSync(); 10 | 11 | 12 | #endif -------------------------------------------------------------------------------- /Mapper_5.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_5_H 2 | #define _MAPPER_5_H 3 | 4 | #include "Mapper.h" 5 | 6 | unsigned char Mapper_5_PPU_Latch_RenderScreen(uint8 mode, uint32 addr); 7 | 8 | void Mapper_5_Init(); 9 | void Mapper_5_Write( uint16 wAddr, unsigned char byData ); 10 | unsigned char Mapper_5_Read( uint16 wAddr ); 11 | void Mapper_5_HSync(); 12 | 13 | #endif -------------------------------------------------------------------------------- /Mapper_64.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_64.h" 2 | 3 | uint8 Mapper_64_regs[3]; 4 | uint8 Mapper_64_irq_latch; 5 | uint8 Mapper_64_irq_counter; 6 | uint8 Mapper_64_irq_enabled; 7 | 8 | void Mapper_64_Init() { 9 | 10 | ROMBANK0 = ROMLASTPAGE( 0 ); 11 | ROMBANK1 = ROMLASTPAGE( 0 ); 12 | ROMBANK2 = ROMLASTPAGE( 0 ); 13 | ROMBANK3 = ROMLASTPAGE( 0 ); 14 | 15 | if ( NesHeader.byVRomSize > 0 ) { 16 | for ( int nPage = 0; nPage < 8; ++nPage ) 17 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 18 | } 19 | 20 | Mapper_64_irq_latch = 0; 21 | Mapper_64_irq_counter = 0; 22 | Mapper_64_irq_enabled = 0; 23 | 24 | Mapper_64_regs[0] = 0; 25 | Mapper_64_regs[1] = 0; 26 | Mapper_64_regs[2] = 0; 27 | } 28 | 29 | void Mapper_64_Write( uint16 wAddr, unsigned char byData ) { 30 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 31 | 32 | switch(wAddr & 0xF003) { 33 | case 0x8000: { 34 | Mapper_64_regs[0] = byData & 0x0F; 35 | Mapper_64_regs[1] = byData & 0x40; 36 | Mapper_64_regs[2] = byData & 0x80; 37 | } break; 38 | 39 | case 0x8001: { 40 | switch(Mapper_64_regs[0]) { 41 | case 0x00: { 42 | if(Mapper_64_regs[2]) { 43 | PPUBANK[4] = &VROM[ byData * 0x400 ]; 44 | PPUBANK[5] = &VROM[ (byData + 1) * 0x400 ]; 45 | } else { 46 | PPUBANK[0] = &VROM[ byData * 0x400 ]; 47 | PPUBANK[1] = &VROM[ (byData + 1) * 0x400 ]; 48 | } 49 | } break; 50 | 51 | case 0x01: { 52 | if(Mapper_64_regs[2]) { 53 | PPUBANK[6] = &VROM[ byData * 0x400 ]; 54 | PPUBANK[7] = &VROM[ (byData + 1) * 0x400 ]; 55 | } else { 56 | PPUBANK[2] = &VROM[ byData * 0x400 ]; 57 | PPUBANK[3] = &VROM[ (byData + 1) * 0x400 ]; 58 | } 59 | } break; 60 | 61 | case 0x02: { 62 | if(Mapper_64_regs[2]) { 63 | PPUBANK[0] = &VROM[ byData * 0x400 ]; 64 | } else { 65 | PPUBANK[4] = &VROM[ byData * 0x400 ]; 66 | } 67 | } 68 | break; 69 | 70 | case 0x03: { 71 | if(Mapper_64_regs[2]) { 72 | PPUBANK[1] = &VROM[ byData * 0x400 ]; 73 | } else { 74 | PPUBANK[5] = &VROM[ byData * 0x400 ]; 75 | } 76 | } 77 | break; 78 | 79 | case 0x04: { 80 | if(Mapper_64_regs[2]) { 81 | PPUBANK[2] = &VROM[ byData * 0x400 ]; 82 | } else { 83 | PPUBANK[6] = &VROM[ byData * 0x400 ]; 84 | } 85 | } 86 | break; 87 | 88 | case 0x05: { 89 | if(Mapper_64_regs[2]) { 90 | PPUBANK[3] = &VROM[ byData * 0x400 ]; 91 | } else { 92 | PPUBANK[7] = &VROM[ byData * 0x400 ]; 93 | } 94 | } 95 | break; 96 | 97 | case 0x06: { 98 | if(Mapper_64_regs[1]) { 99 | ROMBANK1 = ROMPAGE(byData % num_8k_ROM_banks); 100 | } else { 101 | ROMBANK0 = ROMPAGE(byData % num_8k_ROM_banks); 102 | } 103 | } 104 | break; 105 | 106 | case 0x07: { 107 | if(Mapper_64_regs[1]) { 108 | ROMBANK2 = ROMPAGE(byData % num_8k_ROM_banks); 109 | } else { 110 | ROMBANK1 = ROMPAGE(byData % num_8k_ROM_banks); 111 | } 112 | } break; 113 | 114 | case 0x08: { 115 | PPUBANK[1] = &VROM[ byData * 0x400 ]; 116 | } break; 117 | 118 | case 0x09: { 119 | PPUBANK[3] = &VROM[ byData * 0x400 ]; 120 | } break; 121 | 122 | case 0x0F: { 123 | if(Mapper_64_regs[1]) { 124 | ROMBANK0 = ROMPAGE(byData % num_8k_ROM_banks); 125 | } else { 126 | ROMBANK2 = ROMPAGE(byData % num_8k_ROM_banks); 127 | } 128 | } break; 129 | } 130 | } 131 | break; 132 | 133 | case 0xA000: { 134 | if(!(byData & 0x01)) { 135 | pNesX_Mirroring(MIRRORING_VERTICAL); 136 | } else { 137 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 138 | } 139 | } break; 140 | 141 | case 0xC000: { 142 | Mapper_64_irq_latch = byData; 143 | Mapper_64_irq_counter = Mapper_64_irq_latch; 144 | } break; 145 | 146 | case 0xC001: { 147 | Mapper_64_irq_counter = Mapper_64_irq_latch; 148 | } break; 149 | 150 | case 0xE000: { 151 | Mapper_64_irq_enabled = 0; 152 | Mapper_64_irq_counter = Mapper_64_irq_latch; 153 | } break; 154 | 155 | case 0xE001: { 156 | Mapper_64_irq_enabled = 1; 157 | Mapper_64_irq_counter = Mapper_64_irq_latch; 158 | } break; 159 | } 160 | } 161 | 162 | void Mapper_64_HSync() { 163 | if (Mapper_64_irq_enabled) { 164 | if ((ppuinfo.PPU_Scanline >= 0) && (ppuinfo.PPU_Scanline <= 239)) { 165 | if (PPU_R1 & (R1_SHOW_SCR | R1_SHOW_SP )) { 166 | if (!(--Mapper_64_irq_counter)) { 167 | Mapper_64_irq_counter = Mapper_64_irq_latch; 168 | IRQ_REQ; 169 | } 170 | } 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /Mapper_64.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_64_H 2 | #define _MAPPER_64_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_64_Init(); 7 | void Mapper_64_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_64_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_66.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_66.h" 2 | 3 | void Mapper_66_Init() { 4 | ROMBANK0 = ROMPAGE( 0 ); 5 | ROMBANK1 = ROMPAGE( 1 ); 6 | ROMBANK2 = ROMPAGE( 2 ); 7 | ROMBANK3 = ROMPAGE( 3 ); 8 | 9 | /* Set PPU Banks */ 10 | for ( int nPage = 0; nPage < 8; ++nPage ) 11 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 12 | 13 | pNesX_Mirroring(MIRRORING_VERTICAL); 14 | } 15 | 16 | void Mapper_66_Write( uint16 wAddr, unsigned char byData ) { 17 | uint8 prg_bank = (byData & 0xF0) >> 4; 18 | uint8 chr_bank = byData & 0x0F; 19 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 20 | uint32 num_1k_VROM_banks = NesHeader.byVRomSize * 8; 21 | 22 | ROMBANK0 = ROMPAGE((prg_bank * 4)); 23 | ROMBANK1 = ROMPAGE((prg_bank * 4) + 1); 24 | ROMBANK2 = ROMPAGE((prg_bank * 4) + 2); 25 | ROMBANK3 = ROMPAGE((prg_bank * 4) + 3); 26 | 27 | for ( int nPage = 0; nPage < 8; ++nPage ) { 28 | PPUBANK[ nPage ] = &VROM[ (((chr_bank * 8) + nPage) % num_1k_VROM_banks) * 0x400 ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Mapper_66.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_66_H 2 | #define _MAPPER_66_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_66_Init(); 7 | void Mapper_66_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_67.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_67.h" 2 | 3 | uint8 Mapper_67_irq_enabled; 4 | uint8 Mapper_67_irq_counter; 5 | uint8 Mapper_67_irq_latch; 6 | 7 | void Mapper_67_Init() { 8 | // set CPU bank pointers 9 | ROMBANK0 = ROMPAGE(0); 10 | ROMBANK1 = ROMPAGE(1); 11 | ROMBANK2 = ROMLASTPAGE(1); 12 | ROMBANK3 = ROMLASTPAGE(0); 13 | 14 | // set PPU bank pointers 15 | uint32 num_1k_VROM_banks = NesHeader.byVRomSize * 8; 16 | PPUBANK[0] = &VROM[ 0 * 0x400 ]; 17 | PPUBANK[1] = &VROM[ 1 * 0x400 ]; 18 | PPUBANK[2] = &VROM[ 2 * 0x400 ]; 19 | PPUBANK[3] = &VROM[ 3 * 0x400 ]; 20 | PPUBANK[4] = &VROM[ (num_1k_VROM_banks - 4) * 0x400 ]; 21 | PPUBANK[5] = &VROM[ (num_1k_VROM_banks - 3) * 0x400 ]; 22 | PPUBANK[6] = &VROM[ (num_1k_VROM_banks - 2) * 0x400 ]; 23 | PPUBANK[7] = &VROM[ (num_1k_VROM_banks - 1) * 0x400 ]; 24 | 25 | Mapper_67_irq_enabled = 0; 26 | Mapper_67_irq_counter = 0; 27 | Mapper_67_irq_latch = 0; 28 | } 29 | 30 | void Mapper_67_Write(uint16 addr, uint8 data) { 31 | switch (addr & 0xF800) { 32 | case 0x8800: { 33 | PPUBANK[0] = &VROM[ (data * 2) * 0x400 ]; 34 | PPUBANK[1] = &VROM[ ((data * 2) + 1) * 0x400 ]; 35 | } break; 36 | 37 | case 0x9800: { 38 | PPUBANK[2] = &VROM[ (data * 2) * 0x400 ]; 39 | PPUBANK[3] = &VROM[ ((data * 2) + 1) * 0x400 ]; 40 | } break; 41 | 42 | case 0xA800: { 43 | PPUBANK[4] = &VROM[ (data * 2) * 0x400 ]; 44 | PPUBANK[5] = &VROM[ ((data * 2) + 1) * 0x400 ]; 45 | } break; 46 | 47 | case 0xB800: { 48 | PPUBANK[6] = &VROM[ (data * 2) * 0x400 ]; 49 | PPUBANK[7] = &VROM[ ((data * 2) + 1) * 0x400 ]; 50 | } break; 51 | 52 | case 0xC800: { 53 | Mapper_67_irq_counter = Mapper_67_irq_latch; 54 | Mapper_67_irq_latch = data; 55 | } break; 56 | 57 | case 0xD800: { 58 | Mapper_67_irq_enabled = data & 0x10; 59 | } break; 60 | 61 | case 0xE800: { 62 | data &= 0x03; 63 | if (data == 0) { 64 | pNesX_Mirroring(MIRRORING_VERTICAL); 65 | } else if (data == 1) { 66 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 67 | } else if(data == 2) { 68 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 69 | } else { 70 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 71 | } 72 | } break; 73 | 74 | case 0xF800: { 75 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 76 | //printf("Setting configurable ROM banks to [%lu] and [%lu]\n", ((data & 0xF) * 2) % num_8k_ROM_banks, (((data & 0xF) * 2) + 1) % num_8k_ROM_banks); 77 | ROMBANK0 = ROMPAGE(((data & 0xF) * 2) % num_8k_ROM_banks); 78 | ROMBANK1 = ROMPAGE((((data & 0xF) * 2) + 1) % num_8k_ROM_banks); 79 | } break; 80 | } 81 | } 82 | 83 | void Mapper_67_HSync() { 84 | if (Mapper_67_irq_enabled) { 85 | if ((ppuinfo.PPU_Scanline >= 0) && (ppuinfo.PPU_Scanline <= 239)) { 86 | if (PPU_R1 & (R1_SHOW_SCR | R1_SHOW_SP )) { 87 | if (--Mapper_67_irq_counter == 0xF6) { 88 | Mapper_67_irq_counter = Mapper_67_irq_latch; 89 | IRQ_REQ; 90 | } 91 | } 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /Mapper_67.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_67_H 2 | #define _MAPPER_67_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_67_Init(); 7 | void Mapper_67_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_67_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_68.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_68.h" 2 | 3 | uint8 Mapper_68_regs[4]; 4 | 5 | void Mapper_68_Init() { 6 | 7 | ROMBANK0 = ROMPAGE( 0 ); 8 | ROMBANK1 = ROMPAGE( 1 ); 9 | ROMBANK2 = ROMLASTPAGE( 1 ); 10 | ROMBANK3 = ROMLASTPAGE( 0 ); 11 | 12 | Mapper_68_regs[0] = 0; 13 | Mapper_68_regs[1] = 0; 14 | Mapper_68_regs[2] = 0; 15 | Mapper_68_regs[3] = 0; 16 | } 17 | 18 | void SyncMirror() { 19 | if (Mapper_68_regs[0]) { 20 | if (Mapper_68_regs[1] == 0) { 21 | PPUBANK[8] = &VROM[ (Mapper_68_regs[2] + 0x80) * 0x400 ]; 22 | PPUBANK[9] = &VROM[ (Mapper_68_regs[3] + 0x80) * 0x400 ]; 23 | PPUBANK[10] = &VROM[ (Mapper_68_regs[2] + 0x80) * 0x400 ]; 24 | PPUBANK[11] = &VROM[ (Mapper_68_regs[3] + 0x80) * 0x400 ]; 25 | } else if (Mapper_68_regs[1] == 1) { 26 | PPUBANK[8] = &VROM[ (Mapper_68_regs[2] + 0x80) * 0x400 ]; 27 | PPUBANK[9] = &VROM[ (Mapper_68_regs[2] + 0x80) * 0x400 ]; 28 | PPUBANK[10] = &VROM[ (Mapper_68_regs[3] + 0x80) * 0x400 ]; 29 | PPUBANK[11] = &VROM[ (Mapper_68_regs[3] + 0x80) * 0x400 ]; 30 | } else if (Mapper_68_regs[1] == 2) { 31 | PPUBANK[8] = &VROM[ (Mapper_68_regs[2] + 0x80) * 0x400 ]; 32 | PPUBANK[9] = &VROM[ (Mapper_68_regs[2] + 0x80) * 0x400 ]; 33 | PPUBANK[10] = &VROM[ (Mapper_68_regs[2] + 0x80) * 0x400 ]; 34 | PPUBANK[11] = &VROM[ (Mapper_68_regs[2] + 0x80) * 0x400 ]; 35 | } else if (Mapper_68_regs[1] == 3) { 36 | PPUBANK[8] = &VROM[ (Mapper_68_regs[3] + 0x80) * 0x400 ]; 37 | PPUBANK[9] = &VROM[ (Mapper_68_regs[3] + 0x80) * 0x400 ]; 38 | PPUBANK[10] = &VROM[ (Mapper_68_regs[3] + 0x80) * 0x400 ]; 39 | PPUBANK[11] = &VROM[ (Mapper_68_regs[3] + 0x80) * 0x400 ]; 40 | } 41 | } else { 42 | if (Mapper_68_regs[1] == 0) { 43 | pNesX_Mirroring(MIRRORING_VERTICAL); 44 | } else if (Mapper_68_regs[1] == 1) { 45 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 46 | } else if (Mapper_68_regs[1] == 2) { 47 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 48 | } else if (Mapper_68_regs[1] == 3) { 49 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 50 | } 51 | } 52 | } 53 | 54 | void Mapper_68_Write( uint16 wAddr, unsigned char byData ) { 55 | switch(wAddr & 0xF000) { 56 | case 0x8000: { 57 | PPUBANK[0] = &VROM[ (byData * 2) * 0x400 ]; 58 | PPUBANK[1] = &VROM[ ((byData * 2) + 1) * 0x400 ]; 59 | } break; 60 | 61 | case 0x9000: { 62 | PPUBANK[2] = &VROM[ (byData * 2) * 0x400 ]; 63 | PPUBANK[3] = &VROM[ ((byData * 2) + 1) * 0x400 ]; 64 | } break; 65 | 66 | case 0xA000: { 67 | PPUBANK[4] = &VROM[ (byData * 2) * 0x400 ]; 68 | PPUBANK[5] = &VROM[ ((byData * 2) + 1) * 0x400 ]; 69 | } break; 70 | 71 | case 0xB000: { 72 | PPUBANK[6] = &VROM[ (byData * 2) * 0x400 ]; 73 | PPUBANK[7] = &VROM[ ((byData * 2) + 1) * 0x400 ]; 74 | } break; 75 | 76 | case 0xC000: { 77 | Mapper_68_regs[2] = byData; 78 | SyncMirror(); 79 | } break; 80 | 81 | case 0xD000: { 82 | Mapper_68_regs[3] = byData; 83 | SyncMirror(); 84 | } break; 85 | 86 | case 0xE000: { 87 | Mapper_68_regs[0] = (byData & 0x10) >> 4; 88 | Mapper_68_regs[1] = byData & 0x03; 89 | SyncMirror(); 90 | } break; 91 | 92 | case 0xF000: { 93 | ROMBANK0 = ROMPAGE((byData * 2)); 94 | ROMBANK1 = ROMPAGE((byData * 2) + 1); 95 | } break; 96 | } 97 | } -------------------------------------------------------------------------------- /Mapper_68.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_68_H 2 | #define _MAPPER_68_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_68_Init(); 7 | void Mapper_68_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_69.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_69.h" 2 | #include "nes_apu.h" 3 | 4 | uint8 Mapper_69_regs[1]; 5 | uint8 Mapper_69_irq_enabled; 6 | uint32 Mapper_69_irq_counter; 7 | 8 | ///////////////////////////////////////////////////////////////////// 9 | // Mapper 69 10 | void Mapper_69_Init() { 11 | // Init ExSound 12 | apu_set_exsound(NES_APU_EXSOUND_FME7); 13 | 14 | ROMBANK0 = ROMPAGE( 0 ); 15 | ROMBANK1 = ROMPAGE( 1 ); 16 | ROMBANK2 = ROMLASTPAGE( 1 ); 17 | ROMBANK3 = ROMLASTPAGE( 0 ); 18 | 19 | if ( NesHeader.byVRomSize > 0 ) { 20 | for ( int nPage = 0; nPage < 8; ++nPage ) 21 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 22 | } 23 | 24 | Mapper_69_irq_enabled = 0; 25 | Mapper_69_irq_counter = 0; 26 | } 27 | 28 | void Mapper_69_Write(uint16 addr, uint8 data) { 29 | switch(addr & 0xE000) { 30 | case 0x8000: { 31 | Mapper_69_regs[0] = data & 0x0f; 32 | pNesX_DebugPrint("Map69: Setting Command to [%u]\n", Mapper_69_regs[0]); 33 | } break; 34 | 35 | case 0xA000: { 36 | switch (Mapper_69_regs[0]) { 37 | case 0x00: { 38 | pNesX_DebugPrint("Map69: Set PPUBANK0 to Page [%u]\n", data); 39 | PPUBANK[0] = &VROM[ data * 0x400 ]; 40 | } break; 41 | 42 | case 0x01: { 43 | pNesX_DebugPrint("Map69: Set PPUBANK1 to Page [%u]\n", data); 44 | PPUBANK[1] = &VROM[ data * 0x400 ]; 45 | } break; 46 | 47 | case 0x02: { 48 | pNesX_DebugPrint("Map69: Set PPUBANK2 to Page [%u]\n", data); 49 | PPUBANK[2] = &VROM[ data * 0x400 ]; 50 | } break; 51 | 52 | case 0x03: { 53 | pNesX_DebugPrint("Map69: Set PPUBANK3 to Page [%u]\n", data); 54 | PPUBANK[3] = &VROM[ data * 0x400 ]; 55 | } break; 56 | 57 | case 0x04: { 58 | pNesX_DebugPrint("Map69: Set PPUBANK4 to Page [%u]\n", data); 59 | PPUBANK[4] = &VROM[ data * 0x400 ]; 60 | } break; 61 | 62 | case 0x05: { 63 | pNesX_DebugPrint("Map69: Set PPUBANK5 to Page [%u]\n", data); 64 | PPUBANK[5] = &VROM[ data * 0x400 ]; 65 | } break; 66 | 67 | case 0x06: { 68 | pNesX_DebugPrint("Map69: Set PPUBANK6 to Page [%u]\n", data); 69 | PPUBANK[6] = &VROM[ data * 0x400 ]; 70 | } break; 71 | 72 | case 0x07: { 73 | pNesX_DebugPrint("Map69: Set PPUBANK7 to Page [%u]\n", data); 74 | PPUBANK[7] = &VROM[ data * 0x400 ]; 75 | } break; 76 | 77 | case 0x08: { 78 | if(!(data & 0x40)) { 79 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 80 | pNesX_DebugPrint("Map69: Set 0x6000-0x7FFF to Rom Page [%u]\n", data & 0x1f); 81 | // OK - this is really crappy, because the emulator wasn't architected to bank switch 0x6000 - 0x7FFF and just has a statically allocated buffer here 82 | // for now, just copy whatever page is bank swapped into the SRAM buffer so that everything works. This is way slower than just adjusting a bank pointer. 83 | memcpy(SRAM, ROMPAGE((data & 0x1f) % num_8k_ROM_banks), 0x2000); 84 | } 85 | } break; 86 | 87 | case 0x09: { 88 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 89 | pNesX_DebugPrint("Map69: Set ROMBANK0 to Rom Page [%u]\n", data & 0x1f); 90 | ROMBANK0 = ROMPAGE((data & 0x1f) % num_8k_ROM_banks); 91 | } break; 92 | 93 | case 0x0A: { 94 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 95 | pNesX_DebugPrint("Map69: Set ROMBANK1 to Rom Page [%u]\n", data & 0x1f); 96 | ROMBANK1 = ROMPAGE((data & 0x1f) % num_8k_ROM_banks); 97 | } break; 98 | 99 | case 0x0B: { 100 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 101 | pNesX_DebugPrint("Map69: Set ROMBANK2 to Rom Page [%u]\n", data & 0x1f); 102 | ROMBANK2 = ROMPAGE((data & 0x1f) % num_8k_ROM_banks); 103 | } break; 104 | 105 | case 0x0C: { 106 | data &= 0x03; 107 | if (data == 0) { 108 | pNesX_DebugPrint("Map69: Set Mirroring to Vertical\n"); 109 | pNesX_Mirroring(MIRRORING_VERTICAL); 110 | } else if(data == 1) { 111 | pNesX_DebugPrint("Map69: Set Mirroring to Horizontal\n"); 112 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 113 | } else if(data == 2) { 114 | pNesX_DebugPrint("Map69: Set Mirroring to Single Screen Low\n"); 115 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 116 | } else { 117 | pNesX_DebugPrint("Map69: Set Mirroring to Single Screen High\n"); 118 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 119 | } 120 | } break; 121 | 122 | case 0x0D: { 123 | pNesX_DebugPrint("Map69: Set Irq Enabled to [%u]\n", data); 124 | Mapper_69_irq_enabled = data; 125 | } break; 126 | 127 | case 0x0E: { 128 | pNesX_DebugPrint("Map69: Set Irq Counter Low Byte to [%u]\n", data); 129 | Mapper_69_irq_counter = (Mapper_69_irq_counter & 0xFF00) | data; 130 | } break; 131 | 132 | case 0x0F: { 133 | pNesX_DebugPrint("Map69: Set Irq Counter High Byte to [%u]\n", data); 134 | Mapper_69_irq_counter = (Mapper_69_irq_counter & 0x00FF) | (data << 8); 135 | } break; 136 | } 137 | } break; 138 | 139 | case 0xC000: 140 | case 0xE000: { 141 | ex_write(addr, data); 142 | } break; 143 | } 144 | } 145 | 146 | void Mapper_69_HSync() { 147 | if (Mapper_69_irq_enabled) { 148 | if (Mapper_69_irq_counter <= 113) { 149 | IRQ_REQ; 150 | Mapper_69_irq_counter = 0; 151 | } else { 152 | Mapper_69_irq_counter -= 113; 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Mapper_69.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_69_H 2 | #define _MAPPER_69_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_69_Init(); 7 | void Mapper_69_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_69_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_7.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_7.h" 2 | 3 | /*-------------------------------------------------------------------*/ 4 | /* Mapper 7 Init Function */ 5 | /*-------------------------------------------------------------------*/ 6 | void Mapper_7_Init() { 7 | int nPage; 8 | 9 | ROMBANK0 = ROMPAGE( 0 ); 10 | ROMBANK1 = ROMPAGE( 1 ); 11 | ROMBANK2 = ROMPAGE( 2 ); 12 | ROMBANK3 = ROMPAGE( 3 ); 13 | 14 | for ( nPage = 0; nPage < 8; ++nPage ) 15 | PPUBANK[ nPage ] = &PPURAM[ nPage * 0x400 ]; 16 | 17 | /* Set up wiring of the interrupt pin */ 18 | K6502_Set_Int_Wiring( 1, 1 ); 19 | } 20 | 21 | /*-------------------------------------------------------------------*/ 22 | /* Mapper 7 Write Function */ 23 | /*-------------------------------------------------------------------*/ 24 | void Mapper_7_Write(uint16 wAddr, unsigned char byData) { 25 | // printf("Map7_Write: $%04X, %02X\n", wAddr, byData); 26 | unsigned char bank; 27 | 28 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 29 | bank = ((byData & 0x07) << 2) % num_8k_ROM_banks; 30 | // printf("Setting ROM Bank to [%i]\n", bank); 31 | 32 | ROMBANK0 = ROMPAGE( bank ); 33 | ROMBANK1 = ROMPAGE( bank + 1 ); 34 | ROMBANK2 = ROMPAGE( bank + 2 ); 35 | ROMBANK3 = ROMPAGE( bank + 3 ); 36 | 37 | if (byData & 0x10) { 38 | // printf("Setting ROM Mirroring to 1,1,1,1\n"); 39 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 40 | } else { 41 | // printf("Setting ROM Mirroring to 0,0,0,0\n"); 42 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 43 | } 44 | } -------------------------------------------------------------------------------- /Mapper_7.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_7_H 2 | #define _MAPPER_7_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_7_Init(); 7 | void Mapper_7_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_73.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_73.h" 2 | 3 | uint8 Mapper_73_irq_enabled; 4 | uint32 Mapper_73_irq_counter; 5 | 6 | void Mapper_73_Init() { 7 | ROMBANK0 = ROMPAGE( 0 ); 8 | ROMBANK1 = ROMPAGE( 1 ); 9 | ROMBANK2 = ROMLASTPAGE( 1 ); 10 | ROMBANK3 = ROMLASTPAGE( 0 ); 11 | 12 | Mapper_73_irq_counter = 0; 13 | Mapper_73_irq_enabled = 0; 14 | } 15 | 16 | void Mapper_73_Write( uint16 wAddr, unsigned char byData ) { 17 | switch (wAddr) { 18 | case 0x8000: { 19 | Mapper_73_irq_counter = (Mapper_73_irq_counter & 0xFFF0) | (byData & 0x0F); 20 | } break; 21 | 22 | case 0x9000: { 23 | Mapper_73_irq_counter = (Mapper_73_irq_counter & 0xFF0F) | ((byData & 0x0F) << 4); 24 | } break; 25 | 26 | case 0xA000: { 27 | Mapper_73_irq_counter = (Mapper_73_irq_counter & 0xF0FF) | ((byData & 0x0F) << 8); 28 | } break; 29 | 30 | case 0xB000: { 31 | Mapper_73_irq_counter = (Mapper_73_irq_counter & 0x0FFF) | ((byData & 0x0F) << 12); 32 | } break; 33 | 34 | case 0xC000: { 35 | Mapper_73_irq_enabled = byData; 36 | } break; 37 | 38 | case 0xF000: { 39 | uint32 num_8k_ROM_banks = NesHeader.byRomSize * 2; 40 | ROMBANK0 = ROMPAGE((byData*2) % num_8k_ROM_banks); 41 | ROMBANK1 = ROMPAGE((byData*2+1) % num_8k_ROM_banks); 42 | } break; 43 | } 44 | } 45 | 46 | void Mapper_73_HSync() { 47 | if (Mapper_73_irq_enabled & 0x02) { 48 | if (Mapper_73_irq_counter > 0xFFFF - 114) { 49 | IRQ_REQ; 50 | Mapper_73_irq_enabled = 0; 51 | } else { 52 | Mapper_73_irq_counter += 114; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Mapper_73.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_73_H 2 | #define _MAPPER_73_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_73_Init(); 7 | void Mapper_73_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_73_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_75.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_75.h" 2 | 3 | uint8 Mapper_75_regs[2]; 4 | 5 | void Mapper_75_Init() { 6 | ROMBANK0 = ROMPAGE( 0 ); 7 | ROMBANK1 = ROMPAGE( 1 ); 8 | ROMBANK2 = ROMLASTPAGE( 1 ); 9 | ROMBANK3 = ROMLASTPAGE( 0 ); 10 | 11 | if ( NesHeader.byVRomSize > 0 ) { 12 | for ( int nPage = 0; nPage < 8; ++nPage ) 13 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 14 | } 15 | 16 | Mapper_75_regs[0] = 0; 17 | Mapper_75_regs[1] = 1; 18 | } 19 | 20 | void Mapper_75_Write( uint16 wAddr, unsigned char byData ) { 21 | switch(wAddr & 0xF000) { 22 | case 0x8000: { 23 | ROMBANK0 = ROMPAGE(byData); 24 | } break; 25 | 26 | case 0x9000: { 27 | if (byData & 0x01) { 28 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 29 | } else { 30 | pNesX_Mirroring(MIRRORING_VERTICAL); 31 | } 32 | Mapper_75_regs[0] = (Mapper_75_regs[0] & 0x0F) | ((byData & 0x02) << 3); 33 | PPUBANK[0] = &VROM[ (Mapper_75_regs[0] * 4) * 0x400 ]; 34 | PPUBANK[1] = &VROM[ ((Mapper_75_regs[0] * 4) + 1) * 0x400 ]; 35 | PPUBANK[2] = &VROM[ ((Mapper_75_regs[0] * 4) + 2) * 0x400 ]; 36 | PPUBANK[3] = &VROM[ ((Mapper_75_regs[0] * 4) + 3) * 0x400 ]; 37 | Mapper_75_regs[1] = (Mapper_75_regs[1] & 0x0F) | ((byData & 0x04) << 2); 38 | PPUBANK[4] = &VROM[ (Mapper_75_regs[1] * 4) * 0x400 ]; 39 | PPUBANK[5] = &VROM[ ((Mapper_75_regs[1] * 4) + 1) * 0x400 ]; 40 | PPUBANK[6] = &VROM[ ((Mapper_75_regs[1] * 4) + 2) * 0x400 ]; 41 | PPUBANK[7] = &VROM[ ((Mapper_75_regs[1] * 4) + 3) * 0x400 ]; 42 | } break; 43 | 44 | case 0xA000: { 45 | ROMBANK1 = ROMPAGE(byData); 46 | } break; 47 | 48 | case 0xC000: { 49 | ROMBANK2 = ROMPAGE(byData); 50 | } break; 51 | 52 | case 0xE000: { 53 | Mapper_75_regs[0] = (Mapper_75_regs[0] & 0x10) | (byData & 0x0F); 54 | PPUBANK[0] = &VROM[ (Mapper_75_regs[0] * 4) * 0x400 ]; 55 | PPUBANK[1] = &VROM[ ((Mapper_75_regs[0] * 4) + 1) * 0x400 ]; 56 | PPUBANK[2] = &VROM[ ((Mapper_75_regs[0] * 4) + 2) * 0x400 ]; 57 | PPUBANK[3] = &VROM[ ((Mapper_75_regs[0] * 4) + 3) * 0x400 ]; 58 | } break; 59 | 60 | case 0xF000: { 61 | Mapper_75_regs[1] = (Mapper_75_regs[1] & 0x10) | (byData & 0x0F); 62 | PPUBANK[4] = &VROM[ (Mapper_75_regs[1] * 4) * 0x400 ]; 63 | PPUBANK[5] = &VROM[ ((Mapper_75_regs[1] * 4) + 1) * 0x400 ]; 64 | PPUBANK[6] = &VROM[ ((Mapper_75_regs[1] * 4) + 2) * 0x400 ]; 65 | PPUBANK[7] = &VROM[ ((Mapper_75_regs[1] * 4) + 3) * 0x400 ]; 66 | } break; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Mapper_75.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_75_H 2 | #define _MAPPER_75_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_75_Init(); 7 | void Mapper_75_Write( uint16 wAddr, unsigned char byData ); 8 | 9 | #endif -------------------------------------------------------------------------------- /Mapper_85.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_85.h" 2 | 3 | #include "nes_apu.h" 4 | 5 | unsigned char Mapper_85_irq_enabled; 6 | unsigned char Mapper_85_irq_counter; 7 | unsigned char Mapper_85_irq_latch; 8 | 9 | void Mapper_85_Init() { 10 | apu_set_exsound(NES_APU_EXSOUND_VRC7); 11 | 12 | // set CPU bank pointers 13 | ROMBANK0 = ROMPAGE(0); 14 | ROMBANK1 = ROMPAGE(1); 15 | ROMBANK2 = ROMLASTPAGE(1); 16 | ROMBANK3 = ROMLASTPAGE(0); 17 | 18 | for ( int nPage = 0; nPage < 8; ++nPage ) 19 | PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ]; 20 | 21 | Mapper_85_irq_enabled = 0; 22 | Mapper_85_irq_counter = 0; 23 | Mapper_85_irq_latch = 0; 24 | } 25 | 26 | void Mapper_85_Write(uint16 addr, uint8 data) { 27 | switch(addr & 0xF038) { 28 | case 0x8000: { 29 | ROMBANK0 = ROMPAGE(data); 30 | } break; 31 | 32 | case 0x8008: 33 | case 0x8010: { 34 | ROMBANK1 = ROMPAGE(data); 35 | } break; 36 | 37 | case 0x9000: { 38 | ROMBANK2 = ROMPAGE(data); 39 | } 40 | break; 41 | 42 | case 0x9010: 43 | case 0x9030: { 44 | ex_write(addr, data); 45 | } break; 46 | 47 | case 0xA000: { 48 | PPUBANK[ 0 ] = &VROM[ data * 0x400 ]; 49 | } break; 50 | 51 | case 0xA008: 52 | case 0xA010: { 53 | PPUBANK[ 1 ] = &VROM[ data * 0x400 ]; 54 | } break; 55 | 56 | case 0xB000: { 57 | PPUBANK[ 2 ] = &VROM[ data * 0x400 ]; 58 | } break; 59 | 60 | case 0xB008: 61 | case 0xB010: { 62 | PPUBANK[ 3 ] = &VROM[ data * 0x400 ]; 63 | } break; 64 | 65 | case 0xC000: { 66 | PPUBANK[ 4 ] = &VROM[ data * 0x400 ]; 67 | } break; 68 | 69 | case 0xC008: 70 | case 0xC010: { 71 | PPUBANK[ 5 ] = &VROM[ data * 0x400 ]; 72 | } break; 73 | 74 | case 0xD000: { 75 | PPUBANK[ 6 ] = &VROM[ data * 0x400 ]; 76 | } break; 77 | 78 | case 0xD008: 79 | case 0xD010: { 80 | PPUBANK[ 7 ] = &VROM[ data * 0x400 ]; 81 | } break; 82 | 83 | case 0xE000: { 84 | data &= 0x03; 85 | if (data == 0x00) { 86 | pNesX_Mirroring(MIRRORING_VERTICAL); 87 | } else if(data == 0x01) { 88 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 89 | } else if(data == 0x02) { 90 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_LOW); 91 | } else { 92 | pNesX_Mirroring(MIRRORING_SINGLE_SCREEN_HIGH); 93 | } 94 | } break; 95 | 96 | case 0xE008: 97 | case 0xE010: { 98 | Mapper_85_irq_latch = data; 99 | } break; 100 | 101 | case 0xF000: { 102 | Mapper_85_irq_enabled = data & 0x03; 103 | if (Mapper_85_irq_enabled & 0x02) { 104 | Mapper_85_irq_counter = Mapper_85_irq_latch; 105 | } 106 | } break; 107 | 108 | case 0xF008: 109 | case 0xF010: { 110 | Mapper_85_irq_enabled = (Mapper_85_irq_enabled & 0x01) * 3; 111 | } break; 112 | } 113 | } 114 | 115 | void Mapper_85_HSync() { 116 | if (Mapper_85_irq_enabled & 0x02) { 117 | if (Mapper_85_irq_counter == 0xFF) { 118 | IRQ_REQ; 119 | Mapper_85_irq_counter = Mapper_85_irq_latch; 120 | } else { 121 | Mapper_85_irq_counter++; 122 | } 123 | } 124 | } 125 | 126 | -------------------------------------------------------------------------------- /Mapper_85.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_85_H 2 | #define _MAPPER_85_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_85_Init(); 7 | void Mapper_85_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_85_HSync(); 9 | 10 | #endif -------------------------------------------------------------------------------- /Mapper_9.c: -------------------------------------------------------------------------------- 1 | #include "Mapper_9.h" 2 | 3 | /*-------------------------------------------------------------------*/ 4 | /* Mapper 9 Variables */ 5 | /*-------------------------------------------------------------------*/ 6 | unsigned char Map9_Regs[6]; 7 | unsigned char Map9_Latch_0000; 8 | unsigned char Map9_Latch_1000; 9 | unsigned char Map9_bank1swap; 10 | unsigned char Map9_bank2swap; 11 | 12 | void Mapper_9_set_VROM_0000() { 13 | unsigned char bank_num; 14 | 15 | if (Map9_Latch_0000 == 0xFD) 16 | bank_num = Map9_Regs[1]; 17 | else 18 | bank_num = Map9_Regs[2]; 19 | 20 | bank_num <<= 2; 21 | pNesX_DebugPrint("Map9: Setting Sprite PPU Banks to %u, %u, %u, %u\n", bank_num, bank_num + 1, bank_num + 2, bank_num + 3); 22 | 23 | PPUBANK[0] = VROMPAGE( bank_num ); 24 | PPUBANK[1] = VROMPAGE( bank_num + 1 ); 25 | PPUBANK[2] = VROMPAGE( bank_num + 2 ); 26 | PPUBANK[3] = VROMPAGE( bank_num + 3 ); 27 | } 28 | 29 | void Mapper_9_set_VROM_1000() { 30 | unsigned char bank_num; 31 | 32 | if (Map9_Latch_1000 == 0xFD) 33 | bank_num = Map9_Regs[3]; 34 | else 35 | bank_num = Map9_Regs[4]; 36 | 37 | bank_num <<= 2; 38 | pNesX_DebugPrint("Map9: Setting Character PPU Banks to %u, %u, %u, %u\n", bank_num, bank_num + 1, bank_num + 2, bank_num + 3); 39 | 40 | PPUBANK[4] = VROMPAGE( bank_num ); 41 | PPUBANK[5] = VROMPAGE( bank_num + 1 ); 42 | PPUBANK[6] = VROMPAGE( bank_num + 2 ); 43 | PPUBANK[7] = VROMPAGE( bank_num + 3 ); 44 | } 45 | 46 | void Mapper_9_PPU_Latch_FDFE(uint16 wAddr) { 47 | unsigned char latch = (wAddr & 0x0FF0) >> 4; 48 | if (wAddr & 0x1000) { 49 | if (latch != Map9_Latch_1000) { 50 | pNesX_DebugPrint("Map9: Latching BG Addr [0x%04x] on Scanline [%li]\n", wAddr, ppuinfo.PPU_Scanline); 51 | Map9_Latch_1000 = latch; 52 | Mapper_9_set_VROM_1000(); 53 | } 54 | } else { 55 | if (latch != Map9_Latch_0000) { 56 | pNesX_DebugPrint("Map9: Latching Spr Addr [0x%04x] on Scanline [%li]\n", wAddr, ppuinfo.PPU_Scanline); 57 | Map9_Latch_0000 = (wAddr & 0x0FF0) >> 4; 58 | Mapper_9_set_VROM_0000(); 59 | } 60 | } 61 | } 62 | 63 | /*-------------------------------------------------------------------*/ 64 | /* Mapper 9 Init Function */ 65 | /*-------------------------------------------------------------------*/ 66 | void Mapper_9_Init() { 67 | // set ROM bank pointers 68 | ROMBANK0 = ROMPAGE(0); 69 | ROMBANK1 = ROMLASTPAGE(2); 70 | ROMBANK2 = ROMLASTPAGE(1); 71 | ROMBANK3 = ROMLASTPAGE(0); 72 | 73 | // clean out the registers 74 | Map9_Regs[0] = 0; 75 | Map9_Regs[1] = 0; 76 | Map9_Regs[2] = 4; 77 | Map9_Regs[3] = 0; 78 | Map9_Regs[4] = 0; 79 | Map9_Regs[5] = 0; 80 | 81 | Map9_Latch_0000 = 0xFE; 82 | Map9_Latch_1000 = 0xFE; 83 | 84 | Mapper_9_set_VROM_0000(); 85 | Mapper_9_set_VROM_1000(); 86 | 87 | /* Set up wiring of the interrupt pin */ 88 | K6502_Set_Int_Wiring( 1, 1 ); 89 | } 90 | 91 | void Mapper_9_Write(uint16 wAddr, unsigned char byData) { 92 | switch(wAddr & 0xF000) { 93 | case 0xA000: { 94 | // 8K ROM bank at $8000 95 | Map9_Regs[0] = byData & 0x0F; 96 | ROMBANK0 = ROMPAGE(Map9_Regs[0]); 97 | pNesX_DebugPrint("Map9: Setting ROMBANK0 to Page [%u]\n", Map9_Regs[0]); 98 | } break; 99 | 100 | case 0xB000: { 101 | // B000-BFFF: select 4k VROM for (0000) $FD latch 102 | Map9_Regs[1] = byData & 0x1F; 103 | pNesX_DebugPrint("Map9: Setting VROM for Sprite $FD Latch to Page [%u]\n", Map9_Regs[1]); 104 | Mapper_9_set_VROM_0000(); 105 | } break; 106 | 107 | case 0xC000: { 108 | // C000-CFFF: select 4k VROM for (0000) $FE latch 109 | Map9_Regs[2] = byData & 0x1F; 110 | pNesX_DebugPrint("Map9: Setting VROM for Sprite $FE Latch to Page [%u]\n", Map9_Regs[2]); 111 | Mapper_9_set_VROM_0000(); 112 | } break; 113 | 114 | case 0xD000: { 115 | // D000-DFFF: select 4k VROM for (1000) $FD latch 116 | Map9_Regs[3] = byData & 0x1F; 117 | pNesX_DebugPrint("Map9: Setting VROM for Character $FD Latch to Page [%u]\n", Map9_Regs[3]); 118 | Mapper_9_set_VROM_1000(); 119 | } break; 120 | 121 | case 0xE000: { 122 | // E000-EFFF: select 4k VROM for (1000) $FE latch 123 | Map9_Regs[4] = byData & 0x1F; 124 | pNesX_DebugPrint("Map9: Setting VROM for Character $FE Latch to Page [%u]\n", Map9_Regs[4]); 125 | Mapper_9_set_VROM_1000(); 126 | } break; 127 | 128 | case 0xF000: { 129 | Map9_Regs[5] = byData; 130 | if (Map9_Regs[5] & 0x01) { 131 | //Horizontal Mirror 132 | pNesX_DebugPrint("Map9: Setting Mirroring to Horizontal\n"); 133 | pNesX_Mirroring(MIRRORING_HORIZONTAL); 134 | } else { 135 | //Vertical Mirror 136 | pNesX_DebugPrint("Map9: Setting Mirroring to Vertical\n"); 137 | pNesX_Mirroring(MIRRORING_VERTICAL); 138 | } 139 | } break; 140 | } 141 | } -------------------------------------------------------------------------------- /Mapper_9.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAPPER_9_H 2 | #define _MAPPER_9_H 3 | 4 | #include "Mapper.h" 5 | 6 | void Mapper_9_Init(); 7 | void Mapper_9_Write( uint16 wAddr, unsigned char byData ); 8 | void Mapper_9_PPU_Latch_FDFE(uint16 wAddr); 9 | 10 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FrNES is an NES emulator for the Sega Dreamcast console. It was based around Racoon's pNESx emulator for the original PlayStation. 2 | 3 | In 2000, I had been working on a port of Hu-Go the PC Engine emulator to the Dreamcast and ran into a few issues with the port. I found the pNESx source online and decided to take my working menu code from the Hu-Go port and hook it up to the pNESx emulator core. The initial port took only a few hours to get running as the playstation code translated quite well to the libdream APIs which were available at the time. A month or so later I released the emulator to the DC Scene and spent the next year or so improving elements of the emulator. I added the Nofrendo sound code and implemented some of the more popular mappers, and called it quits after a Christmas release of the emulator in 2002. 4 | 5 | In 2013 I decided to dig out the source code and try to build it against KOS 2.0.0. Over the years I brought it up to date with modern KOS. I also eventually incorporated the VQFB technique for rendering, 6 | better sound code, a more modern file browser and fixed a number of CPU opcode and address mode issues. I released this updated version as version 0.7 on June 28, 2024. 7 | 8 | -------------------------------------------------------------------------------- /ROMLoad.c: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* ROMLoad.c : ROM Checksums an Read/Write/Checksum Operations */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | #include "ROMLoad.h" 10 | #include "macros.h" 11 | 12 | #include 13 | 14 | #include "GUI_SystemPage.h" 15 | #include "pNesX_System_DC.h" 16 | 17 | file_t my_file; 18 | dirent_t* my_dir; 19 | int numberOfRoms = 0; 20 | int currentindex; 21 | 22 | uint32 crc_32_tab[256] = { /* CRC polynomial 0xedb88320 */ 23 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 24 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 25 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 26 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 27 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 28 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 29 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 30 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 31 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 32 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 33 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 34 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 35 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 36 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 37 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 38 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 39 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 40 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 41 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 42 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 43 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 44 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 45 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 46 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 47 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 48 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 49 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 50 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 51 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 52 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 53 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 54 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 55 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 56 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 57 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 58 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 59 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 60 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 61 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 62 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 63 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 64 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 65 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 66 | }; 67 | 68 | const int id_size = 1; 69 | 70 | uint32 UPDC32 (unsigned char octet, uint32 crc) { 71 | return ( ((crc) >> 8) ^ crc_32_tab [ (crc & 0x000000FF) ^ ((uint8) octet) ] ); 72 | } 73 | 74 | //Initializes a RomInfo array to the unread values 75 | void InitializeFileInfos(RomInfo_t* RomInfoArray, char** RomPtrArray, int NumBuffers) { 76 | printf("InitializeFileInfos: clearing entries\n"); 77 | memset(RomInfoArray, 0, sizeof(RomInfo_t) * NumBuffers); 78 | for (int i = 0; i < NumBuffers; i++) { 79 | RomPtrArray[i] = RomInfoArray[i].FileName; 80 | } 81 | }; 82 | 83 | //Start the Search Process 84 | int StartFileSearch(char* Path, RomInfo_t* RomInfoArray) { 85 | printf("StartFileSearch: beginning search\n"); 86 | 87 | my_file = fs_open(Path, O_DIR); 88 | if (my_file == -1) { 89 | printf("StartFileSearch: error unable to open directory\n"); 90 | return 0; 91 | } else { 92 | printf("StartFileSearch: directory opened successfully\n"); 93 | numberOfRoms = 0; 94 | currentindex = 0; 95 | // The cd interface doesn't put .. into the root directory list at any level 96 | // and the sd interface only does it in subdirectories, so add it here for consistency 97 | if ((strstr(Path, "/cd") == Path) || (strcmp(Path, "/sd/") == 0)) { 98 | strcpy(RomInfoArray[currentindex].FileName, ",DIR"); 99 | strcpy(RomInfoArray[currentindex].PhysFileName, ".."); 100 | RomInfoArray[currentindex].IsRead = 1; 101 | currentindex++; 102 | numberOfRoms++; 103 | } 104 | return 1; 105 | } 106 | }; 107 | 108 | void EndFileSearch() { 109 | printf("EndFileSearch: closing directory\n"); 110 | if (fs_close(my_file) == -1) { 111 | printf("EndFileSearch: error, unable to close directory\n"); 112 | } 113 | currentindex = 0; 114 | } 115 | 116 | int ReturnCurrentNumRoms() { 117 | return numberOfRoms; 118 | } 119 | 120 | //Loads a fileinfo 121 | int LoadNextFileSimple(RomInfo_t* RomInfoArray, char* current_path) { 122 | // printf("LoadNextFileSimple: reading directory\n"); 123 | my_dir = fs_readdir(my_file); 124 | if (my_dir != NULL) { 125 | // printf("LoadNextFileSimple: returned new entry [%s] with attributes [%lX]\n", my_dir -> name, my_dir -> attr); 126 | if (my_dir -> attr & 0x1000) { 127 | if (strcmp(my_dir -> name, "..") == 0) { 128 | strcpy(RomInfoArray[currentindex].FileName, ",DIR"); 129 | strcpy(RomInfoArray[currentindex].PhysFileName, ".."); 130 | RomInfoArray[currentindex].IsRead = 1; 131 | currentindex++; 132 | numberOfRoms++; 133 | } else if (strcmp(my_dir -> name, ".") == 0) { 134 | 135 | } else { 136 | snprintf(RomInfoArray[currentindex].FileName, 65, "%s,%s", my_dir -> name, "DIR"); 137 | strcat(RomInfoArray[currentindex].PhysFileName, my_dir -> name); 138 | RomInfoArray[currentindex].IsRead = 1; 139 | currentindex++; 140 | numberOfRoms++; 141 | } 142 | } else if ((strstr(my_dir -> name, ".nes") != NULL) || (strstr(my_dir -> name, ".NES") != NULL)) { 143 | RomInfoArray[currentindex].FileSize = my_dir -> size; 144 | strcpy(RomInfoArray[currentindex].FileName, my_dir -> name); 145 | strcpy(RomInfoArray[currentindex].PhysFileName, current_path); 146 | strcat(RomInfoArray[currentindex].PhysFileName, my_dir -> name); 147 | RomInfoArray[currentindex].IsRead = 1; 148 | currentindex++; 149 | numberOfRoms++; 150 | } 151 | return 1; 152 | } else { 153 | return 0; 154 | } 155 | } 156 | 157 | uint32 ReturnChecksum(const char* filepath, uint32 filesize, unsigned char* temprom) { 158 | printf("ReturnChecksum: calculating crc32 of ROM image [%s]\n", filepath); 159 | uint32 my_fd; 160 | uint32 oldcrc32; 161 | int i; 162 | 163 | printf("ReturnChecksum: loading ROM image into buffer\n"); 164 | my_fd = fs_open(filepath, O_RDONLY); 165 | if (my_fd == -1) { 166 | printf("ReturnChecksum: failed to open ROM image with error [%s]\n", strerror(errno)); 167 | return 0; 168 | } 169 | if (fs_read(my_fd, temprom, filesize) != filesize) { 170 | printf("ReturnChecksum: was not able to read ROM image from file system\n"); 171 | return 0; 172 | } 173 | if (fs_close(my_fd) == -1) { 174 | printf("ReturnChecksum: failed to close ROM image file handle\n"); 175 | return 0; 176 | } 177 | 178 | oldcrc32 = 0xFFFFFFFF; 179 | 180 | i = 16; 181 | 182 | for (; i < filesize; i++) { 183 | oldcrc32 = UPDC32 (temprom[i], oldcrc32); 184 | } 185 | 186 | oldcrc32 = oldcrc32 ^ 0xFFFFFFFF; 187 | printf("ReturnChecksum: returning CRC of [%08lx]\n", oldcrc32); 188 | 189 | return oldcrc32; 190 | } 191 | -------------------------------------------------------------------------------- /ROMLoad.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* ROMLoad.h : ROM Checksums an Read/Write/Checksum Operations */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | #ifndef __ROMLOAD_H 10 | #define __ROMLOAD_H 11 | 12 | #include 13 | #include "string.h" 14 | 15 | typedef struct __attribute__ ((packed, aligned(4))) RomInfo_s { 16 | char FileName[65]; 17 | char PhysFileName[65]; 18 | int FileSize; 19 | int IsRead; 20 | } RomInfo_t; 21 | 22 | typedef struct { 23 | char FileName[65]; 24 | uint32 CheckSum; 25 | } RomCheck; 26 | 27 | //Initializes a RomInfo array to the unread values 28 | void InitializeFileInfos(RomInfo_t* RomInfoArray, char** RomPtrArray, int NumBuffers); 29 | 30 | //Start the Search Process 31 | int StartFileSearch(char* Path, RomInfo_t* RomInfoArray); 32 | 33 | //End the Search Process 34 | void EndFileSearch(); 35 | 36 | //Return the Number of Roms found 37 | int ReturnCurrentNumRoms(); 38 | 39 | //Loads a file info without using checksum identification 40 | int LoadNextFileSimple(RomInfo_t* RomInfoArray, char* current_path); 41 | 42 | //Loads a file info using checksum identification 43 | int LoadNextFileComplex(RomInfo_t* RomInfoArray); 44 | 45 | uint32 ReturnChecksum(const char* filepath, uint32 filesize, unsigned char* temprom); 46 | 47 | #endif -------------------------------------------------------------------------------- /TextWindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: TextWindow.h 3 | Project: Platform Development Tools 4 | Date: December. 18th, 2000 5 | Programmer: ReGex 6 | Description: A set of functions to draw a text window suitable for a GUI 7 | */ 8 | 9 | #ifndef __TEXT_WINDOW_H 10 | #define __TEXT_WINDOW_H 11 | 12 | #include 13 | #include 14 | #include "font.h" 15 | 16 | #define CIRCLE_TRIANGLES 64 17 | #define CORNER_TRIANGLES 16 18 | #define CORNER_RADIUS 16 19 | 20 | typedef struct 21 | { 22 | //Visual Style Options 23 | float Border_Thickness; 24 | float Header_Text_Scale; 25 | float Text_Scale; 26 | int Max_Items; 27 | int Use_Header; 28 | 29 | //Colors to Use 30 | uint32 Border_Color; 31 | uint32 Inside_Color; 32 | uint32 Header_Text_Color; 33 | uint32 Selected_Text_Color; 34 | uint32 Selected_Background_Color; 35 | uint32 Text_Color; 36 | 37 | //Margin Info 38 | float Left_Margin; 39 | float Line_Spacing; 40 | 41 | //Not Implemented Yet -- Probably Never Will Be Either :D 42 | int IsTransparent; 43 | int IsAnimating; 44 | int Animation_Mode; 45 | } Window_Style; 46 | 47 | typedef struct 48 | { 49 | //Physical Window Position Attributes 50 | float x; 51 | float y; 52 | float width; 53 | float height; 54 | 55 | //Data Attributes 56 | char* Header_Text; 57 | char** Data_Strings; 58 | 59 | //The Top Index of the Window 60 | int Top_Index; 61 | int Num_Strings; 62 | 63 | //Index of the highlighted string 64 | int Highlighted_Index; 65 | 66 | //Font Attributes 67 | Font* font; 68 | } Window_Data; 69 | 70 | void win_draw_textwindow (Window_Data* windata, Window_Style* winstyle, uint32 list); 71 | 72 | #endif -------------------------------------------------------------------------------- /aica_fw.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* aica_fw.h : Header for Dreamcast AICA firmware for FrNES 0.60 */ 4 | /* */ 5 | /* 2001/12/22 ReGex 0.60 Final Release */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | 10 | #ifndef __AICA_FW 11 | #define __AICA_FW 12 | 13 | extern unsigned char aica_fw[]; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /font.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: BMFont.h 3 | Project: Platform Development Tools 4 | Date: Sept. 24, 2014 5 | Author: Matt Slevinsky 6 | Based on http://www.angelcode.com/dev/bmfonts/ 7 | Description: Bitmap Font Library that is compatible with angelcode's BMF compiler 8 | */ 9 | 10 | #ifndef __BMFFONT_H 11 | #define __BMFFONT_H 12 | 13 | #include 14 | #include "uthash.h" 15 | #include "utarray.h" 16 | 17 | typedef enum EFontTextEncoding { 18 | NONE, 19 | UTF8, 20 | UTF16 21 | } EFontTextEncoding; 22 | 23 | typedef enum LineRenderMode { 24 | SINGLE, 25 | MULTILINE 26 | } LineRenderMode; 27 | 28 | typedef enum TextAlignmentMode { 29 | LEFT, 30 | CENTER, 31 | RIGHT 32 | } TextAlignmentMode; 33 | 34 | typedef struct KerningPair { 35 | uint32 first; 36 | uint32 second; 37 | int16 amount; 38 | } KerningPair; 39 | 40 | typedef struct CharDescriptor { 41 | uint32 id; 42 | int16 srcX; 43 | int16 srcY; 44 | int16 srcW; 45 | int16 srcH; 46 | int16 xOff; 47 | int16 yOff; 48 | int16 xAdv; 49 | int16 page; 50 | unsigned int chnl; 51 | 52 | UT_array* kerningPairs; 53 | UT_hash_handle hh; 54 | } CharDescriptor; 55 | 56 | typedef struct FontPage { 57 | uint16 width; 58 | uint16 height; 59 | pvr_ptr_t texture; 60 | } FontPage; 61 | 62 | typedef struct Font { 63 | uint16 fontHeight; // total height of the font 64 | uint16 base; // y of base line 65 | uint16 scaleW; 66 | uint16 scaleH; 67 | CharDescriptor* defChar; 68 | int hasOutline; 69 | 70 | float scale; 71 | EFontTextEncoding encoding; 72 | 73 | CharDescriptor* characters; 74 | UT_array* pages; 75 | } Font; 76 | 77 | Font* load_font(const char* filepath); 78 | void draw_string(Font* font, int currentList, char* string, float xPos, float yPos, float zPos, float width, float height, LineRenderMode lineRenderMode, TextAlignmentMode textAlignmentMode, uint32 color, float scale); 79 | //void measure_line(char* string, uint16* width, uint16* height); 80 | //void measure_string(char* string, uint16* width, uint16* height, LineRenderMode lineRenderMode, TextAlignmentMode textAlignmentMode); 81 | void destroy_font(Font* font); 82 | 83 | #endif -------------------------------------------------------------------------------- /input_recorder.c: -------------------------------------------------------------------------------- 1 | #include "input_recorder.h" 2 | 3 | extern uint32 numEmulationFrames; 4 | extern uint32 currentCRC32; 5 | 6 | uint32 currentSample; 7 | uint32 numSamples; 8 | InputFrame_t frameInputs[MAXIMUM_INPUT_FRAMES]; 9 | 10 | void resetRecording() { 11 | currentSample = 0; 12 | numSamples = 0; 13 | memset(frameInputs, 0, sizeof(InputFrame_t) * MAXIMUM_INPUT_FRAMES); 14 | } 15 | 16 | void recordInput(InputFrame_t* input) { 17 | memcpy(&frameInputs[currentSample], input, sizeof(InputFrame_t)); 18 | currentSample++; 19 | numSamples = currentSample; 20 | } 21 | 22 | void printRecording() { 23 | for (uint32 frameIndex = 0; frameIndex < numSamples; frameIndex++) { 24 | printf("Index [%lu]: Button [%u] Start [%lu] Duration [%u]\n", frameIndex, frameInputs[frameIndex].button, frameInputs[frameIndex].frameStart, frameInputs[frameIndex].frameDuration); 25 | } 26 | } 27 | 28 | void sortInputFrames() { 29 | printf("Sorting [%lu] frames\n", numSamples); 30 | if (numSamples > 0) { 31 | for (uint32 frameIndex = 0; frameIndex < numSamples - 1; frameIndex++) { 32 | uint32 minimumFrameStart = frameInputs[frameIndex].frameStart; 33 | uint32 minimumFrameIndex = frameIndex; 34 | for (uint32 nextIndex = frameIndex + 1; nextIndex < numSamples; nextIndex++) { 35 | if (frameInputs[nextIndex].frameStart < minimumFrameStart) { 36 | minimumFrameStart = frameInputs[nextIndex].frameStart; 37 | minimumFrameIndex = nextIndex; 38 | } 39 | } 40 | if (minimumFrameIndex != frameIndex) { 41 | InputFrame_t temp; 42 | memcpy(&temp, &frameInputs[frameIndex], sizeof(InputFrame_t)); 43 | memcpy(&frameInputs[frameIndex], &frameInputs[minimumFrameIndex], sizeof(InputFrame_t)); 44 | memcpy(&frameInputs[minimumFrameIndex], &temp, sizeof(InputFrame_t)); 45 | } 46 | } 47 | } 48 | 49 | printRecording(); 50 | } 51 | 52 | void uploadRecording() { 53 | printf("Uploading Input Recording to PC Host\n"); 54 | sortInputFrames(); 55 | 56 | char PCPath[256]; 57 | snprintf(PCPath, 256, "/pc/Users/maslevin/Documents/Projects/numechanix/frnes/%08lX_recording.inp", currentCRC32); 58 | file_t PCFile = fs_open(PCPath, O_WRONLY); 59 | if (PCFile != -1) { 60 | fs_write(PCFile, frameInputs, currentSample * sizeof(InputFrame_t)); 61 | fs_close(PCFile); 62 | printf("Closed file on PC\n"); 63 | } else { 64 | printf("Error: Unable to Open File on PC Host\n"); 65 | } 66 | } 67 | 68 | bool loadRecording() { 69 | printf("Loading Input Recording from PC Host\n"); 70 | char PCPath[256]; 71 | snprintf(PCPath, 256, "/pc/Users/maslevin/Documents/Projects/numechanix/frnes/%08lX_recording.inp", currentCRC32); 72 | file_t PCFile = fs_open(PCPath, O_RDONLY); 73 | if (PCFile != -1) { 74 | uint32 size = fs_read(PCFile, frameInputs, MAXIMUM_INPUT_FRAMES * sizeof(InputFrame_t)); 75 | currentSample = 0; 76 | numSamples = size / sizeof(InputFrame_t); 77 | printf("Read Recording containing [%lu] samples\n", numSamples); 78 | fs_close(PCFile); 79 | 80 | printRecording(); 81 | printf("Closed file on PC\n"); 82 | return true; 83 | } else { 84 | printf("Error: Unable to Open File on PC Host\n"); 85 | } 86 | 87 | return false; 88 | } -------------------------------------------------------------------------------- /input_recorder.h: -------------------------------------------------------------------------------- 1 | #ifndef _INPUT_RECORDER_H 2 | #define _INPUT_RECORDER_H 3 | 4 | #include 5 | 6 | #define MAXIMUM_INPUT_FRAMES 131072 7 | 8 | #define CONTROLLER_BUTTON_A 0 9 | #define CONTROLLER_BUTTON_B 1 10 | #define CONTROLLER_BUTTON_SELECT 2 11 | #define CONTROLLER_BUTTON_START 3 12 | #define CONTROLLER_BUTTON_UP 4 13 | #define CONTROLLER_BUTTON_DOWN 5 14 | #define CONTROLLER_BUTTON_LEFT 6 15 | #define CONTROLLER_BUTTON_RIGHT 7 16 | 17 | typedef struct __attribute__ ((packed, aligned(4))) InputFrame_s { 18 | uint32 frameStart; 19 | uint16 frameDuration; 20 | uint8 controller; 21 | uint8 button; 22 | } InputFrame_t; 23 | 24 | extern uint32 currentSample; 25 | extern uint32 numSamples; 26 | extern InputFrame_t frameInputs[MAXIMUM_INPUT_FRAMES]; 27 | 28 | void resetRecording(); 29 | void recordInput(InputFrame_t* input); 30 | void uploadRecording(); 31 | bool loadRecording(); 32 | 33 | #endif -------------------------------------------------------------------------------- /macros.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG 2 | #pragma GCC diagnostic ignored "-Wunused-value" 3 | //#define printf(...) (0) 4 | #endif -------------------------------------------------------------------------------- /nes_exsound.h: -------------------------------------------------------------------------------- 1 | #ifndef _NES_EXSOUND_H 2 | #define _NES_EXSOUND_H 3 | 4 | #include 5 | 6 | int32 VRC6SoundRender(); 7 | void VRC6SoundWrite(uint32 address, uint8 value); 8 | void VRC6SoundReset(void); 9 | void VRC6SoundVolume(uint32 volume); 10 | 11 | int32 OPLLSoundRender(void); 12 | void OPLLSoundWrite(uint32 address, uint8 value); 13 | void OPLLSoundReset(void); 14 | void OPLLSoundVolume(uint32 volume); 15 | 16 | int32 FDSSoundRender(void); 17 | void FDSSoundWrite(uint32 address, uint8 value); 18 | void FDSSoundReset(void); 19 | void FDSSoundVolume(uint32 volume); 20 | uint8 FDSSoundRead(uint32 address); 21 | void FDSSoundWriteCurrent(uint32 address, uint8 value); 22 | 23 | int32 PSGSoundRender(void); 24 | void PSGSoundWrite(uint32 address, uint8 value); 25 | void PSGSoundReset(void); 26 | void PSGSoundVolume(uint32 volume); 27 | 28 | int32 MMC5SoundRender(void); 29 | void MMC5SoundWrite(uint32 address, uint8 value); 30 | void MMC5SoundReset(void); 31 | void MMC5SoundVolume(uint32 volume); 32 | 33 | int32 N106SoundRender(void); 34 | void N106SoundWrite(uint32 address, uint8 value); 35 | void N106SoundReset(void); 36 | void N106SoundVolume(uint32 volume); 37 | 38 | void LogTableInitialize(); 39 | 40 | #endif -------------------------------------------------------------------------------- /pNesX.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX.c : NES Emulator for PSX */ 4 | /* */ 5 | /* 1999/11/03 Racoon New preparation */ 6 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 7 | /* Slightly reorganized from pNesX version */ 8 | /* */ 9 | /*===================================================================*/ 10 | 11 | #ifndef PNESX_H_INCLUDED 12 | #define PNESX_H_INCLUDED 13 | 14 | /*-------------------------------------------------------------------*/ 15 | /* Include files */ 16 | /*-------------------------------------------------------------------*/ 17 | 18 | //#include "pNesX_Types.h" 19 | #include 20 | 21 | #include "Mapper.h" 22 | 23 | /*-------------------------------------------------------------------*/ 24 | /* NES resources */ 25 | /*-------------------------------------------------------------------*/ 26 | 27 | #define RAM_SIZE 0x2000 28 | #define SRAM_SIZE 0x2000 29 | #define PPURAM_SIZE 0x4000 30 | #define SPRRAM_SIZE 256 31 | 32 | /* RAM */ 33 | extern unsigned char RAM[]; 34 | 35 | /* SRAM */ 36 | extern unsigned char SRAM[]; 37 | 38 | /* ROM */ 39 | extern unsigned char *ROM; 40 | 41 | /* ROM BANK ( 8Kb * 4 ) */ 42 | extern unsigned char *ROMBANK0; 43 | extern unsigned char *ROMBANK1; 44 | extern unsigned char *ROMBANK2; 45 | extern unsigned char *ROMBANK3; 46 | 47 | /*-------------------------------------------------------------------*/ 48 | /* PPU resources */ 49 | /*-------------------------------------------------------------------*/ 50 | typedef struct __attribute__ ((packed, aligned(4))) PPU_Info_s { 51 | uint16 PPU_Addr; 52 | uint32 PPU_Scr_H_Bit; 53 | uint32 PPU_Scanline; 54 | uint32 PPU_SP_Height; 55 | uint32 PPU_R0; 56 | } PPU_Info; 57 | 58 | extern PPU_Info ppuinfo; 59 | 60 | /* PPU RAM */ 61 | extern unsigned char PPURAM[]; 62 | 63 | /* Cartridge VROM */ 64 | extern unsigned char *VROM; 65 | 66 | /* Cartridge VRAM */ 67 | extern unsigned char *VRAM; 68 | 69 | /* PPU BANK ( 1Kb * 16 ) */ 70 | extern unsigned char *PPUBANK[]; 71 | 72 | #define FRAMEBUFFER_WIDTH 256 73 | #define FRAMEBUFFER_HEIGHT 256 74 | 75 | //Here we define the size of a framebuffer texture we want 76 | #define FRAMEBUFFER_PIXELS (FRAMEBUFFER_WIDTH * FRAMEBUFFER_HEIGHT) 77 | 78 | //The codebook for a VQ texture is always 2048 bytes 79 | #define CODEBOOK_SIZE 2048 80 | 81 | typedef struct { 82 | unsigned char codebook[CODEBOOK_SIZE]; 83 | unsigned char texture[FRAMEBUFFER_PIXELS]; 84 | } VQ_Texture; 85 | 86 | /* Display Buffer */ 87 | #define NUM_PVR_FRAMES 3 88 | 89 | extern VQ_Texture* WorkFrame; 90 | extern uint16 WorkFrameIdx; 91 | extern VQ_Texture* WorkFrames[NUM_PVR_FRAMES]; 92 | extern uint8 codebook[CODEBOOK_SIZE]; 93 | 94 | #define NAME_TABLE0 8 95 | #define NAME_TABLE1 9 96 | #define NAME_TABLE2 10 97 | #define NAME_TABLE3 11 98 | 99 | #define NAME_TABLE_V_MASK 2 100 | #define NAME_TABLE_H_MASK 1 101 | 102 | /* Sprite RAM */ 103 | extern unsigned char SPRRAM[]; 104 | 105 | #define SPR_Y 0 106 | #define SPR_CHR 1 107 | #define SPR_ATTR 2 108 | #define SPR_X 3 109 | #define SPR_ATTR_COLOR 0x3 110 | #define SPR_ATTR_V_FLIP 0x80 111 | #define SPR_ATTR_H_FLIP 0x40 112 | #define SPR_ATTR_PRI 0x20 113 | 114 | /* PPU Register */ 115 | extern unsigned char PPU_R1; 116 | extern unsigned char PPU_R2; 117 | extern unsigned char PPU_R3; 118 | extern unsigned char PPU_R7; 119 | 120 | extern unsigned char PPU_Scr_V; 121 | extern unsigned char PPU_Scr_V_Next; 122 | extern unsigned char PPU_Scr_V_Byte_Next; 123 | extern unsigned char PPU_Scr_V_Bit_Next; 124 | 125 | extern unsigned char PPU_Scr_H; 126 | extern unsigned char PPU_Scr_H_Next; 127 | extern unsigned char PPU_Scr_H_Byte_Next; 128 | extern unsigned char PPU_Scr_H_Bit_Next; 129 | 130 | extern unsigned char PPU_Latch_Flag; 131 | extern uint16 PPU_Addr; 132 | extern uint16 PPU_Increment; 133 | extern uint16 PPU_Temp; 134 | extern unsigned char PPU_2007_Buffer; 135 | 136 | extern int SpriteJustHit; 137 | #define SPRITE_HIT_SENTINEL 255 138 | 139 | #define MIRRORING_HORIZONTAL 0 140 | #define MIRRORING_VERTICAL 1 141 | #define MIRRORING_FOUR_SCREEN 2 142 | #define MIRRORING_SINGLE_SCREEN_LOW 3 143 | #define MIRRORING_SINGLE_SCREEN_HIGH 4 144 | 145 | #define R0_NMI_VB 0x80 146 | #define R0_NMI_SP 0x40 147 | #define R0_SP_SIZE 0x20 148 | #define R0_BG_ADDR 0x10 149 | #define R0_SP_ADDR 0x08 150 | #define R0_INC_ADDR 0x04 151 | #define R0_NAME_ADDR 0x03 152 | 153 | #define R1_BACKCOLOR 0xe0 154 | #define R1_SHOW_SP 0x10 155 | #define R1_SHOW_SCR 0x08 156 | #define R1_CLIP_SP 0x04 157 | #define R1_CLIP_BG 0x02 158 | #define R1_MONOCHROME 0x01 159 | 160 | #define R2_IN_VBLANK 0x80 161 | #define R2_HIT_SP 0x40 162 | #define R2_MAX_SP 0x20 163 | #define R2_WRITE_FLAG 0x10 164 | 165 | /* NES display size */ 166 | #define NES_DISP_WIDTH 256 167 | #define NES_DISP_HEIGHT 224 168 | 169 | #ifdef DEBUG 170 | #define MAX_EXIT_COUNT 1 171 | #else 172 | #define MAX_EXIT_COUNT 50 173 | #endif 174 | 175 | /*-------------------------------------------------------------------*/ 176 | /* Display and Others resouces */ 177 | /*-------------------------------------------------------------------*/ 178 | extern float frames_per_second; 179 | 180 | /* Frame Skip */ 181 | extern uint16 FrameSkip; 182 | extern uint16 FrameCnt; 183 | 184 | /*-------------------------------------------------------------------*/ 185 | /* APU and Pad resources */ 186 | /*-------------------------------------------------------------------*/ 187 | 188 | extern unsigned char APU_Reg[]; 189 | 190 | extern uint32 PAD1_Latch; 191 | extern uint32 PAD2_Latch; 192 | extern uint32 ExitCount; 193 | extern uint32 PAD1_Bit; 194 | extern uint32 PAD2_Bit; 195 | 196 | #define PAD_SYS_QUIT 1 197 | #define PAD_SYS_OK 2 198 | #define PAD_SYS_CANCEL 4 199 | #define PAD_SYS_UP 8 200 | #define PAD_SYS_DOWN 0x10 201 | #define PAD_SYS_LEFT 0x20 202 | #define PAD_SYS_RIGHT 0x40 203 | 204 | #define PAD_PUSH(a,b) ( ( (a) & (b) ) != 0 ) 205 | 206 | /*-------------------------------------------------------------------*/ 207 | /* ROM information */ 208 | /*-------------------------------------------------------------------*/ 209 | 210 | /* .nes File Header */ 211 | struct NesHeader_tag { 212 | unsigned char byID[ 4 ]; 213 | unsigned char byRomSize; 214 | unsigned char byVRomSize; 215 | unsigned char byInfo1; 216 | unsigned char byInfo2; 217 | unsigned char byReserve[ 8 ]; 218 | }; 219 | 220 | /* .nes File Header */ 221 | extern struct NesHeader_tag NesHeader; 222 | 223 | /* Mapper No. */ 224 | struct Mapper; 225 | extern unsigned char MapperNo; 226 | 227 | /* Other */ 228 | extern unsigned char ROM_Mirroring; 229 | extern unsigned char ROM_SRAM; 230 | extern unsigned char ROM_Trainer; 231 | extern unsigned char ROM_FourScr; 232 | 233 | struct Timestamp_tag { 234 | unsigned char byData; 235 | uint16 reg; 236 | uint16 sample_write; 237 | }; 238 | 239 | extern bool odd_cycle; 240 | 241 | /*-------------------------------------------------------------------*/ 242 | /* Function prototypes */ 243 | /*-------------------------------------------------------------------*/ 244 | 245 | /* Initialize pNesX */ 246 | void pNesX_Init(); 247 | 248 | /* Completion treatment */ 249 | void pNesX_Fin(); 250 | 251 | /* Load a cassette */ 252 | int pNesX_Load( const char *filepath, uint32 filename ); 253 | 254 | /* Reset pNesX */ 255 | int pNesX_Reset(); 256 | 257 | /* Initialize PPU */ 258 | void pNesX_SetupPPU(); 259 | 260 | /* Set up a Mirroring of Name Table */ 261 | void pNesX_Mirroring( int nType ); 262 | void pNesX_Mirroring_Manual( int bank1, int bank2, int bank3, int bank4); 263 | 264 | /* The main loop of pNesX */ 265 | void pNesX_Main(); 266 | 267 | /* The loop of emulation */ 268 | void pNesX_Cycle(); 269 | 270 | /* A function in H-Sync */ 271 | int pNesX_HSync(); 272 | void pNesX_VSync(); 273 | 274 | void pNesX_DoSpu(); 275 | 276 | #endif /* !PNESX_H_INCLUDED */ 277 | 278 | -------------------------------------------------------------------------------- /pNesX_DrawLine_BG_C.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "macros.h" 3 | 4 | #include "pNesX.h" 5 | #include "Mapper_5.h" 6 | #include "pNesX_PPU_DC.h" 7 | #include "pNesX_DrawLine_BG_C.h" 8 | 9 | #include "profile.h" 10 | 11 | void pNesX_DrawLine_BG_C(unsigned char* pPoint) { 12 | startProfiling(2); 13 | uint16 nX; 14 | uint16 nY; 15 | uint16 nY4; 16 | uint16 nYBit; 17 | unsigned char* pPalTbl; 18 | uint16 nNameTable; 19 | unsigned char* pbyNameTable; 20 | unsigned char* pAlBase; 21 | unsigned char* paletteRegisters = &PPURAM[0x3f00]; 22 | 23 | nNameTable = ((ppuinfo.PPU_Addr & 0x0C00) >> 10) + 8; 24 | nX = (ppuinfo.PPU_Addr & 0x001F); 25 | nY = ((ppuinfo.PPU_Addr >> 5) & 0x001F); 26 | nYBit = ((ppuinfo.PPU_Addr >> 12) & 0x0007); 27 | nY4 = ( ( nY & 2 ) << 1 ); 28 | 29 | pbyNameTable = PPUBANK[nNameTable] + (nY << 5) + nX; 30 | pAlBase = PPUBANK[nNameTable] + 0x03C0 + ((nY >> 2) << 3); 31 | pPalTbl = &paletteRegisters[(( (pAlBase[nX >> 2] >> ( ( nX & 2 ) + nY4 ) ) & 0x3 ) << 2 )]; 32 | 33 | if (MapperNo == 5) { 34 | Mapper_5_PPU_Latch_RenderScreen(1, 0); 35 | } 36 | 37 | unsigned char nameTableValue = *pbyNameTable; 38 | unsigned char characterBank = ((ppuinfo.PPU_R0 & R0_BG_ADDR) ? 4 : 0) + (nameTableValue >> 6); 39 | unsigned char characterIndex = (nameTableValue & 0x3F); 40 | unsigned char* pbyBGData = PPUBANK[characterBank] + (characterIndex << 4) + (nYBit); 41 | unsigned char byData1 = ( ( pbyBGData[ 0 ] >> 1 ) & 0x55 ) | ( pbyBGData[ 8 ] & 0xAA ); 42 | unsigned char byData2 = ( pbyBGData[ 0 ] & 0x55 ) | ( ( pbyBGData[ 8 ] << 1 ) & 0xAA ); 43 | 44 | switch (ppuinfo.PPU_Scr_H_Bit) { 45 | case 0: 46 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 47 | case 1: 48 | *(pPoint++) = pPalTbl[( byData2 >> 6 ) & 0x3]; 49 | case 2: 50 | *(pPoint++) = pPalTbl[( byData1 >> 4 ) & 0x3]; 51 | case 3: 52 | *(pPoint++) = pPalTbl[( byData2 >> 4 ) & 0x3]; 53 | case 4: 54 | *(pPoint++) = pPalTbl[( byData1 >> 2 ) & 0x3]; 55 | case 5: 56 | *(pPoint++) = pPalTbl[( byData2 >> 2 ) & 0x3]; 57 | case 6: 58 | *(pPoint++) = pPalTbl[byData1 & 0x3]; 59 | case 7: 60 | *(pPoint++) = pPalTbl[byData2 & 0x3]; 61 | } 62 | 63 | nX++; 64 | 65 | // crossing a name table boundary 66 | if (!(nX & 0x001f)) { 67 | nNameTable ^= NAME_TABLE_H_MASK; 68 | nX = 0; 69 | pbyNameTable = PPUBANK[nNameTable] + (nY << 5) + nX; 70 | pAlBase = PPUBANK[nNameTable] + 0x03C0 + ((nY >> 2) << 3); 71 | } else { 72 | pbyNameTable++; 73 | } 74 | 75 | for (uint8 nIdx = 1; nIdx < 32; nIdx++) { 76 | 77 | /* 78 | if ((nX == 13) && (nY == 25)) { 79 | printf("BG [%u, %u]: [$%02X]\n", nX, nY, *pbyNameTable); 80 | } 81 | */ 82 | 83 | nameTableValue = *pbyNameTable; 84 | characterBank = ((ppuinfo.PPU_R0 & R0_BG_ADDR) ? 4 : 0) + (nameTableValue >> 6); 85 | characterIndex = (nameTableValue & 0x3F); 86 | pbyBGData = PPUBANK[characterBank] + (characterIndex << 4) + (nYBit); 87 | byData1 = ( ( pbyBGData[ 0 ] >> 1 ) & 0x55 ) | ( pbyBGData[ 8 ] & 0xAA ); 88 | byData2 = ( pbyBGData[ 0 ] & 0x55 ) | ( ( pbyBGData[ 8 ] << 1 ) & 0xAA ); 89 | pPalTbl = &paletteRegisters[(( (pAlBase[nX >> 2] >> ( ( nX & 2 ) + nY4 ) ) & 0x3 ) << 2 )]; 90 | 91 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 92 | *(pPoint++) = pPalTbl[( byData2 >> 6 ) & 0x3]; 93 | *(pPoint++) = pPalTbl[( byData1 >> 4 ) & 0x3]; 94 | *(pPoint++) = pPalTbl[( byData2 >> 4 ) & 0x3]; 95 | *(pPoint++) = pPalTbl[( byData1 >> 2 ) & 0x3]; 96 | *(pPoint++) = pPalTbl[( byData2 >> 2 ) & 0x3]; 97 | *(pPoint++) = pPalTbl[byData1 & 0x3]; 98 | *(pPoint++) = pPalTbl[byData2 & 0x3]; 99 | 100 | nX++; 101 | 102 | // are we crossing a name table boundary? 103 | if (!(nX & 0x001F)) { 104 | nNameTable ^= NAME_TABLE_H_MASK; 105 | nX = 0; 106 | pbyNameTable = PPUBANK[nNameTable] + (nY << 5) + nX; 107 | pAlBase = PPUBANK[nNameTable] + 0x03C0 + ((nY >> 2) << 3); 108 | } else { 109 | pbyNameTable++; 110 | } 111 | } 112 | 113 | nameTableValue = *pbyNameTable; 114 | characterBank = ((ppuinfo.PPU_R0 & R0_BG_ADDR) ? 4 : 0) + (nameTableValue >> 6); 115 | characterIndex = (nameTableValue & 0x3F); 116 | pbyBGData = PPUBANK[characterBank] + (characterIndex << 4) + (nYBit); 117 | byData1 = ( ( pbyBGData[ 0 ] >> 1 ) & 0x55 ) | ( pbyBGData[ 8 ] & 0xAA ); 118 | byData2 = ( pbyBGData[ 0 ] & 0x55 ) | ( ( pbyBGData[ 8 ] << 1 ) & 0xAA ); 119 | pPalTbl = &paletteRegisters[(( (pAlBase[nX >> 2] >> ( ( nX & 2 ) + nY4 ) ) & 0x3 ) << 2 )]; 120 | 121 | switch (ppuinfo.PPU_Scr_H_Bit) { 122 | case 1: 123 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 124 | break; 125 | case 2: 126 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 127 | *(pPoint++) = pPalTbl[( byData2 >> 6 ) & 0x3]; 128 | break; 129 | case 3: 130 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 131 | *(pPoint++) = pPalTbl[( byData2 >> 6 ) & 0x3]; 132 | *(pPoint++) = pPalTbl[( byData1 >> 4 ) & 0x3]; 133 | break; 134 | case 4: 135 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 136 | *(pPoint++) = pPalTbl[( byData2 >> 6 ) & 0x3]; 137 | *(pPoint++) = pPalTbl[( byData1 >> 4 ) & 0x3]; 138 | *(pPoint++) = pPalTbl[( byData2 >> 4 ) & 0x3]; 139 | break; 140 | case 5: 141 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 142 | *(pPoint++) = pPalTbl[( byData2 >> 6 ) & 0x3]; 143 | *(pPoint++) = pPalTbl[( byData1 >> 4 ) & 0x3]; 144 | *(pPoint++) = pPalTbl[( byData2 >> 4 ) & 0x3]; 145 | *(pPoint++) = pPalTbl[( byData1 >> 2 ) & 0x3]; 146 | break; 147 | case 6: 148 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 149 | *(pPoint++) = pPalTbl[( byData2 >> 6 ) & 0x3]; 150 | *(pPoint++) = pPalTbl[( byData1 >> 4 ) & 0x3]; 151 | *(pPoint++) = pPalTbl[( byData2 >> 4 ) & 0x3]; 152 | *(pPoint++) = pPalTbl[( byData1 >> 2 ) & 0x3]; 153 | *(pPoint++) = pPalTbl[( byData2 >> 2 ) & 0x3]; 154 | break; 155 | case 7: 156 | *(pPoint++) = pPalTbl[( byData1 >> 6 ) & 0x3]; 157 | *(pPoint++) = pPalTbl[( byData2 >> 6 ) & 0x3]; 158 | *(pPoint++) = pPalTbl[( byData1 >> 4 ) & 0x3]; 159 | *(pPoint++) = pPalTbl[( byData2 >> 4 ) & 0x3]; 160 | *(pPoint++) = pPalTbl[( byData1 >> 2 ) & 0x3]; 161 | *(pPoint++) = pPalTbl[( byData2 >> 2 ) & 0x3]; 162 | *(pPoint++) = pPalTbl[byData1 & 0x3]; 163 | break; 164 | } 165 | 166 | if (!(PPU_R1 & 0x02)) { 167 | pPoint -= 256; 168 | memset(pPoint, pPalTbl[0], 8); 169 | } 170 | endProfiling(2); 171 | } -------------------------------------------------------------------------------- /pNesX_DrawLine_BG_C.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_DrawLine_BG_C.h : Interface for C Background Line Renderer */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | #ifndef PNESX_DRAWLINE_BG_C 10 | #define PNESX_DRAWLINE_BG_C 11 | 12 | void pNesX_DrawLine_BG_C(unsigned char* pPoint); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /pNesX_DrawLine_BG_C_Map9.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_DrawLine_BG_C_Map9.h : Interface for C Sprite Renderer */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | #ifndef PNESX_MAP9DRAWLINE_BG_C 10 | #define PNESX_MAP9DRAWLINE_BG_C 11 | 12 | void pNesX_Map9DrawLine_BG_C(unsigned char* pPoint); 13 | uint16 pNesX_Map9Simulate_Spr_C(); 14 | void pNesX_Map9Simulate_BG_C(); 15 | void pNesX_Map9DrawLine_Spr_C(unsigned char* pSprBuf); 16 | 17 | #endif -------------------------------------------------------------------------------- /pNesX_DrawLine_Spr_C.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "macros.h" 3 | 4 | #include "pNesX.h" 5 | #include "pNesX_PPU_DC.h" 6 | #include "pNesX_DrawLine_BG_C.h" 7 | #include "Mapper.h" 8 | #include "Mapper_5.h" 9 | #include "pNesX_System_DC.h" 10 | 11 | #define MAX_SPRITES_ON_A_LINE 8 12 | 13 | // How many entries in SpritesToDrawNextScanline are valid 14 | unsigned char NumSpritesToDrawNextScanline = 0; 15 | // The indexes of the top 8 sprites to draw on the next scanline 16 | unsigned char SpritesToDrawNextScanline[MAX_SPRITES_ON_A_LINE] = {0}; 17 | // Mark whether the sprite overflow flag should be set on next scanline 18 | bool OverflowSpritesOnNextScanline = false; 19 | 20 | // How many entries in SpritesToDraw are valid 21 | unsigned char NumSpritesToDraw = 0; 22 | // The top 8 sprites to draw this scanline 23 | unsigned char SpritesToDraw[MAX_SPRITES_ON_A_LINE] = {0}; 24 | // Whether we overflowed sprites this scanline 25 | bool OverflowedSprites = false; 26 | 27 | void pNesX_DrawLine_Spr_C(unsigned char* scanline_buffer) { 28 | startProfiling(3); 29 | unsigned char spriteBuffer[256]; 30 | 31 | int nX; 32 | int nY; 33 | int nYBit; 34 | unsigned char *pSPRRAM; 35 | int nAttr; 36 | uint16 bySprCol; 37 | unsigned char patternData[8]; 38 | unsigned char* pbyBGData; 39 | unsigned char* pPalTbl; 40 | unsigned char byData1; 41 | unsigned char byData2; 42 | 43 | if (MapperNo == 5) { 44 | Mapper_5_PPU_Latch_RenderScreen(0, 0); 45 | } 46 | 47 | // Sprite Evaluation Logic 48 | // Reset buffers and counts on scanline 0 49 | if (ppuinfo.PPU_Scanline == 0) { 50 | NumSpritesToDrawNextScanline = 0; 51 | memset(SpritesToDrawNextScanline, 0, 8); 52 | NumSpritesToDraw = 0; 53 | memset(SpritesToDraw, 0, 8); 54 | OverflowSpritesOnNextScanline = false; 55 | OverflowedSprites = false; 56 | } else { 57 | // Otherwise move the SpritesToDrawNextScanline to this scanline 58 | NumSpritesToDraw = NumSpritesToDrawNextScanline; 59 | memcpy(SpritesToDraw, SpritesToDrawNextScanline, 8); 60 | NumSpritesToDrawNextScanline = 0; 61 | 62 | // More than 8 sprites were requested to be drawn on this scanline, so set the PPU flag for overflow 63 | if (OverflowSpritesOnNextScanline) { 64 | PPU_R2 |= R2_MAX_SP; 65 | OverflowedSprites = true; 66 | OverflowSpritesOnNextScanline = false; 67 | } else { 68 | // Or if we are not going to overflow this scanline, set the PPU flag back 69 | PPU_R2 &= ~R2_MAX_SP; 70 | OverflowedSprites = false; 71 | } 72 | } 73 | 74 | // Calculate the sprites to draw on the next scanline 75 | pSPRRAM = SPRRAM; 76 | for ( unsigned char spriteIndex = 0; spriteIndex < 64; spriteIndex++) { 77 | nY = pSPRRAM[ SPR_Y ]; 78 | 79 | if (!((nY > ppuinfo.PPU_Scanline) || ((nY + ppuinfo.PPU_SP_Height) <= ppuinfo.PPU_Scanline))) { 80 | if (NumSpritesToDrawNextScanline < MAX_SPRITES_ON_A_LINE) { 81 | SpritesToDrawNextScanline[NumSpritesToDrawNextScanline] = spriteIndex; 82 | NumSpritesToDrawNextScanline++; 83 | } else { 84 | // printf("Overflowed Sprites on Scanline [%u]\n", ppuinfo.PPU_Scanline); 85 | OverflowSpritesOnNextScanline = true; 86 | break; 87 | } 88 | } 89 | 90 | pSPRRAM+=4; 91 | } 92 | 93 | // If sprite Rendering is Enabled and we're not on scanline 0 and we have sprites to draw 94 | if ((ppuinfo.PPU_Scanline > 0) && 95 | (NumSpritesToDraw > 0) && 96 | (PPU_R1 & R1_SHOW_SP)) { 97 | memset4(spriteBuffer, 0, 256); 98 | for (int spriteIndex = (NumSpritesToDraw - 1); spriteIndex >= 0; spriteIndex--) { 99 | //Calculate sprite address by taking index and multiplying by 4, since each entry is 4 bytes 100 | pSPRRAM = SPRRAM + (SpritesToDraw[spriteIndex] << 2); 101 | 102 | nX = pSPRRAM[ SPR_X ]; 103 | nY = pSPRRAM[ SPR_Y ] + 1; 104 | nAttr = pSPRRAM[ SPR_ATTR ]; 105 | nYBit = ppuinfo.PPU_Scanline - nY; 106 | nYBit = ( nAttr & SPR_ATTR_V_FLIP ) ? ( ppuinfo.PPU_SP_Height - nYBit - 1) : nYBit; 107 | 108 | unsigned char nameTableValue = (ppuinfo.PPU_R0 & R0_SP_SIZE) ? 109 | (pSPRRAM[SPR_CHR] & 0xfe) : 110 | (pSPRRAM[SPR_CHR]); 111 | unsigned char characterBank = ((ppuinfo.PPU_R0 & R0_SP_SIZE) ? 112 | ((pSPRRAM[SPR_CHR] & 1) ? 4 : 0) + (nameTableValue >> 6) : 113 | ((ppuinfo.PPU_R0 & R0_SP_ADDR) ? 4 : 0) + (nameTableValue >> 6)); 114 | unsigned char characterIndex = ((ppuinfo.PPU_R0 & R0_SP_SIZE) && (nYBit >= 8)) ? 115 | (nameTableValue & 0x3F) + 1 : 116 | (nameTableValue & 0x3F); 117 | 118 | pbyBGData = PPUBANK[characterBank] + (characterIndex << 4) + (nYBit % 8); 119 | byData1 = ( ( pbyBGData[ 0 ] >> 1 ) & 0x55 ) | ( pbyBGData[ 8 ] & 0xAA ); 120 | byData2 = ( pbyBGData[ 0 ] & 0x55 ) | ( ( pbyBGData[ 8 ] << 1 ) & 0xAA ); 121 | pPalTbl = &PPURAM[0x3F10 + ((nAttr & SPR_ATTR_COLOR) << 2)]; 122 | 123 | unsigned char offset = 0; 124 | unsigned char pixelsToDraw = 8; 125 | // If we aren't rendering the left 8 pixels of sprites skip past their offset 126 | // before merging the sprite pixels into the render buffer 127 | if ((nX < 8) && (!(PPU_R1 & R1_CLIP_SP))) { 128 | offset = 8 - nX; 129 | } 130 | // If the sprite would go off the right side of the buffer, reduce the number of 131 | // pixels to draw so that we don't overflow 132 | if (nX > 248) { 133 | pixelsToDraw = 256 - nX; 134 | } 135 | 136 | if ( nAttr & SPR_ATTR_H_FLIP ) { 137 | patternData[ 0 ] = byData2 & 3; 138 | patternData[ 1 ] = byData1 & 3; 139 | patternData[ 2 ] = ( byData2 >> 2 ) & 3; 140 | patternData[ 3 ] = ( byData1 >> 2 ) & 3; 141 | patternData[ 4 ] = ( byData2 >> 4 ) & 3; 142 | patternData[ 5 ] = ( byData1 >> 4 ) & 3; 143 | patternData[ 6 ] = ( byData2 >> 6 ) & 3; 144 | patternData[ 7 ] = ( byData1 >> 6 ) & 3; 145 | } else { 146 | patternData[ 0 ] = ( byData1 >> 6 ) & 3; 147 | patternData[ 1 ] = ( byData2 >> 6 ) & 3; 148 | patternData[ 2 ] = ( byData1 >> 4 ) & 3; 149 | patternData[ 3 ] = ( byData2 >> 4 ) & 3; 150 | patternData[ 4 ] = ( byData1 >> 2 ) & 3; 151 | patternData[ 5 ] = ( byData2 >> 2 ) & 3; 152 | patternData[ 6 ] = byData1 & 3; 153 | patternData[ 7 ] = byData2 & 3; 154 | } 155 | 156 | nAttr ^= SPR_ATTR_PRI; 157 | bySprCol = (( nAttr & SPR_ATTR_PRI ) << 2 ) | ((pSPRRAM == SPRRAM) ? 0x40 : 0x00); 158 | for (offset; offset < pixelsToDraw; offset++) { 159 | if (patternData[offset]) { 160 | spriteBuffer[nX + offset] = bySprCol | (pPalTbl[patternData[offset]] & 0x3F); 161 | } 162 | } 163 | } 164 | 165 | if (SpriteJustHit == SPRITE_HIT_SENTINEL) { 166 | for (uint16 i = 0; i < 256; i++) { 167 | if ((i < 255) && (spriteBuffer[i] & 0x40) && ((scanline_buffer[i] & 0x40) == 0)) { 168 | SpriteJustHit = ppuinfo.PPU_Scanline; 169 | } 170 | 171 | if ((spriteBuffer[i] != 0) && ((spriteBuffer[i] & 0x80) || (scanline_buffer[i] & 0x40))) { 172 | scanline_buffer[i] = spriteBuffer[i]; 173 | } 174 | } 175 | } else { 176 | for (uint16 i = 0; i < 256; i++) { 177 | if ((spriteBuffer[i] != 0) && ((spriteBuffer[i] & 0x80) || (scanline_buffer[i] & 0x40))) { 178 | scanline_buffer[i] = spriteBuffer[i]; 179 | } 180 | } 181 | } 182 | } 183 | endProfiling(3); 184 | } -------------------------------------------------------------------------------- /pNesX_DrawLine_Spr_C.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_DrawLine_Spr_C.h : Interface for C Sprite Renderer */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | #ifndef PNESX_DRAWLINE_SPR_C 10 | #define PNESX_DRAWLINE_SPR_C 11 | 12 | #include 13 | 14 | void pNesX_DrawLine_Spr_C(unsigned char* scanline_buffer); 15 | 16 | #endif -------------------------------------------------------------------------------- /pNesX_PPU_DC.c: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_PPU_DC.c : PPU Renderer Function */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* Slightly reorganized from pNesX version */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #include 11 | #include "macros.h" 12 | 13 | #include "pNesX.h" 14 | #include "pNesX_PPU_DC.h" 15 | #include "pNesX_System_DC.h" 16 | #include "pNesX_DrawLine_BG_C_Map9.h" 17 | #include "pNesX_DrawLine_BG_C.h" 18 | #include "pNesX_DrawLine_Spr_C.h" 19 | #include "profile.h" 20 | #include "Mapper.h" 21 | 22 | #define __ALIGN32__ __attribute__ ((aligned (32))) 23 | __ALIGN32__ unsigned char Scanline_Buffer[256]; 24 | 25 | extern uint16 PPU_Temp; 26 | 27 | void pNesX_StartFrame() { 28 | if ((PPU_R1 & 0x10) || (PPU_R1 & 0x08)) 29 | ppuinfo.PPU_Addr = PPU_Temp; 30 | } 31 | 32 | /*===================================================================*/ 33 | /* */ 34 | /* pNesX_NewDrawLine() : Render a scanline */ 35 | /* */ 36 | /*===================================================================*/ 37 | void pNesX_DrawLine() { 38 | void* texture_address; 39 | 40 | //texture_address is the Texture the frame currently being rendered will be displayed in 41 | texture_address = &(WorkFrame -> texture[ppuinfo.PPU_Scanline * 256]); 42 | 43 | if ( !( PPU_R1 & R1_SHOW_SCR ) ) { 44 | memset4(Scanline_Buffer, (PPURAM[0x3F00] << 24) | (PPURAM[0x3F00] << 16) | (PPURAM[0x3F00] << 8) | PPURAM[0x3F00], 256); 45 | } else { 46 | if (MapperNo == 9) { 47 | pNesX_Map9DrawLine_BG_C(Scanline_Buffer); 48 | pNesX_Map9DrawLine_Spr_C(Scanline_Buffer); 49 | } else { 50 | pNesX_DrawLine_BG_C(Scanline_Buffer); 51 | pNesX_DrawLine_Spr_C(Scanline_Buffer); 52 | } 53 | } 54 | 55 | //Move the scanline buffer to the PVR texture 56 | pvr_txr_load(Scanline_Buffer, texture_address, 256); 57 | } 58 | -------------------------------------------------------------------------------- /pNesX_PPU_DC.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_PPU_DC.h : PPU Renderer Function */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* Slightly reorganized from pNesX version */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef PNESX_PPU_DC 11 | #define PNESX_PPU_DC 12 | 13 | void pNesX_DrawLine(); 14 | void pNesX_StartFrame(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /pNesX_Sound_APU.c: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_Sound_APU.c : APU functions for NES sound emulation */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* Based on Matthew Conte's Nofrendo sound core */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #include "pNesX_Sound_APU.h" 11 | #include "profile.h" 12 | #include "macros.h" 13 | 14 | int audio_initialize() { 15 | apu = apu_create(APU_SAMPLE_RATE, CYCLE_RATE, 0, APU_SAMPLE_BITS); 16 | apu_set_exsound(NES_APU_EXSOUND_NONE); 17 | if (!apu) return 0; 18 | audio_reset(); 19 | return 1; 20 | } 21 | 22 | void audio_reset() { 23 | apu_reset(); 24 | } 25 | 26 | void audio_shutdown() { 27 | if (apu != NULL) { 28 | apu_destroy(&apu); 29 | apu = NULL; 30 | } 31 | } 32 | 33 | uint8 audio_read(uint32 addr) { 34 | return apu_read(addr); 35 | } 36 | 37 | void audio_write(uint32 addr, uint8 value) { 38 | apu_write(addr, value); 39 | apu_write_cur(addr, value); 40 | } 41 | 42 | void audio_do_frame(uint16* sample_buffer, uint32 num_samples) { 43 | apu_process(sample_buffer, num_samples); 44 | } 45 | 46 | int audio_sync_dmc_registers(uint32 cycles) { 47 | startProfiling(5); 48 | int result = sync_dmc_register(cycles); 49 | endProfiling(5); 50 | return result; 51 | } 52 | 53 | void audio_sync_apu_registers() { 54 | sync_apu_register(); 55 | } -------------------------------------------------------------------------------- /pNesX_Sound_APU.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_Sound_APU.h : APU functions for NES sound emulation */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* Slightly reorganized from pNesX version */ 7 | /* */ 8 | /*===================================================================*/ 9 | 10 | #ifndef PNESX_SOUND_DC 11 | #define PNESX_SOUND_DC 12 | 13 | #include "nes_apu.h" 14 | 15 | #define APU_SAMPLE_RATE 22050 16 | #define CYCLE_RATE 60 17 | #define APU_SAMPLE_BITS 16 18 | 19 | extern int audio_initialize(); 20 | extern void audio_reset(); 21 | extern void audio_shutdown(); 22 | extern uint8 audio_read(uint32 addr); 23 | extern void audio_write(uint32 addr, uint8 value); 24 | extern void audio_do_frame(uint16* sample_buffer, uint32 num_samples); 25 | extern int audio_sync_dmc_registers(uint32 cycles); 26 | extern void audio_sync_apu_registers(); 27 | 28 | #endif -------------------------------------------------------------------------------- /pNesX_System.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_System.h : The function which depends on a system */ 4 | /* */ 5 | /* 1999/11/03 Racoon New preparation */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | #ifndef PNESX_SYSTEM_H_INCLUDED 10 | #define PNESX_SYSTEM_H_INCLUDED 11 | 12 | #include 13 | 14 | /*-------------------------------------------------------------------*/ 15 | /* Palette data */ 16 | /*-------------------------------------------------------------------*/ 17 | extern uint16* NesPalette; 18 | 19 | /*-------------------------------------------------------------------*/ 20 | /* Function prototypes */ 21 | /*-------------------------------------------------------------------*/ 22 | 23 | /* Menu screen */ 24 | int pNesX_Menu(); 25 | 26 | /* Read ROM image file */ 27 | int pNesX_ReadRom( const char *filepath, uint32 filesize ); 28 | 29 | /* Release a memory for ROM */ 30 | void pNesX_ReleaseRom(); 31 | 32 | /* Transfer the contents of work frame on the screen */ 33 | void pNesX_LoadFrame(); 34 | 35 | /* Get a joypad state */ 36 | void pNesX_PadState( uint32 *pdwPad1, uint32 *pdwPad2, uint32 *ExitCount ); 37 | 38 | #endif /* !PNESX_SYSTEM_H_INCLUDED */ -------------------------------------------------------------------------------- /pNesX_System_DC.h: -------------------------------------------------------------------------------- 1 | /*===================================================================*/ 2 | /* */ 3 | /* pNesX_System_DC.h : DC System Functions, GUI */ 4 | /* */ 5 | /* 2001/12/22 ReGex FrNES 0.60 Source Release */ 6 | /* */ 7 | /*===================================================================*/ 8 | 9 | #ifndef __PNESX_SYS_DC_H 10 | #define __PNESX_SYS_DC_H 11 | 12 | #include 13 | 14 | #include "font.h" 15 | #include "TextWindow.h" 16 | #include "ROMLoad.h" 17 | 18 | //#define table for GUI 19 | #define PAGE_ROMSELECT 0 20 | #define PAGE_VIDEOOPTIONS 1 21 | #define PAGE_CONTROLOPTIONS 2 22 | #define PAGE_SYSTEMOPTIONS 3 23 | #define PAGE_GUIOPTIONS 4 24 | #define PAGE_HELP 5 25 | #define PAGE_CREDITS 6 26 | #define MENUNUM_MAIN 0 27 | #define MENUNUM_ROMSELECT 1 28 | #define MENUNUM_VIDEOOPTIONS 2 29 | #define MENUNUM_CONTROLOPTIONS 3 30 | #define MENUNUM_SYSTEMOPTIONS 4 31 | #define MENUNUM_GUIOPTIONS 5 32 | #define MENUNUM_FONTOPTIONS 6 33 | #define MENUNUM_HELP 7 34 | #define MENUNUM_CREDITS 8 35 | #define MENUNUM_AUTOROM 99 36 | 37 | #define RECORDING_MODE_DISABLED 0 38 | #define RECORDING_MODE_ENABLED 1 39 | #define RECORDING_MODE_PLAYBACK 2 40 | 41 | extern uint8 recordingMode; 42 | 43 | extern bool log_enabled; 44 | 45 | extern char szRomPath[]; 46 | extern uint32 RomSize; 47 | 48 | void Load_VMU_Options(); 49 | void Save_VMU_Options(); 50 | void initialize_controllers(); 51 | void rescan_controllers(); 52 | 53 | void calculateOutputScreenGeometry(); 54 | 55 | int LoadSRAM(); 56 | int SaveSRAM(); 57 | 58 | int draw_VMU_icon(maple_device_t* vmu, char* icon); 59 | 60 | void launchEmulator(); 61 | 62 | #ifdef DEBUG 63 | void pNesX_DebugPrint(char* fmt, ...); 64 | #else 65 | #define pNesX_DebugPrint(...) (0) 66 | #endif 67 | 68 | #endif -------------------------------------------------------------------------------- /profile.c: -------------------------------------------------------------------------------- 1 | #include "profile.h" 2 | 3 | uint32 numEmulationFrames = 0; 4 | 5 | #ifdef PROFILE 6 | uint32 numProfilingFunctions = 0; 7 | uint32 profilingMode = PMCR_PIPELINE_FREEZE_BY_ICACHE_MISS_MODE; 8 | const char* PROFILING_MODE_STRINGS[] = { 9 | "No Mode (0x00)", 10 | "Operand Read Accesses", // 0x01 11 | "Operand Write Accesses", // 0x02 12 | "UTLB Misses", // 0x03 13 | "Operand Cache Read Misses", 14 | "Operand Cache Write Misses", 15 | "Instruction Fetches", 16 | "Instruction TLB Misses", 17 | "Instruction Cache Misses", 18 | "Operand Accesses", 19 | "Instruction Fetches", 20 | "On Chip RAM Operand Accesses", 21 | "No Mode (0x0C)", 22 | "On Chip IO Accesses", 23 | "Operand Accesses", 24 | "Operand Cache Misses", 25 | "Branches Issued", 26 | "Branches Taken", 27 | "Subroutines Issued", 28 | "Instructions Issued", 29 | "Parallel Instructions Issued", 30 | "FPU Instructions Issued", 31 | "Interrupts", 32 | "NMIs", 33 | "TRAPA Instructions", 34 | "UBC A Matches", 35 | "UBC B Matches", 36 | "No Mode (0x1B)", 37 | "No Mode (0x1C)", 38 | "No Mode (0x1D)", 39 | "No Mode (0x1E)", 40 | "No Mode (0x1F)", 41 | "No Mode (0x20)", 42 | "Instruction Cache Fills", 43 | "Operand Cache Fills", 44 | "Elapsed Time", 45 | "Pipeline Freezes by Instruction Cache Misses", 46 | "Pipeline Freezes by Data Cache Misses", 47 | "No Mode", 48 | "Pipeline Freezes by Branch Mode", 49 | "Pipeline Freezes by CPU Register Mode", 50 | "Pipeline Freezes by FPU Mode" 51 | }; 52 | 53 | typedef struct __attribute__ ((packed, aligned(4))) { 54 | char* functionName; 55 | uint64 startTime; 56 | uint64 nanoseconds; 57 | uint64 startPerfCounterValue; 58 | uint64 totalPerfCounterValue; 59 | } ProfilingInformation_t; 60 | 61 | ProfilingInformation_t* profilingInformation; 62 | bool resetPerformanceCounter = false; 63 | 64 | void resetProfiling(uint32 newProfilingMode, uint32 numFunctions) { 65 | profilingMode = newProfilingMode; 66 | 67 | if (profilingInformation) { 68 | for (uint32 i = 0; i < numProfilingFunctions; i++) { 69 | free(profilingInformation[i].functionName); 70 | } 71 | free(profilingInformation); 72 | } 73 | 74 | profilingInformation = (ProfilingInformation_t*)malloc(sizeof(ProfilingInformation_t) * numFunctions); 75 | memset(profilingInformation, 0, sizeof(ProfilingInformation_t) * numFunctions); 76 | numProfilingFunctions = numFunctions; 77 | 78 | if (resetPerformanceCounter) { 79 | perf_cntr_stop(PRFC1); 80 | perf_cntr_clear(PRFC1); 81 | } 82 | 83 | perf_cntr_start(PRFC1, profilingMode, PMCR_COUNT_CPU_CYCLES); 84 | resetPerformanceCounter = true; 85 | 86 | numEmulationFrames = 0; 87 | } 88 | 89 | void setProfilingFunctionName(uint32 functionIndex, const char* functionName) { 90 | char* functionCopy = malloc(strlen(functionName) + 1); 91 | strcpy(functionCopy, functionName); 92 | profilingInformation[functionIndex].functionName = functionCopy; 93 | } 94 | 95 | void startProfiling(uint32 functionIndex) { 96 | struct timespec ts; 97 | clock_gettime(CLOCK_MONOTONIC, &ts); 98 | profilingInformation[functionIndex].startTime = ts.tv_sec * 1000000000ULL + ts.tv_nsec; 99 | profilingInformation[functionIndex].startPerfCounterValue = perf_cntr_count(PRFC1); 100 | } 101 | 102 | void endProfiling(uint32 functionIndex) { 103 | struct timespec ts; 104 | clock_gettime(CLOCK_MONOTONIC, &ts); 105 | profilingInformation[functionIndex].nanoseconds += (ts.tv_sec * 1000000000ULL + ts.tv_nsec) - profilingInformation[functionIndex].startTime; 106 | profilingInformation[functionIndex].totalPerfCounterValue += perf_cntr_count(PRFC1) - profilingInformation[functionIndex].startPerfCounterValue; 107 | } 108 | 109 | void printProfilingReport() { 110 | printf("****************** PROFILING REPORT *****************\n"); 111 | printf("Over [%lu] Frames\n", numEmulationFrames); 112 | printf("------------------ Execution Time -------------------\n"); 113 | for (uint32 i = 0; i < numProfilingFunctions; i++) { 114 | printf("%s: %.2f nanoseconds per frame\n", 115 | profilingInformation[i].functionName, 116 | (float)profilingInformation[i].nanoseconds / (float)numEmulationFrames); 117 | } 118 | printf("---------------- %s ---------------\n", PROFILING_MODE_STRINGS[profilingMode]); 119 | const char* itemString = PROFILING_MODE_STRINGS[profilingMode]; 120 | if (profilingMode == 0x23) { 121 | itemString = "cycles"; 122 | } else if (profilingMode > 0x23) { 123 | itemString = "lost cycles due to pipeline freeze"; 124 | } 125 | for (uint32 i = 0; i < numProfilingFunctions; i++) { 126 | printf("%s: %.2f %s per frame\n", 127 | profilingInformation[i].functionName, 128 | (float)profilingInformation[i].totalPerfCounterValue / (float)numEmulationFrames, 129 | itemString); 130 | } 131 | printf("*****************************************************\n"); 132 | } 133 | #endif -------------------------------------------------------------------------------- /profile.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROFILE_H 2 | #define _PROFILE_H 3 | 4 | #include 5 | 6 | extern uint32 numEmulationFrames; 7 | 8 | #define PROFILE 9 | 10 | #ifdef PROFILE 11 | void resetProfiling(uint32 newProfilingMode, uint32 numFunctions); 12 | void setProfilingFunctionName(uint32 functionIndex, const char* functionName); 13 | void startProfiling(uint32 functionIndex); 14 | void endProfiling(uint32 functionIndex); 15 | void printProfilingReport(); 16 | #else 17 | #define resetProfiling(...) (0) 18 | #define setProfilingFunctionName(...) (0) 19 | #define startProfiling(...) (0) 20 | #define endProfiling(...) (0) 21 | #define printProfilingReport() (0) 22 | #endif 23 | 24 | #endif -------------------------------------------------------------------------------- /romdisk/nes.pal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maslevin/FrNES/b462a618e5c103cc9a340c6e3b8dd6c54cc1de9e/romdisk/nes.pal -------------------------------------------------------------------------------- /romdisk/neuro.fnt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maslevin/FrNES/b462a618e5c103cc9a340c6e3b8dd6c54cc1de9e/romdisk/neuro.fnt -------------------------------------------------------------------------------- /romdisk/neuro_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maslevin/FrNES/b462a618e5c103cc9a340c6e3b8dd6c54cc1de9e/romdisk/neuro_0.png -------------------------------------------------------------------------------- /romdisk/neuro_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maslevin/FrNES/b462a618e5c103cc9a340c6e3b8dd6c54cc1de9e/romdisk/neuro_1.png -------------------------------------------------------------------------------- /sound_tables/make_lineartable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tbl_param.h" 4 | 5 | static unsigned int lineartbl[lineartable_len]; 6 | 7 | int 8 | main() 9 | { 10 | int i; 11 | double a; 12 | unsigned int ua; 13 | 14 | memset(lineartbl, 0, sizeof(lineartbl)); 15 | 16 | lineartbl[0] = LOG_LIN_BITS << LOG_BITS; 17 | 18 | for (i = 1; i < lineartable_len; i++) 19 | lineartbl[i] = 20 | (unsigned int)((LIN_BITS - log(i)/log(2)) * (1 << LOG_BITS)) << 1; 21 | 22 | for (i = 0; i < lineartable_len; ++i) 23 | printf("%d,\n", lineartbl[i]); 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /sound_tables/make_logtable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tbl_param.h" 4 | 5 | static unsigned int logtbl[logtable_len]; 6 | 7 | int 8 | main() 9 | { 10 | int i; 11 | double a; 12 | 13 | memset(logtbl, 0, sizeof(logtbl)); 14 | 15 | for (i = 0; i < logtable_len; i++) 16 | logtbl[i] = (unsigned int)(pow (2, (LOG_LIN_BITS - (i / (double)logtable_len)))); 17 | 18 | for (i = 0; i < logtable_len; ++i) 19 | printf("%d,\n", logtbl[i]); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /sound_tables/tbl/lineartable.h: -------------------------------------------------------------------------------- 1 | 122880, 2 | 49152, 3 | 40960, 4 | 36166, 5 | 32768, 6 | 30130, 7 | 27974, 8 | 26154, 9 | 24576, 10 | 23182, 11 | 21938, 12 | 20812, 13 | 19782, 14 | 18836, 15 | 17962, 16 | 17146, 17 | 16384, 18 | 15666, 19 | 14990, 20 | 14352, 21 | 13746, 22 | 13170, 23 | 12620, 24 | 12094, 25 | 11590, 26 | 11108, 27 | 10644, 28 | 10198, 29 | 9770, 30 | 9354, 31 | 8954, 32 | 8566, 33 | 8192, 34 | 7828, 35 | 7474, 36 | 7132, 37 | 6798, 38 | 6476, 39 | 6160, 40 | 5852, 41 | 5554, 42 | 5262, 43 | 4978, 44 | 4700, 45 | 4428, 46 | 4162, 47 | 3902, 48 | 3648, 49 | 3398, 50 | 3156, 51 | 2916, 52 | 2682, 53 | 2452, 54 | 2228, 55 | 2006, 56 | 1790, 57 | 1578, 58 | 1368, 59 | 1162, 60 | 960, 61 | 762, 62 | 566, 63 | 374, 64 | 186, 65 | 0, 66 | -------------------------------------------------------------------------------- /sound_tables/tbl_param.h: -------------------------------------------------------------------------------- 1 | #ifndef __NES_APU_TABLES_PARAM_H 2 | #define __NES_APU_TABLES_PARAM_H 3 | 4 | #define LOG_BITS 12 5 | #define LIN_BITS 6 6 | #define LOG_LIN_BITS 30 7 | 8 | #define lineartable_len ((1 << LIN_BITS) + 1) 9 | #define logtable_len (1 << LOG_BITS) 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /vmu_icons.h: -------------------------------------------------------------------------------- 1 | static char vmu_screen_normal[] = 2 | "................................................" 3 | "........+++++++......+++....++.++++++++.++++++++" 4 | ".......+++++++......++++...++.++++++++.++++++++." 5 | "......++...........++.++..++.++.......++........" 6 | ".....+++++..++.++.++..++,++.++++.....++++++++..." 7 | "....+++++..+++++.++...++++.++.............++...." 8 | "...++.....++....++....+++.+++++++.+++++++++....." 9 | "..++.....++....++.....++.+++++++.+++++++++......" 10 | "................................................" 11 | "++++++++++++++++++++++++++++++++++++++++++++++++" 12 | "+++++.+++.+....+...+++++++++..++++....++++.+++++" 13 | "+++++.+++.+.++++.++.+++++++.++.++++++.+++..+++++" 14 | "+++++.+++.+...++...++++++++.++.+++++.+++++.+++++" 15 | "++++++.+.++.++++.++.+++++++.++.++++.++++++.+++++" 16 | "+++++++.+++....+.++.+.++++++..++.++.++.++...++++" 17 | "++++++++++++++++++++++++++++++++++++++++++++++++" 18 | "++++++++++++++++++++++++++++++++++++++++++++++++" 19 | "................................................" 20 | "................................................" 21 | "................................................" 22 | "................................................" 23 | "................................................" 24 | "................................................" 25 | "................................................" 26 | "................................................" 27 | "................................................" 28 | "................................................" 29 | "................................................" 30 | "................................................" 31 | "................................................" 32 | "................................................" 33 | "................................................" 34 | "................................................"; 35 | 36 | static char vmu_screen_saving[] = 37 | "................................................" 38 | "........+++++++......+++....++.++++++++.++++++++" 39 | ".......+++++++......++++...++.++++++++.++++++++." 40 | "......++...........++.++..++.++.......++........" 41 | ".....+++++..++.++.++..++,++.++++.....++++++++..." 42 | "....+++++..+++++.++...++++.++.............++...." 43 | "...++.....++....++....+++.+++++++.+++++++++....." 44 | "..++.....++....++.....++.+++++++.+++++++++......" 45 | "................................................" 46 | "++++++++++++++++++++++++++++++++++++++++++++++++" 47 | "+++++.+++.+....+...+++++++++..++++....++++.+++++" 48 | "+++++.+++.+.++++.++.+++++++.++.++++++.+++..+++++" 49 | "+++++.+++.+...++...++++++++.++.+++++.+++++.+++++" 50 | "++++++.+.++.++++.++.+++++++.++.++++.++++++.+++++" 51 | "+++++++.+++....+.++.+.++++++..++.++.++.++...++++" 52 | "++++++++++++++++++++++++++++++++++++++++++++++++" 53 | "++++++++++++++++++++++++++++++++++++++++++++++++" 54 | "................................................" 55 | "................................................" 56 | "................................................" 57 | "................................................" 58 | "...+++.....+++..++....++..++...++....+..++++...." 59 | "..++..+...++.++.++....++.++++.++.++..+.++...+..." 60 | "...++....+...++.++....++.++++.++..++.+.++......." 61 | "....++..+++++++.++...++..++++.++...+++.++.++...." 62 | "..+..++.++...++.++..++...++++.++....++.++...+..." 63 | "...+++..++...++..++++.....++..++....++..++++...." 64 | "................................................" 65 | "................................................" 66 | "................................................" 67 | "................................................" 68 | "................................................" 69 | "................................................"; 70 | 71 | static char vmu_screen_loading[] = 72 | "................................................" 73 | "........+++++++......+++....++.++++++++.++++++++" 74 | ".......+++++++......++++...++.++++++++.++++++++." 75 | "......++...........++.++..++.++.......++........" 76 | ".....+++++..++.++.++..++,++.++++.....++++++++..." 77 | "....+++++..+++++.++...++++.++.............++...." 78 | "...++.....++....++....+++.+++++++.+++++++++....." 79 | "..++.....++....++.....++.+++++++.+++++++++......" 80 | "................................................" 81 | "++++++++++++++++++++++++++++++++++++++++++++++++" 82 | "+++++.+++.+....+...+++++++++..++++....++++.+++++" 83 | "+++++.+++.+.++++.++.+++++++.++.++++++.+++..+++++" 84 | "+++++.+++.+...++...++++++++.++.+++++.+++++.+++++" 85 | "++++++.+.++.++++.++.+++++++.++.++++.++++++.+++++" 86 | "+++++++.+++....+.++.+.++++++..++.++.++.++...++++" 87 | "++++++++++++++++++++++++++++++++++++++++++++++++" 88 | "++++++++++++++++++++++++++++++++++++++++++++++++" 89 | "................................................" 90 | "................................................" 91 | "................................................" 92 | "................................................" 93 | ".++......++++.....+++..++++..++..++....+..++++.." 94 | ".++.....++..++...++.++.++..+.++.++.++..+.++...+." 95 | ".++.....++..++..+...++.++..+.++.++..++.+.++....." 96 | ".++.....++..++.+++++++.++..+.++.++...+++.++.++.." 97 | ".++++++.++++++.++...++.++..+.++.++....++.++...+." 98 | "..++++...++++..++...++.++++..++.++....++..++++.." 99 | "................................................" 100 | "................................................" 101 | "................................................" 102 | "................................................"; 103 | 104 | static char vmu_screen_error[] = 105 | "................................................" 106 | "........+++++++......+++....++.++++++++.++++++++" 107 | ".......+++++++......++++...++.++++++++.++++++++." 108 | "......++...........++.++..++.++.......++........" 109 | ".....+++++..++.++.++..++,++.++++.....++++++++..." 110 | "....+++++..+++++.++...++++.++.............++...." 111 | "...++.....++....++....+++.+++++++.+++++++++....." 112 | "..++.....++....++.....++.+++++++.+++++++++......" 113 | "................................................" 114 | "++++++++++++++++++++++++++++++++++++++++++++++++" 115 | "+++++.+++.+....+...+++++++++..++++....++++.+++++" 116 | "+++++.+++.+.++++.++.+++++++.++.++++++.+++..+++++" 117 | "+++++.+++.+...++...++++++++.++.+++++.+++++.+++++" 118 | "++++++.+.++.++++.++.+++++++.++.++++.++++++.+++++" 119 | "+++++++.+++....+.++.+.++++++..++.++.++.++...++++" 120 | "++++++++++++++++++++++++++++++++++++++++++++++++" 121 | "++++++++++++++++++++++++++++++++++++++++++++++++" 122 | "................................................" 123 | "................................................" 124 | "................................................" 125 | "................................................" 126 | "..++++.++++..++++...+++..++++...+....+....+....." 127 | ".++....++..+.++..+.++.++.++..+.+++..+++..+++...." 128 | ".++++..++..+.++..+.++.++.++..+.+++..+++..+++...." 129 | ".++....++++. ++++..++.++.++++..+++..+++..+++...." 130 | ".++....++..+.++..+.++.++.++.++.................." 131 | "..++++.++..+.++..+..+++..++.++..+....+....+....." 132 | "................................................" 133 | "................................................" 134 | "................................................" 135 | "................................................"; 136 | --------------------------------------------------------------------------------