Skip to content
This repository has been archived by the owner on Mar 24, 2024. It is now read-only.

Add Game Genie Support for NES #186

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ venv

**/*.pyc

*.sw[mnop]
3 changes: 2 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[submodule "retro-go-stm32"]
path = retro-go-stm32
url = https://github.com/kbeckmann/retro-go-stm32
# BEFORE SHIPPING: Change back to main repo
url = https://github.com/martaaay/retro-go-stm32
[submodule "LCD-Game-Emulator"]
path = LCD-Game-Emulator
url = https://github.com/bzhxx/LCD-Game-Emulator.git
7 changes: 6 additions & 1 deletion Core/Inc/retro-go/rg_emulators.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ typedef enum
typedef struct rom_system_t rom_system_t;

typedef struct {
uint32_t id;
const char *name;
const char *ext;
// char folder[32];
Expand All @@ -25,6 +26,10 @@ typedef struct {
bool missing_cover;
rom_region_t region;
const rom_system_t *system;

const char** game_genie_codes; // Game Genie codes to choose from
const char** game_genie_descs; // Game Genie code descriptions
int game_genie_count;
} retro_emulator_file_t;

typedef struct {
Expand All @@ -44,7 +49,7 @@ typedef struct {
void emulators_init();
void emulator_init(retro_emulator_t *emu);
void emulator_start(retro_emulator_file_t *file, bool load_state, bool start_paused);
void emulator_show_file_menu(retro_emulator_file_t *file);
bool emulator_show_file_menu(retro_emulator_file_t *file);
void emulator_show_file_info(retro_emulator_file_t *file);
void emulator_crc32_file(retro_emulator_file_t *file);
bool emulator_build_file_object(const char *path, retro_emulator_file_t *out_file);
Expand Down
24 changes: 23 additions & 1 deletion Core/Src/porting/nes/main_nes.c
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,29 @@ int app_main_nes(uint8_t load_state, uint8_t start_paused)
HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t *) audiobuffer_dma, (2 * AUDIO_SAMPLE_RATE) / 60);
}

nofrendo_start(ACTIVE_FILE->name, nes_region, AUDIO_SAMPLE_RATE, false);
int game_genie_count = 0;
const char **active_game_genie_codes = NULL;
#if GAME_GENIE == 1
for(int i=0; i<MAX_GAME_GENIE_CODES && i<ACTIVE_FILE->game_genie_count; i++) {
if (odroid_settings_ActiveGameGenieCodes_is_enabled(ACTIVE_FILE->id, i)) {
game_genie_count++;
}
}

active_game_genie_codes = rg_alloc(game_genie_count * sizeof(char**), MEM_ANY);
for(int i=0, j=0; i<MAX_GAME_GENIE_CODES && i<ACTIVE_FILE->game_genie_count; i++) {
if (odroid_settings_ActiveGameGenieCodes_is_enabled(ACTIVE_FILE->id, i)) {
active_game_genie_codes[j] = ACTIVE_FILE->game_genie_codes[i];
j++;
}
}
#endif

nofrendo_start(ACTIVE_FILE->name, active_game_genie_codes, game_genie_count, nes_region, AUDIO_SAMPLE_RATE, false);

#if GAME_GENIE == 1
rg_free(active_game_genie_codes); // No need to clean up the objects in the array as they're allocated in read only space
#endif

return 0;
}
4 changes: 2 additions & 2 deletions Core/Src/porting/nes/nofrendo_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void nofrendo_stop(void)
// vid_shutdown();
}

int nofrendo_start(const char *filename, int region, int sample_rate, bool stereo)
int nofrendo_start(const char *filename, const char **game_genie_codes, int game_genie_codes_count, int region, int sample_rate, bool stereo)
{
if (osd_init())
return -1;
Expand All @@ -97,7 +97,7 @@ int nofrendo_start(const char *filename, int region, int sample_rate, bool stere
return -1;
}

if (!nes_insertcart(filename))
if (!nes_insertcart(filename, game_genie_codes, game_genie_codes_count))
{
MESSAGE_ERROR("Failed to insert NES cart.\n");
return -2;
Expand Down
4 changes: 3 additions & 1 deletion Core/Src/porting/odroid_overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ int odroid_overlay_game_menu()
static uint16_t overlay_buffer[ODROID_SCREEN_WIDTH * 32 * 2] __attribute__ ((aligned (4)));
static short dialog_open_depth = 0;
static short font_size = 8;
char* ODROID_DIALOG_VALUE_ON = "ON";
char* ODROID_DIALOG_VALUE_OFF = "OFF";

void odroid_overlay_init()
{
Expand Down Expand Up @@ -203,7 +205,7 @@ static int get_dialog_items_count(odroid_dialog_choice_t *options)
if (options == NULL)
return 0;

for (int i = 0; i < 16; i++)
for (int i = 0; i < 17; i++)
{
// if (memcmp(&last, options + i, sizeof(last))) {
if (options[i].id == last.id && options[i].enabled == last.enabled) {
Expand Down
47 changes: 46 additions & 1 deletion Core/Src/porting/odroid_settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "odroid_settings.h"
#include "main.h"
#include "appid.h"
#include "game_genie.h"

#define CONFIG_MAGIC 0xcafef00d
#define ODROID_APPID_COUNT 4
Expand All @@ -25,6 +26,15 @@ typedef struct app_config {
uint8_t sprite_limit;
} app_config_t;

#if GAME_GENIE == 1
#if MAX_GAME_GENIE_CODES != 16
#error MAX_GAME_GENIE_CODES is assumed to be 16. Changing this value requires adjusting the type of active_game_genie_codes below
#endif
typedef struct rom_config {
uint16_t active_game_genie_codes; // A bit array for which game genie codes in retro_emulator_file_t.game_genie_codes are active for this rom
} rom_config_t;
#endif

typedef struct persistent_config {
uint32_t magic;
uint8_t version;
Expand All @@ -42,12 +52,16 @@ typedef struct persistent_config {

app_config_t app[APPID_COUNT];

#if GAME_GENIE == 1
rom_config_t rom[ROM_COUNT]; // index is the same as 'id' in retro_emulator_file_t
#endif

uint32_t crc32;
} persistent_config_t;

static const persistent_config_t persistent_config_default = {
.magic = CONFIG_MAGIC,
.version = 4,
.version = 5,

.backlight = ODROID_BACKLIGHT_LEVEL6,
.start_action = ODROID_START_ACTION_RESUME,
Expand Down Expand Up @@ -75,6 +89,9 @@ static const persistent_config_t persistent_config_default = {
{0}, // PCE
{0}, // GW
},
#if GAME_GENIE == 1
.rom = {{0}},
#endif
};

__attribute__((section (".configflash"))) __attribute__((aligned(4096))) persistent_config_t persistent_config_flash;
Expand Down Expand Up @@ -331,3 +348,31 @@ void odroid_settings_DisplayOverscan_set(int32_t value)
{
persistent_config_ram.app[odroid_system_get_app()->id].disp_overscan = value;
}


#if GAME_GENIE == 1
bool odroid_settings_ActiveGameGenieCodes_is_enabled(uint32_t rom_id, int code_index)
{
if (rom_id < 0 || rom_id >= ROM_COUNT || code_index < 0 || code_index > MAX_GAME_GENIE_CODES) {
return false;
}

uint16_t active_game_genie_codes = persistent_config_ram.rom[rom_id].active_game_genie_codes;
return ((active_game_genie_codes >> code_index) & 0x1) == 1;
}

bool odroid_settings_ActiveGameGenieCodes_set(uint32_t rom_id, int code_index, bool enable)
{
if (rom_id < 0 || rom_id >= ROM_COUNT || code_index < 0 || code_index > MAX_GAME_GENIE_CODES) {
return false;
}

if (enable) {
persistent_config_ram.rom[rom_id].active_game_genie_codes |= (1<<code_index);
} else {
persistent_config_ram.rom[rom_id].active_game_genie_codes &= ~(1<<code_index);
}

return true;
}
#endif
86 changes: 83 additions & 3 deletions Core/Src/retro-go/rg_emulators.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
static retro_emulator_t emulators[MAX_EMULATORS];
static int emulators_count = 0;

static retro_emulator_file_t *CHOSEN_FILE = NULL;

retro_emulator_t *file_to_emu(retro_emulator_file_t *file) {
for (int i = 0; i < MAX_EMULATORS; i++)
if (emulators[i].system == file->system)
Expand Down Expand Up @@ -73,8 +75,12 @@ static void event_handler(gui_event_t event, tab_t *tab)

if (event == KEY_PRESS_A)
{
emulator_show_file_menu(file);
gui_redraw();
while(true) {
bool redraw = emulator_show_file_menu(file);
gui_redraw();
gui_redraw();
if (!redraw) break;
}
}
else if (event == KEY_PRESS_B)
{
Expand Down Expand Up @@ -328,8 +334,59 @@ void emulator_show_file_info(retro_emulator_file_t *file)
odroid_overlay_dialog("Properties", choices, -1);
}

void emulator_show_file_menu(retro_emulator_file_t *file)
#if GAME_GENIE == 1
static bool game_genie_update_cb(odroid_dialog_choice_t *option, odroid_dialog_event_t event, uint32_t repeat)
{
if (event == ODROID_DIALOG_PREV || event == ODROID_DIALOG_NEXT) {
if (option->value == ODROID_DIALOG_VALUE_OFF) {
bool result = odroid_settings_ActiveGameGenieCodes_set(CHOSEN_FILE->id, option->id, true);
if (result) {
option->value = ODROID_DIALOG_VALUE_ON;
} else {
option->value = ODROID_DIALOG_VALUE_OFF;
}
} else {
option->value = ODROID_DIALOG_VALUE_OFF;
odroid_settings_ActiveGameGenieCodes_set(CHOSEN_FILE->id, option->id, false);
}
}

return event == ODROID_DIALOG_ENTER;
}

static bool show_game_genie_dialog()
{
static odroid_dialog_choice_t last = ODROID_DIALOG_CHOICE_LAST;

// +1 for the terminator sentinel
odroid_dialog_choice_t *choices = rg_alloc((CHOSEN_FILE->game_genie_count + 1) * sizeof(odroid_dialog_choice_t), MEM_ANY);
for(int i=0; i<CHOSEN_FILE->game_genie_count; i++) {
const char *label = CHOSEN_FILE->game_genie_descs[i];
if (label == NULL) {
label = CHOSEN_FILE->game_genie_codes[i];
}
bool is_on = odroid_settings_ActiveGameGenieCodes_is_enabled(CHOSEN_FILE->id, i);
choices[i].id = i;
choices[i].label = label;
choices[i].value = is_on ? ODROID_DIALOG_VALUE_ON : ODROID_DIALOG_VALUE_OFF;
choices[i].enabled = 1;
choices[i].update_cb = game_genie_update_cb;
}
choices[CHOSEN_FILE->game_genie_count] = last;

odroid_overlay_dialog("Game Genie Codes", choices, 0);

rg_free(choices);

odroid_settings_commit();

return false;
}
#endif

bool emulator_show_file_menu(retro_emulator_file_t *file)
{
CHOSEN_FILE = file;
// char *save_path = odroid_system_get_path(ODROID_PATH_SAVE_STATE, emu_get_file_path(file));
// char *sram_path = odroid_system_get_path(ODROID_PATH_SAVE_SRAM, emu_get_file_path(file));
// bool has_save = odroid_sdcard_get_filesize(save_path) > 0;
Expand All @@ -339,6 +396,16 @@ void emulator_show_file_menu(retro_emulator_file_t *file)
bool has_save = 1;
bool has_sram = 0;
bool is_fav = 0;
bool force_redraw = false;

#if GAME_GENIE == 1
odroid_dialog_choice_t last = ODROID_DIALOG_CHOICE_LAST;
odroid_dialog_choice_t game_genie_row = {4, "Game Genie Codes", "", 1, NULL};
odroid_dialog_choice_t game_genie_choice = last;
if (strcmp(file->system->system_name, "Nintendo Entertainment System") == 0) {
game_genie_choice = game_genie_row;
}
#endif

odroid_dialog_choice_t choices[] = {
#if STATE_SAVING == 1
Expand All @@ -349,6 +416,10 @@ void emulator_show_file_menu(retro_emulator_file_t *file)
{3, is_fav ? "Del favorite" : "Add favorite", "", 1, NULL},
#if STATE_SAVING == 1
{2, "Delete save ", "", has_save || has_sram, NULL},
#endif
#if GAME_GENIE == 1
{0, "------------", "", -1, NULL},
game_genie_choice,
#endif
ODROID_DIALOG_CHOICE_LAST
};
Expand All @@ -369,9 +440,18 @@ void emulator_show_file_menu(retro_emulator_file_t *file)
// else
// favorite_add(file);
}
else if (sel == 4) {
#if GAME_GENIE == 1
show_game_genie_dialog();
force_redraw = true;
#endif
}

// free(save_path);
// free(sram_path);
CHOSEN_FILE = NULL;

return force_redraw;
}

void emulator_start(retro_emulator_file_t *file, bool load_state, bool start_paused)
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Core/Src/bilinear.c \
Core/Src/gw_buttons.c \
Core/Src/gw_flash.c \
Core/Src/gw_lcd.c \
Core/Src/game_genie.c \
Core/Src/main.c \
Core/Src/sha256.c \
Core/Src/flashapp.c \
Expand Down
12 changes: 10 additions & 2 deletions Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ ifeq ($(STATE_SAVING),0)
SAVE_PARAM := --no-save
endif

# Set to 1 to add game genie support
GAME_GENIE ?= 0

# Screenshot support allocates 150kB of external flash. Disabled by default for 1MB flash.
ifeq ($(EXTFLASH_SIZE), 1048576)
ENABLE_SCREENSHOT ?= 0
Expand Down Expand Up @@ -278,7 +281,8 @@ C_DEFS += \
-DSTATE_SAVING=$(STATE_SAVING) \
-DENABLE_SCREENSHOT=$(ENABLE_SCREENSHOT) \
-DGNW_TARGET_MARIO=$(GNW_TARGET_MARIO) \
-DGNW_TARGET_ZELDA=$(GNW_TARGET_ZELDA)
-DGNW_TARGET_ZELDA=$(GNW_TARGET_ZELDA) \
-DGAME_GENIE=$(GAME_GENIE) \

# AS includes
AS_INCLUDES +=
Expand Down Expand Up @@ -384,7 +388,9 @@ $(BUILD_DIR)/rom_files.txt: FORCE | $(BUILD_DIR)
$(V)$(ECHO) [ BASH ] Checking for updated roms
$(V)./scripts/update_rom_files.sh build/rom_files.txt roms/gb roms/nes roms/sms roms/gg roms/col roms/pce roms/sg roms/gw

$(BUILD_DIR)/roms.a: $(BUILD_DIR)/rom_files.txt parse_roms.py
roms/*/*.ggcodes:

