diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 913a068d..6bb40576 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -131,6 +131,11 @@ m_flashrom.c: .text: [0x803AC5C8, 0x803AF48C] .data: [0x80654188, 0x80654298] .bss: [0x81295BD8, 0x81295C30] +m_font.c: + .text: [0x803AF48C, 0x803B15E0] + .rodata: [0x80642080, 0x80642258] + .data: [0x80654298, 0x806544D0] + .bss: [0x81295C30, 0x81295C70] m_fuusen.c: .text: [0x803B15E0, 0x803B1908] .rodata: [0x80642258, 0x80642288] diff --git a/include/Famicom/famicom.h b/include/Famicom/famicom.h index b1b63014..06ca55ca 100644 --- a/include/Famicom/famicom.h +++ b/include/Famicom/famicom.h @@ -8,13 +8,18 @@ extern "C" { #endif +#define FAMICOM_INTERNAL_ROM_NUM 19 + +#define NESTAG_CMD_SIZE 3 +#define NESTAG_SIZE (NESTAG_CMD_SIZE + 1) + #define NESTAG_END "END" #define NESTAG_VEQ "VEQ" #define NESTAG_VNE "VNE" #define NESTAG_GID "GID" #define NESTAG_GNM "GNM" #define NESTAG_CPN "CPN" -#define NESTAG_OFS "OFS" +#define NESTAG_OFS "OFS" /* Offset into the shared highscore data to read/write at */ #define NESTAG_HSC "HSC" #define NESTAG_GNO "GNO" #define NESTAG_BBR "BBR" @@ -100,6 +105,8 @@ typedef struct famicom_common_s { extern void* my_malloc_current; extern u8 save_game_image; +extern FamicomCommon famicomCommon; + typedef u8 (*FAMICOM_GETSAVECHAN_PROC)(int* player_no, int* slot_card_result); extern void famicom_setCallback_getSaveChan(FAMICOM_GETSAVECHAN_PROC getSaveChan_proc); extern int famicom_mount_archive(); @@ -109,6 +116,8 @@ extern int famicom_1frame(); extern int famicom_init(int, void*, u8); extern int famicom_cleanup(); +extern void nesinfo_tags_set(int rom_no); + #ifdef __cplusplus } diff --git a/include/Famicom/ks_nes_common.h b/include/Famicom/ks_nes_common.h index daa108d8..6642239f 100644 --- a/include/Famicom/ks_nes_common.h +++ b/include/Famicom/ks_nes_common.h @@ -27,7 +27,8 @@ typedef struct ks_nes_common_work_obj_s { } ksNesCommonWorkObj; typedef struct ks_nes_state_obj_s { - u8 _temp[0x1A78]; + /* 0x0000 */ u8 wram[2048]; + /* 0x0800 */ u8 _temp[0x1A78 - 0x800]; } ksNesStateObj; #ifdef __cplusplus diff --git a/include/_mem.h b/include/_mem.h index f5134435..9174dcae 100644 --- a/include/_mem.h +++ b/include/_mem.h @@ -11,6 +11,7 @@ extern "C" { void * memcpy(void * dst, const void * src, size_t n); void * memset(void * dst, int val, size_t n); +int memcmp(const void* src1, const void* src2, size_t n); void __fill_mem(void * dst, int val, unsigned long n); #pragma section code_type diff --git a/src/m_font_main.c_inc b/src/m_font_main.c_inc index e7d4357e..1bde1bf9 100644 --- a/src/m_font_main.c_inc +++ b/src/m_font_main.c_inc @@ -39,7 +39,7 @@ typedef struct control_code_s { s8 attribute; } mFont_ControlCodeInfo_t; -static mFont_ControlCodeInfo_t mFont_cont_info_tbl[mFont_CONT_CODE_NUM] = { +static const mFont_ControlCodeInfo_t mFont_cont_info_tbl[mFont_CONT_CODE_NUM] = { { 2, mFont_CONT_ATTRIBUTE_0 }, { 2, mFont_CONT_ATTRIBUTE_0 }, { 2, mFont_CONT_ATTRIBUTE_0 }, @@ -669,7 +669,6 @@ static void mFont_gppDrawCharRect( *gfx_pp = g; } -// TODO: Non-matching static void mFont_gppDrawCharPoly( GRAPH* graph, Gfx** gfx_pp, @@ -683,21 +682,29 @@ static void mFont_gppDrawCharPoly( int ulx, uly, lrx, lry; xy_t vert_tl, vert_br; f32 inv_half_s, inv_half_t; + f32 t0, t1; mFont_gppLoadTexture(&g, c, &uls, &ult, &lrs, &lrt); vert_tl.x = pos_tl->x - ((f32)SCREEN_WIDTH * 0.5f); vert_tl.y = -(pos_tl->y - ((f32)SCREEN_HEIGHT * 0.5f)); - vert_br.x = pos_br->x - ((f32)SCREEN_WIDTH * 0.5f) - vert_tl.x; - vert_br.y = -(pos_br->y - ((f32)SCREEN_HEIGHT * 0.5f)) - vert_tl.y; + vert_br.x = vert_tl.x; + vert_br.y = vert_tl.y; + t0 = pos_br->x - ((f32)SCREEN_WIDTH * 0.5f) - vert_tl.x; + t1 = -(pos_br->y - ((f32)SCREEN_HEIGHT * 0.5f)) - vert_tl.y; inv_half_s = 0.5f / (f32)s; inv_half_t = 0.5f / (f32)t; + + vert_br.x += t0 * (1.0f - inv_half_s); + vert_br.y += t1 * (1.0f - inv_half_t); + vert_tl.x += t0 * inv_half_s; + vert_tl.y += t1 * inv_half_t; - ulx = (vert_tl.x + vert_br.x * inv_half_s) * mFont_SCALE_F; - uly = (vert_tl.y + vert_br.y * inv_half_t) * mFont_SCALE_F; - lrx = (vert_tl.x + vert_br.x * (1.0f - inv_half_s)) * mFont_SCALE_F; - lry = (vert_tl.y + vert_br.y * (1.0f - inv_half_t)) * mFont_SCALE_F; + ulx = (int)(vert_tl.x * mFont_SCALE_F); + uly = (int)(vert_tl.y * mFont_SCALE_F); + lrx = (int)(vert_br.x * mFont_SCALE_F); + lry = (int)(vert_br.y * mFont_SCALE_F); lrs = ((uls + s) << 6) - 32; lrt = ((ult + t) << 6) - 32; diff --git a/src/static/Famicom/famicom_nesinfo.cpp b/src/static/Famicom/famicom_nesinfo.cpp new file mode 100644 index 00000000..22c05cc0 --- /dev/null +++ b/src/static/Famicom/famicom_nesinfo.cpp @@ -0,0 +1,276 @@ +#include "Famicom/famicom.h" + +#include "_mem.h" +#include "dolphin/os.h" + +static u8 highscore_num = 0; +static u8 highscore_updated = 0; +static u8* highscore_flags = nullptr; +static u8 nesinfo_mcrd_cont_no = 0; +static u8* nesinfo_mcrd_game_name = nullptr; +static u8* nesinfo_ptr = nullptr; +static u32 nesinfo_tags_size = 0; +static u8* nesinfo_tags_start = nullptr; +static u8* nesinfo_tags_end = nullptr; +static char* nesinfo_tags_gameName = nullptr; +static char* nesinfo_tags_kanjiName = nullptr; +static u8* nesinfo_tags_moriName = nullptr; +static u32 nesinfo_data_size = 0; +static u8* nesinfo_data_start = nullptr; +static u8* nesinfo_data_end = nullptr; +static u32 nesinfo_rom_size = 0; +static u8* nesinfo_rom_start = nullptr; +static u8* nesinfo_rom_end = nullptr; +static u32 nesinfo_expand_rom_size = 0; +static bool tcs_bad = false; +static bool ics_bad = false; + +enum highscore_state { HIGHSCORE_STATE_UNSET, HIGHSCORE_STATE_SET, HIGHSCORE_STATE_2, HIGHSCORE_STATE_UNINITIALIZED }; + +enum famicom_games { + FAMICOM_GAME_CLU_CLU_LAND, + FAMICOM_GAME_BALLOON_FIGHT, + FAMICOM_GAME_DONKEY_KONG, + FAMICOM_GAME_DONKEY_KONG_JR_MATH, + FAMICOM_GAME_PINBALL, + +}; + +#define END_TAG() 'E', 'N', 'D', 0 +#define GID_TAG(l) 'G', 'I', 'D', (l) +#define GNM_TAG(l) 'G', 'N', 'M', (l) +#define GNO_TAG() 'G', 'N', 'O', sizeof(u8) +#define OFS_TAG() 'O', 'F', 'S', sizeof(u16) +#define HSC_TAG(l) 'H', 'S', 'C', (sizeof(u16) + l) + +#define OFS_U16(ofs) ((u8)((u32)(ofs) >> 8), (u8)(ofs)) + +static u8 tags_table_default[] = { END_TAG() }; + +// clang-format off +static u8 tags_table_cluclu_land[] = { + GID_TAG(2), 'C', 'L', + GNM_TAG(12), 'C', 'L', 'U', ' ', 'C', 'L', 'U', ' ', 'L', 'A', 'N', 'D', + GNO_TAG(), FAMICOM_GAME_CLU_CLU_LAND, + OFS_TAG(), OFS_U16(0x0000), + HSC_TAG(4), OFS_U16(0x8020), 0, 0, 0, 0, + END_TAG(), +}; + +static u8 tags_table_balloon_fight[] = { + GID_TAG(2), 'B', 'F', + GNM_TAG(13), 'B', 'A', 'L', 'L', 'O', 'O', 'N', ' ', 'F', 'I', 'G', 'H', 'T', + GNO_TAG(), FAMICOM_GAME_BALLOON_FIGHT, + OFS_TAG(), OFS_U16(0x0004), + HSC_TAG(5), OFS_U16(0x0629), 0, 0, 0, 1, 0, + HSC_TAG(5), OFS_U16(0x062E), 0, 0, 0, 1, 0, + HSC_TAG(5), OFS_U16(0x0633), 0, 0, 5, 2, 0, + END_TAG(), +}; + +static u8 tags_table_donkey_kong[] = { + GID_TAG(2), 'D', 'K', + GNM_TAG(11), 'D', 'O', 'N', 'K', 'E', 'Y', ' ', 'K', 'O', 'N', 'G', + GNO_TAG(), FAMICOM_GAME_DONKEY_KONG, + OFS_TAG(), OFS_U16(0x0013), + HSC_TAG(2), OFS_U16(0x0507), 0, 0, + HSC_TAG(2), OFS_U16(0x0509), 0, 0, + END_TAG(), +}; + +static u8 tags_table_sansu_asobi[] = { + GID_TAG(2), 'C', 'A', + GNM_TAG(13), 'D', 'O', 'N', 'K', 'Y', ' ', 'J', 'R', ' ', 'M', 'A', 'T', 'H', + GNO_TAG(), FAMICOM_GAME_DONKEY_KONG_JR_MATH, + OFS_TAG(), OFS_U16(0x0017), + HSC_TAG(2), OFS_U16(0x04D7), 0, 0, + HSC_TAG(2), OFS_U16(0x04D9), 0, 0, + HSC_TAG(2), OFS_U16(0x04DB), 0, 0, + HSC_TAG(2), OFS_U16(0x04DD), 0, 0, + HSC_TAG(2), OFS_U16(0x04DF), 0, 0, + HSC_TAG(2), OFS_U16(0x04E1), 0, 0, + HSC_TAG(2), OFS_U16(0x04E3), 0, 0, + HSC_TAG(2), OFS_U16(0x04E5), 0, 0, + HSC_TAG(2), OFS_U16(0x04E7), 0, 0, + END_TAG(), +}; + +static u8 tags_table_pinball[] = { + GID_TAG(2), 'P', 'N', + GNM_TAG(7), 'P', 'I', 'N', 'B', 'A', 'L', 'L', + GNO_TAG(), FAMICOM_GAME_PINBALL, + OFS_TAG(), OFS_U16(0x0029), + HSC_TAG(2), OFS_U16(0x0507), 0, 0, + HSC_TAG(2), OFS_U16(0x0509), 0, 0, + END_TAG(), +}; + +typedef struct nesinfo_tag_s { + u8* tags_table; + size_t tags_size; + char* gameName; + char* kanjiName; +} nesinfo_tag_info; + +static nesinfo_tag_info tags_table_table[FAMICOM_INTERNAL_ROM_NUM]; + +// clang-format on + +static u8 moriNameTable[FAMICOM_INTERNAL_ROM_NUM][16] = { + // TODO +}; + +static void update_highscore_raw(u32 ofs, u32 size, u8* initial_value, u8* high_score, u8* state) { + u8* current_score_p = &famicomCommon.sp->wram[ofs]; + + if (*state == HIGHSCORE_STATE_UNINITIALIZED) { + memcpy(high_score, initial_value, size); + *state = HIGHSCORE_STATE_UNSET; // default highscore + // High score data was not found, so it has been initialized. + OSReport("ハイスコアデータがないので初期化しました\n"); + } + + if (*state == HIGHSCORE_STATE_UNSET) { + if (memcmp(current_score_p, initial_value, size) == 0) { + // The high score in WRAM has been reset to its default value. + OSReport("WRAMのハイスコアが初期値になりました\n"); + memcpy(current_score_p, high_score, size); + *state = HIGHSCORE_STATE_SET; + } else { + // The high score in WRAM has not been reset to its default value. Offset=%04x\n + OSReport("WRAMのハイスコアが初期値になっていません オフセット=%04x\n", ofs); + } + } else { + if (memcmp(current_score_p, high_score, size) != 0) { + // The high score in WRAM has been updated. + OSReport("WRAMのハイスコアが更新されました\n"); + memcpy(high_score, current_score_p, size); + highscore_updated = true; + } + } +} + +static u16 nesinfo_get_u16(u8* data) { + return (u16)(((u32)data[0] << 8) + (u32)data[1]); +} + +static u8 nesinfo_get_u8(u8* data) { + return (u8)(u32)data[0]; +} + +static void nesinfo_set_u16(u8* data, u16* value) { + data[0] = (u8)(((u32)value >> 8) & 0xFF); + data[1] = (u8)((u32)value & 0xFF); +} + +static u8* nesinfo_next_tag_raw(u8* data) { + if (data == nullptr || (nesinfo_tags_end != nullptr && data >= nesinfo_tags_end) || + memcmp(data, NESTAG_END, NESTAG_CMD_SIZE) == 0) { + return nullptr; + } else { + return &data[data[NESTAG_CMD_SIZE] + NESTAG_SIZE]; + } +} + +static u8* nesinfo_next_tag(u8* data) { + do { + data = nesinfo_next_tag_raw(data); + if (data == nullptr) { + break; + } + + if (memcmp(data, NESTAG_VEQ, NESTAG_CMD_SIZE) == 0) { + if (data[NESTAG_SIZE + 1] != 1) { + data = nesinfo_next_tag_raw(data); + } + } else if (memcmp(data, NESTAG_VNE, NESTAG_CMD_SIZE) == 0) { + if (data[NESTAG_SIZE + 1] == 1) { + data = nesinfo_next_tag_raw(data); + } + } else { + break; // found a tag to return + } + } while (data != nullptr); + + return data; +} + +static u16 calc_check_sum2(void* data, size_t size) { + if (((u32)data & 1) == 0) { + u16 sum; + size_t i; + u16* data2; + + data2 = (u16*)data; + sum = 0; + for (i = 0; i < size; i += 2) { + sum += *data2++; + } + + return sum; + } else { + u16 sum0; + u16 sum1; + size_t i; + u8* data_u8; + + data_u8 = (u8*)data; + sum0 = 0; + sum1 = 0; + for (i = 0; i < size - 1; i += sizeof(u16)) { + sum0 += data_u8[0]; + sum1 += data_u8[1]; + data_u8 += sizeof(u16); + } + + if (i < size) { + sum0 += data_u8[0]; + data_u8 += sizeof(u8); + } + + return (u16)((sum0 << 8) + sum1); + } +} + +static void print_stringn_lf(u8* data, size_t size) { + while (size-- > 0) { + OSReport("%c", *data++); + } + + OSReport("\n"); +} + +static void print_hex_lf(u8* data, size_t size) { + while (size-- > 0) { + OSReport(" %02x", *data++); + } + + OSReport("\n"); +} + +extern void nesinfo_tags_set(int rom_no) { + nesinfo_tags_start = nullptr; + nesinfo_tags_end = nullptr; + nesinfo_tags_size = 0; + nesinfo_tags_gameName = nullptr; + nesinfo_tags_kanjiName = nullptr; + nesinfo_tags_moriName = nullptr; + + if (rom_no < 0) { + return; + } + + if (rom_no < 0 || rom_no >= FAMICOM_INTERNAL_ROM_NUM) { + return; + } + + nesinfo_tags_start = tags_table_table[rom_no].tags_table; + nesinfo_tags_end = nesinfo_tags_start + tags_table_table[rom_no].tags_size; + nesinfo_tags_size = (u32)(nesinfo_tags_end - nesinfo_tags_start); + nesinfo_tags_gameName = tags_table_table[rom_no].gameName; + nesinfo_tags_kanjiName = tags_table_table[rom_no].kanjiName; + + if (rom_no < FAMICOM_INTERNAL_ROM_NUM) { + nesinfo_tags_moriName = moriNameTable[rom_no]; + } +}