From 858ef45f41aef7f94267d3a247d5d90b653f2b6e Mon Sep 17 00:00:00 2001 From: bubio Date: Sat, 14 Feb 2026 16:05:04 +0900 Subject: [PATCH 1/3] =?UTF-8?q?FDC:=208MHz=E5=B0=82=E7=94=A8=E3=81=AE?= =?UTF-8?q?=E7=92=B0=E5=A2=83=E5=A4=89=E6=95=B0=E3=82=AA=E3=83=BC=E3=83=90?= =?UTF-8?q?=E3=83=BC=E3=83=A9=E3=82=A4=E3=83=89=E7=B5=8C=E8=B7=AF=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 40 ++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 395df9a..3d33d4d 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -95,6 +95,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 +143,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 +162,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 +178,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'); } @@ -195,7 +218,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,7 +248,10 @@ 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", + fdc_trace("runtime_params: cpu_type=%d cpu_power=%d mode=%s seek_scale=%d disable_unstable=%d lost_usec=%d const_exec=%d", + config.cpu_type, + config.cpu_power, + fdc_is_8mhz_mode() ? "8mhz" : "4mhz", seek_scale, disable_unstable ? 1 : 0, lost_usec, From 1c850404819a6c6d6bc1deff1ea94188adf26df4 Mon Sep 17 00:00:00 2001 From: bubio Date: Sat, 14 Feb 2026 16:06:15 +0900 Subject: [PATCH 2/3] =?UTF-8?q?8MHz=E8=AA=BF=E6=95=B4:=20FDC=E3=83=91?= =?UTF-8?q?=E3=83=A9=E3=83=A1=E3=83=BC=E3=82=BF=E3=82=928MHz=E5=B0=82?= =?UTF-8?q?=E7=94=A8=E7=92=B0=E5=A2=83=E5=A4=89=E6=95=B0=E3=81=A7=E5=88=87?= =?UTF-8?q?=E6=9B=BF=E5=8F=AF=E8=83=BD=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index 0ff7549..674c0d0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -51,6 +51,24 @@ "XM8_DISABLE_UNSTABLE_MASK": "1", "XM8_FDC_TRACE_FILE": "xm8_fdc_trace_s1000_nounstable.log" } + }, + { + "name": "macOS: Wizardry 8MHz チューニング", + "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_8mhz_tuning.log", + "XM8_FDC_SEEK_SCALE_8MHZ": "1000", + "XM8_DISABLE_UNSTABLE_MASK_8MHZ": "1", + "XM8_FDC_LOST_USEC_8MHZ": "15000", + "XM8_FDC_CONST_EXEC_USEC_8MHZ": "1" + } } ] } From c96e1b5bd737450d1248f160a2f307b3138f14ae Mon Sep 17 00:00:00 2001 From: bubio Date: Sat, 14 Feb 2026 23:52:48 +0900 Subject: [PATCH 3/3] =?UTF-8?q?Wizardry=208MHz=E5=AE=89=E5=AE=9A=E5=8C=96:?= =?UTF-8?q?=20single=5Fexec=E6=97=A2=E5=AE=9A=E8=AA=BF=E6=95=B4=E3=81=A8FD?= =?UTF-8?q?C=208MHz=E3=83=91=E3=83=A9=E3=83=A1=E3=83=BC=E3=82=BF=E6=95=B4?= =?UTF-8?q?=E5=82=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 35 ++++++----------- Source/ePC-8801MA/vm/event.cpp | 65 ++++++++++++++++++++++++-------- Source/ePC-8801MA/vm/upd765a.cpp | 50 +++++++++++++++++++++--- 3 files changed, 107 insertions(+), 43 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 674c0d0..99f3ae3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -21,23 +21,7 @@ "MIMode": "gdb" }, { - "name": "macOS: Wizardry 安定化 (LOST=15000 + CONST_EXEC=1)", - "type": "lldb", - "request": "launch", - "program": "${workspaceFolder}/build/XM8.app/Contents/MacOS/xm8", - "args": [], - "cwd": "${workspaceFolder}", - "env": { - "XM8_FDC_TRACE_MAX_LINES": "400000", - "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" - } - }, - { - "name": "macOS: FDCトレース基準 (scale=1000, no-unstable)", + "name": "macOS: Wizardry 安定化 4MHz", "type": "lldb", "request": "launch", "program": "${workspaceFolder}/build/XM8.app/Contents/MacOS/xm8", @@ -47,13 +31,15 @@ "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_TRACE_FILE": "xm8_fdc_trace_s1000_nounstable.log" + "XM8_FDC_LOST_USEC": "15000", + "XM8_FDC_CONST_EXEC_USEC": "1" } }, { - "name": "macOS: Wizardry 8MHz チューニング", + "name": "macOS: Wizardry 安定化 8MHz", "type": "lldb", "request": "launch", "program": "${workspaceFolder}/build/XM8.app/Contents/MacOS/xm8", @@ -63,11 +49,14 @@ "XM8_FDC_TRACE": "1", "XM8_FDC_TRACE_IO": "1", "XM8_FDC_TRACE_MAX_LINES": "400000", - "XM8_FDC_TRACE_FILE": "xm8_fdc_trace_8mhz_tuning.log", - "XM8_FDC_SEEK_SCALE_8MHZ": "1000", + "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": "15000", - "XM8_FDC_CONST_EXEC_USEC_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 3d33d4d..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; @@ -191,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'); } @@ -206,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'); } @@ -248,14 +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: cpu_type=%d cpu_power=%d mode=%s 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, ...) @@ -465,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; @@ -2007,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.