$(BUILD_DIR)/roms.a: $(BUILD_DIR)/rom_files.txt parse_roms.py roms/*/*.ggcodes
$(V)$(ECHO) [ PYTHON3 ] $(notdir $<)
$(V)$(PYTHON3) parse_roms.py --flash-size $(EXTFLASH_SIZE) $(SAVE_PARAM) $(COMPRESS_PARAM)

Expand Down Expand Up @@ -646,6 +652,7 @@ help:
@echo " Set to 0 to disable power saving (default=1)"
@echo " ENABLE_SCREENSHOT - Set to 1 to enable screenshot support (default disabled if extflash is 1MB)"
@echo " GNW_TARGET - Game & Watch target, Valid values {mario,zelda} (default=mario)"
@echo " GAME_GENIE - Set to 1 to enable game genie support (default=0)"
@echo ""
@echo "Current configuration:"
@echo " EXTFLASH_FORCE_SPI=$(EXTFLASH_FORCE_SPI)"
Expand All @@ -659,6 +666,7 @@ help:
@echo " RESET_DBGMCU=$(RESET_DBGMCU)"
@echo " ENABLE_SCREENSHOT=$(ENABLE_SCREENSHOT)"
@echo " GNW_TARGET=$(GNW_TARGET)"
@echo " GAME_GENIE=$(GAME_GENIE)"
@echo " GCC_PATH=$(GCC_PATH)"
@echo " PREFIX=$(PREFIX)"
@echo ""
Expand Down
Loading