diff --git a/.vscode/launch.json b/.vscode/launch.json index 0ff7549..99f3ae3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -21,23 +21,25 @@ "MIMode": "gdb" }, { - "name": "macOS: Wizardry 安定化 (LOST=15000 + CONST_EXEC=1)", + "name": "macOS: Wizardry 安定化 4MHz", "type": "lldb", "request": "launch", "program": "${workspaceFolder}/build/XM8.app/Contents/MacOS/xm8", "args": [], "cwd": "${workspaceFolder}", "env": { + "XM8_FDC_TRACE": "1", + "XM8_FDC_TRACE_IO": "1", "XM8_FDC_TRACE_MAX_LINES": "400000", + "XM8_FDC_TRACE_FILE": "xm8_fdc_trace_wiz_4mhz_stable.log", "XM8_FDC_SEEK_SCALE": "1000", "XM8_DISABLE_UNSTABLE_MASK": "1", "XM8_FDC_LOST_USEC": "15000", - "XM8_FDC_CONST_EXEC_USEC": "1", - "XM8_FDC_TRACE_FILE": "xm8_fdc_trace_wiz_stable.log" + "XM8_FDC_CONST_EXEC_USEC": "1" } }, { - "name": "macOS: FDCトレース基準 (scale=1000, no-unstable)", + "name": "macOS: Wizardry 安定化 8MHz", "type": "lldb", "request": "launch", "program": "${workspaceFolder}/build/XM8.app/Contents/MacOS/xm8", @@ -47,9 +49,14 @@ "XM8_FDC_TRACE": "1", "XM8_FDC_TRACE_IO": "1", "XM8_FDC_TRACE_MAX_LINES": "400000", - "XM8_FDC_SEEK_SCALE": "1000", - "XM8_DISABLE_UNSTABLE_MASK": "1", - "XM8_FDC_TRACE_FILE": "xm8_fdc_trace_s1000_nounstable.log" + "XM8_FDC_TRACE_FILE": "xm8_fdc_trace_wiz_8mhz_stable.log", + "XM8_FDC_SEEK_SCALE_8MHZ": "1500", + "XM8_DISABLE_UNSTABLE_MASK_8MHZ": "1", + "XM8_FDC_LOST_USEC_8MHZ": "12000", + "XM8_FDC_CONST_EXEC_USEC_8MHZ": "1", + "XM8_FDC_CONST_EXEC_DELAY_USEC_8MHZ": "100", + "XM8_FDC_REQUEST_SINGLE_EXEC_8MHZ": "1", + "XM8_FDC_TC_EXEC_8MHZ": "0" } } ] diff --git a/Source/ePC-8801MA/vm/event.cpp b/Source/ePC-8801MA/vm/event.cpp index b4677d8..8cf78d7 100644 --- a/Source/ePC-8801MA/vm/event.cpp +++ b/Source/ePC-8801MA/vm/event.cpp @@ -8,15 +8,49 @@ */ #include "event.h" -#ifdef SDL -#include "z80.h" -#endif // SDL +#ifdef SDL +#include "z80.h" +#include +#endif // SDL #define EVENT_MIX 0 #ifdef SDL #define SINGLE_EXEC_TIMEOUT 10000 // exit single exec mode (us) + +static bool g_single_exec_tuned = false; +static int g_single_exec_timeout_usec = SINGLE_EXEC_TIMEOUT; +static int g_single_exec_slice_clocks = 4; + +static void tune_single_exec_params() +{ + if(g_single_exec_tuned) { + return; + } + g_single_exec_tuned = true; + + // PC-8801MA 8MHz mode needs a wider single-exec window for stable FDC boot timing. + if(config.cpu_type == 0) { + g_single_exec_timeout_usec = 20000; + g_single_exec_slice_clocks = 20; + } + + const char* timeout_env = getenv("XM8_EVENT_SINGLE_EXEC_TIMEOUT_USEC"); + if(timeout_env != NULL && timeout_env[0] != '\0') { + long v = strtol(timeout_env, NULL, 10); + if(v >= 1000 && v <= 1000000) { + g_single_exec_timeout_usec = (int)v; + } + } + const char* slice_env = getenv("XM8_EVENT_SINGLE_EXEC_SLICE_CLOCKS"); + if(slice_env != NULL && slice_env[0] != '\0') { + long v = strtol(slice_env, NULL, 10); + if(v >= 1 && v <= 1024) { + g_single_exec_slice_clocks = (int)v; + } + } +} #endif // SDL void EVENT::initialize() @@ -146,13 +180,14 @@ void EVENT::request_single_exec() void EVENT::drive() { #ifdef SDL + tune_single_exec_params(); if (single_exec == true) { // if passed 10ms, disable single_exec - if (passed_usec(single_exec_clock) > SINGLE_EXEC_TIMEOUT) { + if (passed_usec(single_exec_clock) > g_single_exec_timeout_usec) { single_exec = false; } } -#endif // SDL +#endif // SDL // raise pre frame events to update timing settings for(int i = 0; i < frame_event_count; i++) { @@ -249,8 +284,8 @@ void EVENT::drive() if (main_cpu_exec > 0) { // single execution ? if (single_exec == true) { - if (main_cpu_exec > 4) { - main_cpu_exec = 4; + if (main_cpu_exec > g_single_exec_slice_clocks) { + main_cpu_exec = g_single_exec_slice_clocks; } } cpu_done = d_cpu[0].device->run(main_cpu_exec); @@ -265,11 +300,11 @@ void EVENT::drive() // running sub cpu if (d_cpu[1].update_clocks == 0x400) { // main 4MHz - if (cpu_remain > 0) { - sub_cpu_exec = cpu_remain; + if (cpu_remain > 0) { + sub_cpu_exec = cpu_remain; if (single_exec == true) { - if (sub_cpu_exec > 4) { - sub_cpu_exec = 4; + if (sub_cpu_exec > g_single_exec_slice_clocks) { + sub_cpu_exec = g_single_exec_slice_clocks; } } @@ -279,11 +314,11 @@ void EVENT::drive() } else { // main 8MHz - if (cpu_remain > 2) { - sub_cpu_exec = cpu_remain / 2; + if (cpu_remain > 2) { + sub_cpu_exec = cpu_remain / 2; if (single_exec == true) { - if (sub_cpu_exec > 4) { - sub_cpu_exec = 4; + if (sub_cpu_exec > g_single_exec_slice_clocks) { + sub_cpu_exec = g_single_exec_slice_clocks; } } diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 395df9a..70b25eb 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -86,6 +86,8 @@ static bool g_fdc_disable_unstable_checked = false; static bool g_fdc_disable_unstable = true; static bool g_fdc_const_exec_checked = false; static bool g_fdc_const_exec = true; +static bool g_fdc_const_exec_delay_usec_checked = false; +static int g_fdc_const_exec_delay_usec = 100; static bool g_fdc_request_single_exec_checked = false; static bool g_fdc_request_single_exec = true; static bool g_fdc_tc_exec_checked = false; @@ -95,6 +97,17 @@ static int g_fdc_lost_usec = 15000; static void fdc_trace(const char* fmt, ...); +static bool fdc_is_8mhz_mode() +{ + // PC-8801MA core uses cpu_type==0 as 8MHz path. + return (config.cpu_type == 0); +} + +static const char* fdc_pick_env_name(const char* base_name, const char* mode_name) +{ + return fdc_is_8mhz_mode() ? mode_name : base_name; +} + static bool fdc_trace_enabled() { if(!g_fdc_trace_checked) { @@ -132,7 +145,11 @@ static bool fdc_trace_io_enabled() static int fdc_seek_scale() { if(!g_fdc_seek_scale_checked) { - const char* env = getenv("XM8_FDC_SEEK_SCALE"); + const char* env_name = fdc_pick_env_name("XM8_FDC_SEEK_SCALE", "XM8_FDC_SEEK_SCALE_8MHZ"); + const char* env = getenv(env_name); + if((env == NULL || env[0] == '\0') && fdc_is_8mhz_mode()) { + env = getenv("XM8_FDC_SEEK_SCALE"); + } if(env != NULL && env[0] != '\0') { long v = strtol(env, NULL, 10); if(v >= 1 && v <= 10000) { @@ -147,7 +164,11 @@ static int fdc_seek_scale() static bool fdc_disable_unstable_mask() { if(!g_fdc_disable_unstable_checked) { - const char* env = getenv("XM8_DISABLE_UNSTABLE_MASK"); + const char* env_name = fdc_pick_env_name("XM8_DISABLE_UNSTABLE_MASK", "XM8_DISABLE_UNSTABLE_MASK_8MHZ"); + const char* env = getenv(env_name); + if((env == NULL || env[0] == '\0') && fdc_is_8mhz_mode()) { + env = getenv("XM8_DISABLE_UNSTABLE_MASK"); + } if(env != NULL && env[0] != '\0') { g_fdc_disable_unstable = (env[0] != '0'); } @@ -159,7 +180,11 @@ static bool fdc_disable_unstable_mask() static bool fdc_const_exec_timing() { if(!g_fdc_const_exec_checked) { - const char* env = getenv("XM8_FDC_CONST_EXEC_USEC"); + const char* env_name = fdc_pick_env_name("XM8_FDC_CONST_EXEC_USEC", "XM8_FDC_CONST_EXEC_USEC_8MHZ"); + const char* env = getenv(env_name); + if((env == NULL || env[0] == '\0') && fdc_is_8mhz_mode()) { + env = getenv("XM8_FDC_CONST_EXEC_USEC"); + } if(env != NULL && env[0] != '\0') { g_fdc_const_exec = (env[0] != '0'); } @@ -168,10 +193,33 @@ static bool fdc_const_exec_timing() return g_fdc_const_exec; } +static int fdc_const_exec_delay_usec() +{ + if(!g_fdc_const_exec_delay_usec_checked) { + const char* env_name = fdc_pick_env_name("XM8_FDC_CONST_EXEC_DELAY_USEC", "XM8_FDC_CONST_EXEC_DELAY_USEC_8MHZ"); + const char* env = getenv(env_name); + if((env == NULL || env[0] == '\0') && fdc_is_8mhz_mode()) { + env = getenv("XM8_FDC_CONST_EXEC_DELAY_USEC"); + } + if(env != NULL && env[0] != '\0') { + long v = strtol(env, NULL, 10); + if(v >= 1 && v <= 1000000) { + g_fdc_const_exec_delay_usec = (int)v; + } + } + g_fdc_const_exec_delay_usec_checked = true; + } + return g_fdc_const_exec_delay_usec; +} + static bool fdc_request_single_exec_enabled() { if(!g_fdc_request_single_exec_checked) { - const char* env = getenv("XM8_FDC_REQUEST_SINGLE_EXEC"); + const char* env_name = fdc_pick_env_name("XM8_FDC_REQUEST_SINGLE_EXEC", "XM8_FDC_REQUEST_SINGLE_EXEC_8MHZ"); + const char* env = getenv(env_name); + if((env == NULL || env[0] == '\0') && fdc_is_8mhz_mode()) { + env = getenv("XM8_FDC_REQUEST_SINGLE_EXEC"); + } if(env != NULL && env[0] != '\0') { g_fdc_request_single_exec = (env[0] != '0'); } @@ -183,7 +231,14 @@ static bool fdc_request_single_exec_enabled() static bool fdc_tc_exec_enabled() { if(!g_fdc_tc_exec_checked) { - const char* env = getenv("XM8_FDC_TC_EXEC"); + // 8MHz mode is more stable with legacy PHASE_EXEC->TC path disabled by default. + // 4MHz keeps the previous default behavior. + g_fdc_tc_exec = !fdc_is_8mhz_mode(); + const char* env_name = fdc_pick_env_name("XM8_FDC_TC_EXEC", "XM8_FDC_TC_EXEC_8MHZ"); + const char* env = getenv(env_name); + if((env == NULL || env[0] == '\0') && fdc_is_8mhz_mode()) { + env = getenv("XM8_FDC_TC_EXEC"); + } if(env != NULL && env[0] != '\0') { g_fdc_tc_exec = (env[0] != '0'); } @@ -195,7 +250,11 @@ static bool fdc_tc_exec_enabled() static int fdc_lost_event_usec() { if(!g_fdc_lost_usec_checked) { - const char* env = getenv("XM8_FDC_LOST_USEC"); + const char* env_name = fdc_pick_env_name("XM8_FDC_LOST_USEC", "XM8_FDC_LOST_USEC_8MHZ"); + const char* env = getenv(env_name); + if((env == NULL || env[0] == '\0') && fdc_is_8mhz_mode()) { + env = getenv("XM8_FDC_LOST_USEC"); + } if(env != NULL && env[0] != '\0') { long v = strtol(env, NULL, 10); if(v >= 1 && v <= 10000000) { @@ -221,11 +280,20 @@ static void fdc_dump_runtime_params() int lost_usec = fdc_lost_event_usec(); bool disable_unstable = fdc_disable_unstable_mask(); bool const_exec = fdc_const_exec_timing(); - fdc_trace("runtime_params: seek_scale=%d disable_unstable=%d lost_usec=%d const_exec=%d", + int const_exec_delay_usec = fdc_const_exec_delay_usec(); + bool req_single_exec = fdc_request_single_exec_enabled(); + bool tc_exec = fdc_tc_exec_enabled(); + fdc_trace("runtime_params: cpu_type=%d cpu_power=%d mode=%s seek_scale=%d disable_unstable=%d lost_usec=%d const_exec=%d const_exec_delay_usec=%d req_single_exec=%d tc_exec=%d", + config.cpu_type, + config.cpu_power, + fdc_is_8mhz_mode() ? "8mhz" : "4mhz", seek_scale, disable_unstable ? 1 : 0, lost_usec, - const_exec ? 1 : 0); + const_exec ? 1 : 0, + const_exec_delay_usec, + req_single_exec ? 1 : 0, + tc_exec ? 1 : 0); } static void fdc_trace(const char* fmt, ...) @@ -435,6 +503,8 @@ void UPD765A::release() g_fdc_disable_unstable = true; g_fdc_const_exec_checked = false; g_fdc_const_exec = true; + g_fdc_const_exec_delay_usec_checked = false; + g_fdc_const_exec_delay_usec = 100; g_fdc_request_single_exec_checked = false; g_fdc_request_single_exec = true; g_fdc_tc_exec_checked = false; @@ -1977,7 +2047,7 @@ double UPD765A::get_usec_to_exec_phase() // Optional timing stabilization for troublesome titles: // keep EXEC transition delay deterministic and independent of rotational position. if(fdc_const_exec_timing()) { - return 100; + return fdc_const_exec_delay_usec(); } // XXX: this image may have incorrect skew, so use constant period.