From cf303a1fc84bf1ee783392ce85269deca4d70c9c Mon Sep 17 00:00:00 2001 From: bubio Date: Thu, 12 Feb 2026 23:20:05 +0900 Subject: [PATCH 01/34] =?UTF-8?q?=E3=82=B3=E3=82=A2=E7=A7=BB=E6=A4=8D?= =?UTF-8?q?=E3=81=AE=E4=B8=8B=E6=BA=96=E5=82=99:=20UI=E4=BA=92=E6=8F=9B?= =?UTF-8?q?=E3=83=98=E3=83=AB=E3=83=91=E3=83=BC=E8=BF=BD=E5=8A=A0=E3=81=A8?= =?UTF-8?q?i825x=E6=9C=80=E5=B0=8F=E4=BA=92=E6=8F=9B=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Source/UIを変更せずに使える互換メソッドをEMU/FIFOに追加 - i8251/i8253/i8255へcommon_source_project取り込み用の互換APIを追加 - i8255のハンドシェイク条件参照の不整合を修正 - 移植方針をDocuments/CORE_MIGRATION_SCOPE.mdに明文化 --- Documents/CORE_MIGRATION_SCOPE.md | 47 ++++++++++++++++++++ Source/ePC-8801MA/emu.h | 52 ++++++++++++++-------- Source/ePC-8801MA/fifo.cpp | 48 ++++++++++++++------ Source/ePC-8801MA/fifo.h | 40 +++++++++-------- Source/ePC-8801MA/vm/i8251.cpp | 39 +++++++++++------ Source/ePC-8801MA/vm/i8251.h | 71 ++++++++++++++++++------------ Source/ePC-8801MA/vm/i8253.cpp | 73 ++++++++++++++++++------------- Source/ePC-8801MA/vm/i8253.h | 60 ++++++++++++++----------- Source/ePC-8801MA/vm/i8255.cpp | 59 ++++++++++++++----------- Source/ePC-8801MA/vm/i8255.h | 9 ++-- 10 files changed, 320 insertions(+), 178 deletions(-) create mode 100644 Documents/CORE_MIGRATION_SCOPE.md diff --git a/Documents/CORE_MIGRATION_SCOPE.md b/Documents/CORE_MIGRATION_SCOPE.md new file mode 100644 index 0000000..25a71b0 --- /dev/null +++ b/Documents/CORE_MIGRATION_SCOPE.md @@ -0,0 +1,47 @@ +# XM8 Core Migration Scope (UI-Preserved) + +This document defines how to migrate from `common_source_project` into XM8 without changing files under `Source/UI`. + +## Rules + +1. Keep `Source/UI` unchanged. +2. Prefer same-path/same-name files from `common_source_project/src`. +3. Do not import features that are not used by current XM8 UX/settings unless needed for build or correctness. +4. Keep existing XM8 runtime behavior first, then add optional features deliberately. + +## Required Compatibility Surface + +The core must continue to provide the interfaces used by XM8 UI: + +- `VM::frame_rate()` +- `VM::open_disk()`, `VM::close_disk()` +- `VM::play_tape()`, `VM::rec_tape()`, `VM::close_tape()` +- `VM::save_state()`, `VM::load_state()` +- `VM::get_device(id)` with current ID assumptions used by UI +- `EMU::set_key_buffer()`, `EMU::set_joy_buffer()` +- `config` fields used by UI (`dipswitch`, `sound_device_type`, `scan_line`, `ignore_crc`, etc.) + +## Out of Scope by Default + +The following should not be migrated unless explicitly required: + +- Non-PC-8801 machine features +- Win32-only OSD/frontend pieces (`win32/osd.*`, `winmain.cpp`) +- UI feature sets not exposed in XM8 UI (extra media/device options) +- Optional peripherals not required by current XM8 workflow + +## Migration Order + +1. Compatibility helpers (no behavior change) +2. Small common components (`fifo`, selected device helpers) +3. Medium components (`event`, `disk`, `upd765a`, `z80`) +4. PC-8801 core (`pc88`, `pc8801`) with XM8 behavior preserved + +## Acceptance per Step + +- `cmake --build build -j8` succeeds +- XM8 launches +- Disk mount/eject works +- Tape play/rec works +- Save/load state works +- No UI source changes diff --git a/Source/ePC-8801MA/emu.h b/Source/ePC-8801MA/emu.h index e572ce8..69bbb9a 100644 --- a/Source/ePC-8801MA/emu.h +++ b/Source/ePC-8801MA/emu.h @@ -54,24 +54,40 @@ class EMU // ---------------------------------------- // input device - uint8* key_buffer() - { - return key_status; - } - uint32* joy_buffer() - { - return joy_status; - } - int* mouse_buffer() - { - return mouse_status; - } - - // screen - scrntype* screen_buffer(int y); -#ifdef USE_CRT_FILTER - bool screen_skip_line; -#endif + uint8* key_buffer() + { + return key_status; + } + uint8* get_key_buffer() + { + return key_buffer(); + } + uint32* joy_buffer() + { + return joy_status; + } + uint32* get_joy_buffer() + { + return joy_buffer(); + } + int* mouse_buffer() + { + return mouse_status; + } + int* get_mouse_buffer() + { + return mouse_buffer(); + } + + // screen + scrntype* screen_buffer(int y); + scrntype* get_screen_buffer(int y) + { + return screen_buffer(y); + } +#ifdef USE_CRT_FILTER + bool screen_skip_line; +#endif // timer void get_host_time(cur_time_t* time); diff --git a/Source/ePC-8801MA/fifo.cpp b/Source/ePC-8801MA/fifo.cpp index 688677a..7649cd2 100644 --- a/Source/ePC-8801MA/fifo.cpp +++ b/Source/ePC-8801MA/fifo.cpp @@ -50,17 +50,28 @@ int FIFO::read() } return val; } -int FIFO::read_not_remove(int pt) -{ - if(pt >= 0 && pt < cnt) { - pt += rpt; +int FIFO::read_not_remove(int pt) +{ + if(pt >= 0 && pt < cnt) { + pt += rpt; if(pt >= size) { pt -= size; } return buf[pt]; - } - return 0; -} + } + return 0; +} + +void FIFO::write_not_push(int pt, int d) +{ + if(pt >= 0 && pt < cnt) { + pt += wpt; + if(pt >= size) { + pt -= size; + } + buf[pt] = d; + } +} int FIFO::count() { return cnt; @@ -89,9 +100,9 @@ void FIFO::save_state(void *f) state_fio->FputInt32(wpt); } -bool FIFO::load_state(void *f) -{ - FILEIO *state_fio = (FILEIO *)f; +bool FIFO::load_state(void *f) +{ + FILEIO *state_fio = (FILEIO *)f; if(state_fio->FgetUint32() != STATE_VERSION) { return false; @@ -101,8 +112,17 @@ bool FIFO::load_state(void *f) } state_fio->Fread(buf, size * sizeof(int), 1); cnt = state_fio->FgetInt32(); - rpt = state_fio->FgetInt32(); - wpt = state_fio->FgetInt32(); - return true; -} + rpt = state_fio->FgetInt32(); + wpt = state_fio->FgetInt32(); + return true; +} + +bool FIFO::process_state(void *f, bool loading) +{ + if(loading) { + return load_state(f); + } + save_state(f); + return true; +} diff --git a/Source/ePC-8801MA/fifo.h b/Source/ePC-8801MA/fifo.h index 9983b1b..e3066ba 100644 --- a/Source/ePC-8801MA/fifo.h +++ b/Source/ePC-8801MA/fifo.h @@ -12,25 +12,27 @@ #include "common.h" -class FIFO -{ -private: - int size; - int* buf; - int cnt, rpt, wpt; -public: - FIFO(int s); - void release(); - void clear(); - void write(int val); - int read(); - int read_not_remove(int pt); - int count(); - bool full(); - bool empty(); - void save_state(void *f); - bool load_state(void *f); -}; +class FIFO +{ +private: + int size; + int* buf; + int cnt, rpt, wpt; +public: + FIFO(int s); + void release(); + void clear(); + void write(int val); + int read(); + int read_not_remove(int pt); + void write_not_push(int pt, int d); + int count(); + bool full(); + bool empty(); + void save_state(void *f); + bool load_state(void *f); + bool process_state(void *f, bool loading); +}; #endif diff --git a/Source/ePC-8801MA/vm/i8251.cpp b/Source/ePC-8801MA/vm/i8251.cpp index aa9008a..fb6eb7f 100644 --- a/Source/ePC-8801MA/vm/i8251.cpp +++ b/Source/ePC-8801MA/vm/i8251.cpp @@ -98,14 +98,16 @@ void I8251::write_io8(uint32 addr, uint32 data) if(data & 0x10) { status &= ~(PE | OE | FE); } - // dtr - write_signals(&outputs_dtr, (data & 2) ? 0xffffffff : 0); - // rst/sbrk - write_signals(&outputs_rst, (data & 8) ? 0xffffffff : 0); - // rxen - rxen = ((data & 4) != 0); - if(rxen && !recv_buffer->empty() && recv_id == -1) { - register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id); + // dtr + write_signals(&outputs_dtr, (data & 2) ? 0xffffffff : 0); + // rst/sbrk + write_signals(&outputs_rst, (data & 8) ? 0xffffffff : 0); + // rts + write_signals(&outputs_rts, (data & 0x20) ? 0xffffffff : 0); + // rxen + rxen = ((data & 4) != 0); + if(rxen && !recv_buffer->empty() && recv_id == -1) { + register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id); } // txen txen = ((data & 1) != 0); @@ -252,8 +254,8 @@ void I8251::save_state(FILEIO* state_fio) state_fio->FputInt32(send_id); } -bool I8251::load_state(FILEIO* state_fio) -{ +bool I8251::load_state(FILEIO* state_fio) +{ if(state_fio->FgetUint32() != STATE_VERSION) { return false; } @@ -272,8 +274,17 @@ bool I8251::load_state(FILEIO* state_fio) if(!send_buffer->load_state((void *)state_fio)) { return false; } - recv_id = state_fio->FgetInt32(); - send_id = state_fio->FgetInt32(); - return true; -} + recv_id = state_fio->FgetInt32(); + send_id = state_fio->FgetInt32(); + return true; +} + +bool I8251::process_state(FILEIO* state_fio, bool loading) +{ + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; +} diff --git a/Source/ePC-8801MA/vm/i8251.h b/Source/ePC-8801MA/vm/i8251.h index f0f50ca..81e48fa 100644 --- a/Source/ePC-8801MA/vm/i8251.h +++ b/Source/ePC-8801MA/vm/i8251.h @@ -32,11 +32,12 @@ class I8251 : public DEVICE // output signals outputs_t outputs_out; outputs_t outputs_rxrdy; - outputs_t outputs_syndet; - outputs_t outputs_txrdy; - outputs_t outputs_txe; - outputs_t outputs_dtr; - outputs_t outputs_rst; + outputs_t outputs_syndet; + outputs_t outputs_txrdy; + outputs_t outputs_txe; + outputs_t outputs_dtr; + outputs_t outputs_rst; + outputs_t outputs_rts; // buffer FIFO *recv_buffer; @@ -49,12 +50,13 @@ class I8251 : public DEVICE init_output_signals(&outputs_out); init_output_signals(&outputs_rxrdy); init_output_signals(&outputs_syndet); - init_output_signals(&outputs_txrdy); - init_output_signals(&outputs_txe); - init_output_signals(&outputs_dtr); - init_output_signals(&outputs_rst); - } - ~I8251() {} + init_output_signals(&outputs_txrdy); + init_output_signals(&outputs_txe); + init_output_signals(&outputs_dtr); + init_output_signals(&outputs_rst); + init_output_signals(&outputs_rts); + } + ~I8251() {} // common functions void initialize(); @@ -62,10 +64,11 @@ class I8251 : public DEVICE void reset(); void write_io8(uint32 addr, uint32 data); uint32 read_io8(uint32 addr); - void write_signal(int id, uint32 data, uint32 mask); - void event_callback(int event_id, int err); - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); + void write_signal(int id, uint32 data, uint32 mask); + void event_callback(int event_id, int err); + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading); // unique functions void set_context_out(DEVICE* device, int id) @@ -84,19 +87,31 @@ class I8251 : public DEVICE { register_output_signal(&outputs_txrdy, device, id, mask); } - void set_context_txe(DEVICE* device, int id, uint32 mask) - { - register_output_signal(&outputs_txe, device, id, mask); - } - void set_context_dtr(DEVICE* device, int id, uint32 mask) - { - register_output_signal(&outputs_dtr, device, id, mask); - } - void set_context_rst(DEVICE* device, int id, uint32 mask) - { - register_output_signal(&outputs_rst, device, id, mask); - } -}; + void set_context_txe(DEVICE* device, int id, uint32 mask) + { + register_output_signal(&outputs_txe, device, id, mask); + } + void set_context_txempty(DEVICE* device, int id, uint32 mask) + { + set_context_txe(device, id, mask); + } + void set_context_dtr(DEVICE* device, int id, uint32 mask) + { + register_output_signal(&outputs_dtr, device, id, mask); + } + void set_context_rst(DEVICE* device, int id, uint32 mask) + { + register_output_signal(&outputs_rst, device, id, mask); + } + void set_context_brk(DEVICE* device, int id, uint32 mask) + { + set_context_rst(device, id, mask); + } + void set_context_rts(DEVICE* device, int id, uint32 mask) + { + register_output_signal(&outputs_rts, device, id, mask); + } +}; #endif diff --git a/Source/ePC-8801MA/vm/i8253.cpp b/Source/ePC-8801MA/vm/i8253.cpp index eaf4a5a..2bb943c 100644 --- a/Source/ePC-8801MA/vm/i8253.cpp +++ b/Source/ePC-8801MA/vm/i8253.cpp @@ -95,25 +95,27 @@ void I8253::write_io8(uint32 addr, uint32 data) case 3: // ctrl reg if((data & 0xc0) == 0xc0) { -#ifdef HAS_I8254 - // i8254 read-back command - for(ch = 0; ch < 3; ch++) { - uint8 bit = 2 << ch; - if(!(data & 0x10) && !counter[ch].status_latched) { - counter[ch].status = counter[ch].ctrl_reg & 0x3f; - if(counter[ch].prev_out) { - counter[ch].status |= 0x80; - } - if(counter[ch].null_count) { - counter[ch].status |= 0x40; - } - counter[ch].status_latched = true; - } - if(!(data & 0x20) && !counter[ch].count_latched) { - latch_count(ch); - } - } -#endif +#ifdef HAS_I8254 + // i8254 read-back command + if(device_model == INTEL_8254) { + for(ch = 0; ch < 3; ch++) { + uint8 bit = 2 << ch; + if(!(data & 0x10) && !counter[ch].status_latched) { + counter[ch].status = counter[ch].ctrl_reg & 0x3f; + if(counter[ch].prev_out) { + counter[ch].status |= 0x80; + } + if(counter[ch].null_count) { + counter[ch].status |= 0x40; + } + counter[ch].status_latched = true; + } + if(!(data & 0x20) && !counter[ch].count_latched) { + latch_count(ch); + } + } + } +#endif break; } ch = (data >> 6) & 3; @@ -155,12 +157,14 @@ uint32 I8253::read_io8(uint32 addr) case 0: case 1: case 2: -#ifdef HAS_I8254 - if(counter[ch].status_latched) { - counter[ch].status_latched = false; - return counter[ch].status; - } -#endif +#ifdef HAS_I8254 + if(device_model == INTEL_8254) { + if(counter[ch].status_latched) { + counter[ch].status_latched = false; + return counter[ch].status; + } + } +#endif // if not latched, through current count if(!counter[ch].count_latched) { if(!counter[ch].low_read && !counter[ch].high_read) { @@ -443,8 +447,8 @@ void I8253::save_state(FILEIO* state_fio) state_fio->FputUint64(cpu_clocks); } -bool I8253::load_state(FILEIO* state_fio) -{ +bool I8253::load_state(FILEIO* state_fio) +{ if(state_fio->FgetUint32() != STATE_VERSION) { return false; } @@ -478,6 +482,15 @@ bool I8253::load_state(FILEIO* state_fio) counter[i].period = state_fio->FgetInt32(); counter[i].prev_clk = state_fio->FgetUint32(); } - cpu_clocks = state_fio->FgetUint64(); - return true; -} + cpu_clocks = state_fio->FgetUint64(); + return true; +} + +bool I8253::process_state(FILEIO* state_fio, bool loading) +{ + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; +} diff --git a/Source/ePC-8801MA/vm/i8253.h b/Source/ePC-8801MA/vm/i8253.h index add42d9..cebf57b 100644 --- a/Source/ePC-8801MA/vm/i8253.h +++ b/Source/ePC-8801MA/vm/i8253.h @@ -17,12 +17,17 @@ #define SIG_I8253_CLOCK_0 0 #define SIG_I8253_CLOCK_1 1 #define SIG_I8253_CLOCK_2 2 -#define SIG_I8253_GATE_0 3 -#define SIG_I8253_GATE_1 4 -#define SIG_I8253_GATE_2 5 - -class I8253 : public DEVICE -{ +#define SIG_I8253_GATE_0 3 +#define SIG_I8253_GATE_1 4 +#define SIG_I8253_GATE_2 5 + +enum { + INTEL_8253 = 0, + INTEL_8254, +}; + +class I8253 : public DEVICE +{ private: struct { bool prev_out; @@ -63,13 +68,14 @@ class I8253 : public DEVICE int get_next_count(int ch); public: - I8253(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) - { - for(int i = 0; i < 3; i++) { - init_output_signals(&counter[i].outputs); - counter[i].freq = 0; - } - } + I8253(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) + { + for(int i = 0; i < 3; i++) { + init_output_signals(&counter[i].outputs); + counter[i].freq = 0; + } + device_model = INTEL_8253; + } ~I8253() {} // common functions @@ -79,12 +85,13 @@ class I8253 : public DEVICE uint32 read_io8(uint32 addr); void event_callback(int event_id, int err); void write_signal(int id, uint32 data, uint32 mask); - void update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame) - { - cpu_clocks = new_clocks; - } - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); + void update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame) + { + cpu_clocks = new_clocks; + } + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading); // unique functions void set_context_ch0(DEVICE* device, int id, uint32 mask) @@ -99,11 +106,12 @@ class I8253 : public DEVICE { register_output_signal(&counter[2].outputs, device, id, mask); } - void set_constant_clock(int ch, uint32 hz) - { - counter[ch].freq = hz; - } -}; - -#endif + void set_constant_clock(int ch, uint32 hz) + { + counter[ch].freq = hz; + } + int device_model; +}; + +#endif diff --git a/Source/ePC-8801MA/vm/i8255.cpp b/Source/ePC-8801MA/vm/i8255.cpp index e78f3cf..21833b6 100644 --- a/Source/ePC-8801MA/vm/i8255.cpp +++ b/Source/ePC-8801MA/vm/i8255.cpp @@ -80,18 +80,18 @@ void I8255::write_io8(uint32 addr, uint32 data) // setup control signals if(port[0].mode != 0 || port[1].mode != 0) { uint32 val = port[2].wreg; - if(port[0].mode == 1 || port[0].mode == 2) { - val &= ~BIT_IBF_A; - val |= BIT_OBF_A; - val &= ~BIT_INTR_A; - } - if(port[1].mode == 1) { - if(port[1].mode == 0xff) { - val &= ~BIT_IBF_B; - } else { - val |= BIT_OBF_B; - } - val &= ~BIT_INTR_B; + if(port[0].mode == 1 || port[0].mode == 2) { + val &= ~BIT_IBF_A; + val |= BIT_OBF_A; + val &= ~BIT_INTR_A; + } + if(port[1].mode == 1) { + if(port[1].rmask == 0xff) { + val &= ~BIT_IBF_B; + } else { + val |= BIT_OBF_B; + } + val &= ~BIT_INTR_B; } write_io8(2, val); } @@ -187,14 +187,14 @@ void I8255::write_signal(int id, uint32 data, uint32 mask) } } } - } - if(port[1].mode == 1) { - if(port[0].rmask == 0xff) { - if(mask & BIT_STB_B) { - if((port[2].rreg & BIT_STB_B) && !(data & BIT_STB_B)) { - write_io8(2, port[2].wreg | BIT_IBF_B); - } else if(!(port[2].rreg & BIT_STB_B) && (data & BIT_STB_B)) { - if(port[2].wreg & BIT_STB_B) { + } + if(port[1].mode == 1) { + if(port[1].rmask == 0xff) { + if(mask & BIT_STB_B) { + if((port[2].rreg & BIT_STB_B) && !(data & BIT_STB_B)) { + write_io8(2, port[2].wreg | BIT_IBF_B); + } else if(!(port[2].rreg & BIT_STB_B) && (data & BIT_STB_B)) { + if(port[2].wreg & BIT_STB_B) { write_io8(2, port[2].wreg | BIT_INTR_B); } } @@ -246,8 +246,8 @@ void I8255::save_state(FILEIO* state_fio) } } -bool I8255::load_state(FILEIO* state_fio) -{ +bool I8255::load_state(FILEIO* state_fio) +{ if(state_fio->FgetUint32() != STATE_VERSION) { return false; } @@ -260,7 +260,16 @@ bool I8255::load_state(FILEIO* state_fio) port[i].rmask = state_fio->FgetUint8(); port[i].mode = state_fio->FgetUint8(); port[i].first = state_fio->FgetBool(); - } - return true; -} + } + return true; +} + +bool I8255::process_state(FILEIO* state_fio, bool loading) +{ + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; +} diff --git a/Source/ePC-8801MA/vm/i8255.h b/Source/ePC-8801MA/vm/i8255.h index 6f2c23a..c5e4630 100644 --- a/Source/ePC-8801MA/vm/i8255.h +++ b/Source/ePC-8801MA/vm/i8255.h @@ -46,10 +46,11 @@ class I8255 : public DEVICE void reset(); void write_io8(uint32 addr, uint32 data); uint32 read_io8(uint32 addr); - void write_signal(int id, uint32 data, uint32 mask); - uint32 read_signal(int id); - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); + void write_signal(int id, uint32 data, uint32 mask); + uint32 read_signal(int id); + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading); // unique functions void set_context_port_a(DEVICE* device, int id, uint32 mask, int shift) From a008114dc36c2deb6d8968668c4d8a6eb232807b Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 09:09:13 +0900 Subject: [PATCH 02/34] =?UTF-8?q?=E3=82=B3=E3=82=A2=E7=A7=BB=E6=A4=8D?= =?UTF-8?q?=E3=81=AE=E4=BA=92=E6=8F=9B=E5=B1=A4=E3=82=92=E6=8B=A1=E5=BC=B5?= =?UTF-8?q?:=20device/disk/upd765a=E3=81=AE=E5=8F=97=E3=81=91=E5=8F=A3?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Documents/CORE_MIGRATION_SCOPE.md | 15 +++ Source/ePC-8801MA/vm/device.h | 177 +++++++++++++++++++++--------- Source/ePC-8801MA/vm/disk.cpp | 59 +++++++--- Source/ePC-8801MA/vm/disk.h | 41 ++++--- Source/ePC-8801MA/vm/upd765a.cpp | 75 +++++++++---- Source/ePC-8801MA/vm/upd765a.h | 47 +++++--- 6 files changed, 292 insertions(+), 122 deletions(-) diff --git a/Documents/CORE_MIGRATION_SCOPE.md b/Documents/CORE_MIGRATION_SCOPE.md index 25a71b0..2043b9a 100644 --- a/Documents/CORE_MIGRATION_SCOPE.md +++ b/Documents/CORE_MIGRATION_SCOPE.md @@ -45,3 +45,18 @@ The following should not be migrated unless explicitly required: - Tape play/rec works - Save/load state works - No UI source changes + +## Progress Notes + +- 2026-02-12: + - Added `DEVICE` compatibility aliases used by common-source style code: + `process_state()`, `initialize_output_signals()`, event/clock alias methods, + interrupt alias methods, and `set_device_name()/get_device_name()`. + - Added `DISK` compatibility wrappers: + `open(const _TCHAR*)`, `process_state()`, and utility aliases + (`set_data_crc_error()`, `get_usec_per_track()`, `get_bytes_per_usec()`). + - Added `UPD765A` compatibility wrappers: + `open_disk(const _TCHAR*)`, `process_state()`, + `is_disk_inserted()`, `is_disk_protected()`, `get_media_type()`, + and safer `get_disk_handler()` bounds check. + - Verified with `cmake --build build -j8` (success, warnings only). diff --git a/Source/ePC-8801MA/vm/device.h b/Source/ePC-8801MA/vm/device.h index 03550a1..98faee9 100644 --- a/Source/ePC-8801MA/vm/device.h +++ b/Source/ePC-8801MA/vm/device.h @@ -29,10 +29,11 @@ class DEVICE VM* vm; EMU* emu; public: - DEVICE(VM* parent_vm, EMU* parent_emu) : vm(parent_vm), emu(parent_emu) - { - prev_device = vm->last_device; - next_device = NULL; + DEVICE(VM* parent_vm, EMU* parent_emu) : vm(parent_vm), emu(parent_emu) + { + _tcscpy_s(this_device_name, array_length(this_device_name), _T("Base Device")); + prev_device = vm->last_device; + next_device = NULL; if(vm->first_device == NULL) { // this is the first device vm->first_device = this; @@ -54,10 +55,18 @@ class DEVICE virtual void update_config() {} virtual void save_state(FILEIO* state_fio) {} - virtual bool load_state(FILEIO* state_fio) - { - return true; - } + virtual bool load_state(FILEIO* state_fio) + { + return true; + } + virtual bool process_state(FILEIO* state_fio, bool loading) + { + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; + } // control virtual void reset() {} @@ -396,10 +405,14 @@ class DEVICE output_t item[MAX_OUTPUT]; } outputs_t; - virtual void init_output_signals(outputs_t *items) - { - items->count = 0; - } + virtual void init_output_signals(outputs_t *items) + { + items->count = 0; + } + virtual void initialize_output_signals(outputs_t *items) + { + init_output_signals(items); + } virtual void register_output_signal(outputs_t *items, DEVICE *device, int id, uint32 mask, int shift) { int c = items->count++; @@ -443,12 +456,25 @@ class DEVICE virtual void set_intr_line(bool line, bool pending, uint32 bit) {} // interrupt cpu to device - virtual uint32 intr_ack() - { - return 0xff; - } - virtual void intr_reti() {} - virtual void intr_ei() {} + virtual uint32 intr_ack() + { + return 0xff; + } + virtual void intr_reti() {} + virtual void intr_ei() {} + virtual uint32 get_intr_ack() + { + return intr_ack(); + } + virtual void update_intr() {} + virtual void notify_intr_reti() + { + intr_reti(); + } + virtual void notify_intr_ei() + { + intr_ei(); + } // dma virtual void do_dma() {} @@ -494,13 +520,17 @@ class DEVICE { event_manager = device; } - virtual int event_manager_id() - { - if(event_manager == NULL) { - event_manager = vm->first_device->next_device; - } - return event_manager->this_device_id; - } + virtual int event_manager_id() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->this_device_id; + } + virtual int get_event_manager_id() + { + return event_manager_id(); + } virtual void register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id) { if(event_manager == NULL) { @@ -540,27 +570,39 @@ class DEVICE } event_manager->register_vline_event(device); } - virtual uint32 current_clock() - { - if(event_manager == NULL) { - event_manager = vm->first_device->next_device; - } - return event_manager->current_clock(); - } - virtual uint32 passed_clock(uint32 prev) - { - if(event_manager == NULL) { - event_manager = vm->first_device->next_device; - } - return event_manager->passed_clock(prev); - } - virtual double passed_usec(uint32 prev) - { - if(event_manager == NULL) { - event_manager = vm->first_device->next_device; - } - return event_manager->passed_usec(prev); - } + virtual uint32 current_clock() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->current_clock(); + } + virtual uint32 get_current_clock() + { + return current_clock(); + } + virtual uint32 passed_clock(uint32 prev) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->passed_clock(prev); + } + virtual uint32 get_passed_clock(uint32 prev) + { + return passed_clock(prev); + } + virtual double passed_usec(uint32 prev) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->passed_usec(prev); + } + virtual double get_passed_usec(uint32 prev) + { + return passed_usec(prev); + } virtual uint32 get_cpu_pc(int index) { if(event_manager == NULL) { @@ -735,11 +777,42 @@ class DEVICE { return 0; } -#endif - - DEVICE* prev_device; - DEVICE* next_device; - int this_device_id; -}; +#endif + + // misc + virtual void out_debug_log(const _TCHAR* format, ...) + { + va_list ap; + _TCHAR buffer[1024]; + + va_start(ap, format); + _vstprintf_s(buffer, 1024, format, ap); + va_end(ap); + + emu->out_debug_log(_T("%s"), buffer); + } + void set_device_name(const _TCHAR* format, ...) + { + if(format != NULL) { + va_list ap; + _TCHAR buffer[1024]; + + va_start(ap, format); + _vstprintf_s(buffer, 1024, format, ap); + va_end(ap); + + _tcscpy_s(this_device_name, array_length(this_device_name), buffer); + } + } + const _TCHAR *get_device_name() + { + return (const _TCHAR *)this_device_name; + } + + DEVICE* prev_device; + DEVICE* next_device; + int this_device_id; + _TCHAR this_device_name[128]; +}; #endif diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index 658c36f..a0b8ae8 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -102,11 +102,16 @@ static const fd_format_t fd_formats[] = { { -1, 0, 0, 0, 0 }, }; -#define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer)) - -void DISK::open(_TCHAR path[], int bank) -{ - // check current disk image +#define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer)) + +void DISK::open(const _TCHAR* path, int bank) +{ + open(const_cast<_TCHAR*>(path), bank); +} + +void DISK::open(_TCHAR path[], int bank) +{ + // check current disk image if(inserted) { if(_tcsicmp(orig_path, path) == 0 && file_bank == bank) { return; @@ -836,14 +841,23 @@ int DISK::get_track_size() } } -double DISK::get_usec_per_bytes(int bytes) -{ - return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes; -} - -bool DISK::check_media_type() -{ - switch(drive_type) { +double DISK::get_usec_per_bytes(int bytes) +{ + return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes; +} + +int DISK::get_bytes_per_usec(double usec) +{ + double usec_per_byte = get_usec_per_bytes(1); + if(usec_per_byte <= 0.0) { + return 0; + } + return (int)(usec / usec_per_byte + 0.5); +} + +bool DISK::check_media_type() +{ + switch(drive_type) { case DRIVE_TYPE_2D: return (media_type == MEDIA_TYPE_2D); case DRIVE_TYPE_2DD: @@ -1531,8 +1545,8 @@ void DISK::save_state(FILEIO* state_fio) state_fio->FputBool(drive_mfm); } -bool DISK::load_state(FILEIO* state_fio) -{ +bool DISK::load_state(FILEIO* state_fio) +{ if(state_fio->FgetUint32() != STATE_VERSION) { return false; } @@ -1567,7 +1581,16 @@ bool DISK::load_state(FILEIO* state_fio) crc_error = state_fio->FgetBool(); drive_type = state_fio->FgetUint8(); drive_rpm = state_fio->FgetInt32(); - drive_mfm = state_fio->FgetBool(); - return true; -} + drive_mfm = state_fio->FgetBool(); + return true; +} + +bool DISK::process_state(FILEIO* state_fio, bool loading) +{ + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; +} diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index 736cec1..3a82815 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -164,22 +164,32 @@ class DISK } } - void open(_TCHAR path[], int bank); - void close(); - bool get_track(int trk, int side); - bool make_track(int trk, int side); - bool get_sector(int trk, int side, int index); - void set_deleted(bool value); - void set_crc_error(bool value); + void open(const _TCHAR* path, int bank); + void open(_TCHAR path[], int bank); + void close(); + bool get_track(int trk, int side); + bool make_track(int trk, int side); + bool get_sector(int trk, int side, int index); + void set_deleted(bool value); + void set_crc_error(bool value); + void set_data_crc_error(bool value) + { + set_crc_error(value); + } bool format_track(int trk, int side); void insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool crc_error, uint8 fill_data, int length); void sync_buffer(); - int get_rpm(); - int get_track_size(); - double get_usec_per_bytes(int bytes); - bool check_media_type(); + int get_rpm(); + int get_track_size(); + double get_usec_per_track() + { + return get_usec_per_bytes(get_track_size()); + } + double get_usec_per_bytes(int bytes); + int get_bytes_per_usec(double usec); + bool check_media_type(); bool inserted; bool ejected; @@ -215,10 +225,11 @@ class DISK bool drive_mfm; int drive_num; - // state - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); -}; + // state + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading); +}; #endif diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 8811cf0..6763b6b 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1513,11 +1513,11 @@ double UPD765A::get_usec_to_exec_phase() // user interface // ---------------------------------------------------------------------------- -void UPD765A::open_disk(int drv, _TCHAR path[], int bank) -{ - if(drv < MAX_DRIVE) { - disk[drv]->open(path, bank); - if(disk[drv]->changed) { +void UPD765A::open_disk(int drv, const _TCHAR* path, int bank) +{ + if(drv < MAX_DRIVE) { + disk[drv]->open(path, bank); + if(disk[drv]->changed) { #ifdef _FDC_DEBUG_LOG emu->out_debug_log("FDC: Disk Changed (Drive=%d)\n", drv); #endif @@ -1526,11 +1526,16 @@ void UPD765A::open_disk(int drv, _TCHAR path[], int bank) set_irq(true); } } - } -} - -void UPD765A::close_disk(int drv) -{ + } +} + +void UPD765A::open_disk(int drv, _TCHAR path[], int bank) +{ + open_disk(drv, (const _TCHAR*)path, bank); +} + +void UPD765A::close_disk(int drv) +{ if(drv < MAX_DRIVE && disk[drv]->inserted) { disk[drv]->close(); #ifdef _FDC_DEBUG_LOG @@ -1565,14 +1570,29 @@ bool UPD765A::disk_ejected(int drv) return false; } -bool UPD765A::disk_ejected() -{ - int drv = hdu & DRIVE_MASK; - return disk_ejected(drv); -} - -uint8 UPD765A::media_type(int drv) -{ +bool UPD765A::disk_ejected() +{ + int drv = hdu & DRIVE_MASK; + return disk_ejected(drv); +} + +void UPD765A::is_disk_protected(int drv, bool value) +{ + if(drv < MAX_DRIVE) { + disk[drv]->write_protected = value; + } +} + +bool UPD765A::is_disk_protected(int drv) +{ + if(drv < MAX_DRIVE) { + return disk[drv]->write_protected; + } + return false; +} + +uint8 UPD765A::media_type(int drv) +{ if(drv < MAX_DRIVE && disk[drv]->inserted) { return disk[drv]->media_type; } @@ -1658,8 +1678,8 @@ void UPD765A::save_state(FILEIO* state_fio) state_fio->FputUint32(prev_drq_clock); } -bool UPD765A::load_state(FILEIO* state_fio) -{ +bool UPD765A::load_state(FILEIO* state_fio) +{ if(state_fio->FgetUint32() != STATE_VERSION) { return false; } @@ -1708,7 +1728,16 @@ bool UPD765A::load_state(FILEIO* state_fio) force_ready = state_fio->FgetBool(); reset_signal = state_fio->FgetBool(); prev_index = state_fio->FgetBool(); - prev_drq_clock = state_fio->FgetUint32(); - return true; -} + prev_drq_clock = state_fio->FgetUint32(); + return true; +} + +bool UPD765A::process_state(FILEIO* state_fio, bool loading) +{ + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; +} diff --git a/Source/ePC-8801MA/vm/upd765a.h b/Source/ePC-8801MA/vm/upd765a.h index 616c713..265794d 100644 --- a/Source/ePC-8801MA/vm/upd765a.h +++ b/Source/ePC-8801MA/vm/upd765a.h @@ -140,9 +140,10 @@ class UPD765A : public DEVICE uint32 read_dma_io8(uint32 addr); void write_signal(int id, uint32 data, uint32 mask); uint32 read_signal(int ch); - void event_callback(int event_id, int err); - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); + void event_callback(int event_id, int err); + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading); // unique function void set_context_irq(DEVICE* device, int id, uint32 mask) @@ -161,17 +162,35 @@ class UPD765A : public DEVICE { register_output_signal(&outputs_index, device, id, mask); } - DISK* get_disk_handler(int drv) - { - return disk[drv]; - } - void open_disk(int drv, _TCHAR path[], int bank); - void close_disk(int drv); - bool disk_inserted(int drv); - bool disk_inserted(); // current hdu - bool disk_ejected(int drv); - bool disk_ejected(); // current hdu - uint8 media_type(int drv); + DISK* get_disk_handler(int drv) + { + if(drv < 4) { + return disk[drv]; + } + return NULL; + } + void open_disk(int drv, const _TCHAR* path, int bank); + void open_disk(int drv, _TCHAR path[], int bank); + void close_disk(int drv); + bool disk_inserted(int drv); + bool disk_inserted(); // current hdu + bool is_disk_inserted(int drv) + { + return disk_inserted(drv); + } + bool is_disk_inserted() // current hdu + { + return disk_inserted(); + } + bool disk_ejected(int drv); + bool disk_ejected(); // current hdu + void is_disk_protected(int drv, bool value); + bool is_disk_protected(int drv); + uint8 media_type(int drv); + uint8 get_media_type(int drv) + { + return media_type(drv); + } void set_drive_type(int drv, uint8 type); uint8 get_drive_type(int drv); void set_drive_rpm(int drv, int rpm); From 870de983ee4e297acfbba25b94bccc2550b14cf6 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 10:18:43 +0900 Subject: [PATCH 03/34] =?UTF-8?q?FDC/DISK=E4=BA=92=E6=8F=9BAPI=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=81=97=E6=AC=A1=E6=AE=B5=E7=A7=BB=E6=A4=8D?= =?UTF-8?q?=E3=81=AE=E5=8F=97=E3=81=91=E5=8F=A3=E3=82=92=E6=95=B4=E5=82=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/disk.cpp | 83 +++++++++++++++++++++++++------- Source/ePC-8801MA/vm/disk.h | 21 ++++++-- Source/ePC-8801MA/vm/upd765a.cpp | 19 +++++--- Source/ePC-8801MA/vm/upd765a.h | 73 ++++++++++++++++++++-------- 4 files changed, 147 insertions(+), 49 deletions(-) diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index a0b8ae8..cee1ba6 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -600,8 +600,8 @@ bool DISK::make_track(int trk, int side) return true; } -bool DISK::get_sector(int trk, int side, int index) -{ +bool DISK::get_sector(int trk, int side, int index) +{ sector_size.sd = sector_num.sd = 0; sector = NULL; @@ -640,12 +640,38 @@ bool DISK::get_sector(int trk, int side, int index) data_size.read_2bytes_le_from(t + 14); t += data_size.sd + 0x10; } - set_sector_info(t); - return true; -} - -void DISK::set_sector_info(uint8 *t) -{ + set_sector_info(t); + return true; +} + +bool DISK::get_sector_info(int trk, int side, int index, uint8* c, uint8* h, uint8* r, uint8* n, bool* mfm, int* length) +{ + if(!get_sector(trk, side, index)) { + return false; + } + if(c != NULL) { + *c = id[0]; + } + if(h != NULL) { + *h = id[1]; + } + if(r != NULL) { + *r = id[2]; + } + if(n != NULL) { + *n = id[3]; + } + if(mfm != NULL) { + *mfm = (density == 0x00); + } + if(length != NULL) { + *length = sector_size.sd; + } + return true; +} + +void DISK::set_sector_info(uint8 *t) +{ // header info id[0] = t[0]; id[1] = t[1]; @@ -685,14 +711,24 @@ void DISK::set_deleted(bool value) deleted = value; } -void DISK::set_crc_error(bool value) -{ +void DISK::set_crc_error(bool value) +{ if(sector != NULL) { uint8 *t = sector - 0x10; t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]); // FIXME: always data crc error ? } - crc_error = value; -} + crc_error = value; +} + +void DISK::set_data_mark_missing() +{ + if(sector != NULL) { + uint8 *t = sector - 0x10; + t[8] = (t[8] & 0x0f) | 0xf0; + t[14] = t[15] = 0; + } + crc_error = false; +} bool DISK::format_track(int trk, int side) { @@ -821,8 +857,8 @@ void DISK::trim_buffer() memcpy(buffer, tmp_buffer, file_size.d); } -int DISK::get_rpm() -{ +int DISK::get_rpm() +{ if(drive_rpm != 0) { return drive_rpm; } else if(inserted) { @@ -830,10 +866,21 @@ int DISK::get_rpm() } else { return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300; } -} - -int DISK::get_track_size() -{ +} + +int DISK::get_max_tracks() +{ + if(drive_type != DRIVE_TYPE_UNK) { + return (drive_type != DRIVE_TYPE_2D) ? 84 : 42; + } else if(inserted) { + return (media_type != MEDIA_TYPE_2D) ? 84 : 42; + } else { + return 84; + } +} + +int DISK::get_track_size() +{ if(inserted) { return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100; } else { diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index 3a82815..4196513 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -170,17 +170,20 @@ class DISK bool get_track(int trk, int side); bool make_track(int trk, int side); bool get_sector(int trk, int side, int index); + bool get_sector_info(int trk, int side, int index, uint8* c, uint8* h, uint8* r, uint8* n, bool* mfm, int* length); void set_deleted(bool value); void set_crc_error(bool value); void set_data_crc_error(bool value) { set_crc_error(value); } - - bool format_track(int trk, int side); - void insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool crc_error, uint8 fill_data, int length); - void sync_buffer(); - + void set_data_mark_missing(); + + bool format_track(int trk, int side); + void insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool crc_error, uint8 fill_data, int length); + void sync_buffer(); + + int get_max_tracks(); int get_rpm(); int get_track_size(); double get_usec_per_track() @@ -190,6 +193,14 @@ class DISK double get_usec_per_bytes(int bytes); int get_bytes_per_usec(double usec); bool check_media_type(); + bool correct_timing() + { + return false; + } + bool ignore_crc() + { + return config.ignore_crc; + } bool inserted; bool ejected; diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 6763b6b..ca6dd71 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -446,8 +446,8 @@ uint32 UPD765A::read_signal(int ch) return stat; } -void UPD765A::event_callback(int event_id, int err) -{ +void UPD765A::event_callback(int event_id, int err) +{ #ifdef SDL request_single_exec(); #endif // SDL @@ -485,11 +485,16 @@ void UPD765A::event_callback(int event_id, int err) int drv = event_id - EVENT_SEEK; seek_id[drv] = -1; seek_event(drv); - } -} - -void UPD765A::set_irq(bool val) -{ + } +} + +void UPD765A::update_config() +{ + // reserved for optional noise device contexts +} + +void UPD765A::set_irq(bool val) +{ #ifdef _FDC_DEBUG_LOG // emu->out_debug_log("FDC: IRQ=%d\n", val ? 1 : 0); #endif diff --git a/Source/ePC-8801MA/vm/upd765a.h b/Source/ePC-8801MA/vm/upd765a.h index 265794d..1c539dc 100644 --- a/Source/ePC-8801MA/vm/upd765a.h +++ b/Source/ePC-8801MA/vm/upd765a.h @@ -24,18 +24,24 @@ #define SIG_UPD765A_DRQ_MASK 6 #define SIG_UPD765A_FREADY 7 -class DISK; +class DISK; +class NOISE; class UPD765A : public DEVICE { private: // output signals - outputs_t outputs_irq; - outputs_t outputs_drq; - outputs_t outputs_hdu; - outputs_t outputs_index; - - // fdc + outputs_t outputs_irq; + outputs_t outputs_drq; + outputs_t outputs_hdu; + outputs_t outputs_index; + + // drive noise (optional) + NOISE* d_noise_seek; + NOISE* d_noise_head_down; + NOISE* d_noise_head_up; + + // fdc struct { uint8 track; uint8 result; @@ -120,14 +126,18 @@ class UPD765A : public DEVICE void cmd_invalid(); public: - UPD765A(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) - { - init_output_signals(&outputs_irq); - init_output_signals(&outputs_drq); - init_output_signals(&outputs_hdu); - init_output_signals(&outputs_index); - raise_irq_when_media_changed = false; - } + UPD765A(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) + { + init_output_signals(&outputs_irq); + init_output_signals(&outputs_drq); + init_output_signals(&outputs_hdu); + init_output_signals(&outputs_index); + d_noise_seek = NULL; + d_noise_head_down = NULL; + d_noise_head_up = NULL; + raise_irq_when_media_changed = false; + set_device_name(_T("uPD765A FDC")); + } ~UPD765A() {} // common functions @@ -141,6 +151,7 @@ class UPD765A : public DEVICE void write_signal(int id, uint32 data, uint32 mask); uint32 read_signal(int ch); void event_callback(int event_id, int err); + void update_config(); void save_state(FILEIO* state_fio); bool load_state(FILEIO* state_fio); bool process_state(FILEIO* state_fio, bool loading); @@ -158,10 +169,34 @@ class UPD765A : public DEVICE { register_output_signal(&outputs_hdu, device, id, mask); } - void set_context_index(DEVICE* device, int id, uint32 mask) - { - register_output_signal(&outputs_index, device, id, mask); - } + void set_context_index(DEVICE* device, int id, uint32 mask) + { + register_output_signal(&outputs_index, device, id, mask); + } + void set_context_noise_seek(NOISE* device) + { + d_noise_seek = device; + } + NOISE* get_context_noise_seek() + { + return d_noise_seek; + } + void set_context_noise_head_down(NOISE* device) + { + d_noise_head_down = device; + } + NOISE* get_context_noise_head_down() + { + return d_noise_head_down; + } + void set_context_noise_head_up(NOISE* device) + { + d_noise_head_up = device; + } + NOISE* get_context_noise_head_up() + { + return d_noise_head_up; + } DISK* get_disk_handler(int drv) { if(drv < 4) { From 3654fcecd5191de13871d800e9321416b9dbe7e6 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 10:20:22 +0900 Subject: [PATCH 04/34] =?UTF-8?q?upd765a=E3=81=AE=E3=82=BB=E3=82=AF?= =?UTF-8?q?=E3=82=BF=E6=8E=A2=E7=B4=A2=E6=9D=A1=E4=BB=B6=E3=82=92=E6=95=B4?= =?UTF-8?q?=E7=90=86=E3=81=97FM/MFM=E5=88=A4=E5=AE=9A=E3=82=92=E5=85=B1?= =?UTF-8?q?=E9=80=9A=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/disk.h | 3 +- Source/ePC-8801MA/vm/upd765a.cpp | 119 +++++++++++++++++-------------- 2 files changed, 68 insertions(+), 54 deletions(-) diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index 4196513..535a9f7 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -195,7 +195,8 @@ class DISK bool check_media_type(); bool correct_timing() { - return false; + // Keep current XM8 behavior: standard images use fixed timing path. + return !is_standard_image; } bool ignore_crc() { diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index ca6dd71..ca316b0 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1029,14 +1029,17 @@ uint32 UPD765A::read_sector() return ST0_AT | ST1_MA; } int cy = -1; - for(int i = 0; i < secnum; i++) { - if(!disk[drv]->get_sector(trk, side, i)) { - continue; - } - cy = disk[drv]->id[0]; -#if 0 - if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { -#else + for(int i = 0; i < secnum; i++) { + if(!disk[drv]->get_sector(trk, side, i)) { + continue; + } + if((command & 0x40) != (disk[drv]->density == 0x00 ? 0x40 : 0)) { + continue; + } + cy = disk[drv]->id[0]; +#if 0 + if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { +#else if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] || disk[drv]->id[3] != id[3]) { #endif continue; @@ -1048,15 +1051,15 @@ uint32 UPD765A::read_sector() } else { memcpy(buffer, disk[drv]->track + disk[drv]->data_position[i], disk[drv]->get_track_size() - disk[drv]->data_position[i]); memcpy(buffer + disk[drv]->get_track_size() - disk[drv]->data_position[i], disk[drv]->track, disk[drv]->data_position[i]); - } - fdc[drv].next_trans_position = disk[drv]->data_position[i]; - - if(disk[drv]->crc_error) { - return ST0_AT | ST1_DE | ST2_DD; - } - if(disk[drv]->deleted) { - return ST2_CM; - } + } + fdc[drv].next_trans_position = disk[drv]->data_position[i]; + + if(disk[drv]->crc_error && !disk[drv]->ignore_crc()) { + return ST0_AT | ST1_DE | ST2_DD; + } + if(disk[drv]->deleted) { + return ST2_CM; + } return 0; } #ifdef _FDC_DEBUG_LOG @@ -1090,14 +1093,17 @@ uint32 UPD765A::write_sector(bool deleted) return ST0_AT | ST1_MA; } int cy = -1; - for(int i = 0; i < secnum; i++) { - if(!disk[drv]->get_sector(trk, side, i)) { - continue; - } - cy = disk[drv]->id[0]; - if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { - continue; - } + for(int i = 0; i < secnum; i++) { + if(!disk[drv]->get_sector(trk, side, i)) { + continue; + } + if((command & 0x40) != (disk[drv]->density == 0x00 ? 0x40 : 0)) { + continue; + } + cy = disk[drv]->id[0]; + if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { + continue; + } // sector number is matched int size = 0x80 << (id[3] & 7); memcpy(disk[drv]->sector, buffer, __min(size, disk[drv]->sector_size.sd)); @@ -1129,14 +1135,17 @@ uint32 UPD765A::find_id() return ST0_AT | ST1_MA; } int cy = -1; - for(int i = 0; i < secnum; i++) { - if(!disk[drv]->get_sector(trk, side, i)) { - continue; - } - cy = disk[drv]->id[0]; - if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { - continue; - } + for(int i = 0; i < secnum; i++) { + if(!disk[drv]->get_sector(trk, side, i)) { + continue; + } + if((command & 0x40) != (disk[drv]->density == 0x00 ? 0x40 : 0)) { + continue; + } + cy = disk[drv]->id[0]; + if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { + continue; + } // sector number is matched fdc[drv].next_trans_position = disk[drv]->data_position[i]; return 0; @@ -1299,19 +1308,23 @@ uint32 UPD765A::read_id() break; } } - for(int i = 0; i < secnum; i++) { - int index = (first_sector + i) % secnum; - if(disk[drv]->get_sector(trk, side, index)) { - id[0] = disk[drv]->id[0]; - id[1] = disk[drv]->id[1]; - id[2] = disk[drv]->id[2]; - id[3] = disk[drv]->id[3]; - fdc[drv].next_trans_position = disk[drv]->id_position[index] + 6; - return 0; - } - } - return ST0_AT | ST1_ND; -} + for(int i = 0; i < secnum; i++) { + int index = (first_sector + i) % secnum; + if(!disk[drv]->get_sector(trk, side, index)) { + continue; + } + if((command & 0x40) != (disk[drv]->density == 0x00 ? 0x40 : 0)) { + continue; + } + id[0] = disk[drv]->id[0]; + id[1] = disk[drv]->id[1]; + id[2] = disk[drv]->id[2]; + id[3] = disk[drv]->id[3]; + fdc[drv].next_trans_position = disk[drv]->id_position[index] + 6; + return 0; + } + return ST0_AT | ST1_ND; +} uint32 UPD765A::write_id() { @@ -1469,13 +1482,13 @@ int UPD765A::get_cur_position(int drv) double UPD765A::get_usec_to_exec_phase() { int drv = hdu & DRIVE_MASK; - int trk = fdc[drv].track; - int side = (hdu >> 2) & 1; - - // XXX: this is a standard image and skew may be incorrect - if(disk[drv]->is_standard_image) { - return 100; - } + int trk = fdc[drv].track; + int side = (hdu >> 2) & 1; + + // XXX: this image may have incorrect skew, so use constant period. + if(!disk[drv]->correct_timing()) { + return 100; + } // search target sector int position = get_cur_position(drv); From ef4b10152ca185c134c6491dcb3926f7ae363fba Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 10:21:37 +0900 Subject: [PATCH 05/34] =?UTF-8?q?upd765a=E3=81=AE=E3=82=BB=E3=82=AF?= =?UTF-8?q?=E3=82=BF=E9=81=B8=E6=8A=9E=E3=81=A8=E3=82=A8=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E3=82=92common=E5=81=B4=E3=81=AB=E8=BF=91?= =?UTF-8?q?=E3=81=A5=E3=81=91=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 61 ++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index ca316b0..6d499da 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1040,11 +1040,14 @@ uint32 UPD765A::read_sector() #if 0 if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { #else - if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] || disk[drv]->id[3] != id[3]) { -#endif - continue; - } - // sector number is matched + if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] || disk[drv]->id[3] != id[3]) { +#endif + continue; + } + if(disk[drv]->sector_size.sd == 0) { + continue; + } + // sector number is matched if(disk[drv]->invalid_format) { memset(buffer, disk[drv]->drive_mfm ? 0x4e : 0xff, sizeof(buffer)); memcpy(buffer, disk[drv]->sector, disk[drv]->sector_size.sd); @@ -1062,12 +1065,15 @@ uint32 UPD765A::read_sector() } return 0; } -#ifdef _FDC_DEBUG_LOG - emu->out_debug_log("FDC: SECTOR NOT FOUND (TRK=%d SIDE=%d ID=%2x,%2x,%2x,%2x)\n", trk, side, id[0], id[1], id[2], id[3]); -#endif - if(cy != id[0] && cy != -1) { - if(cy == 0xff) { - return ST0_AT | ST1_ND | ST2_BC; + #ifdef _FDC_DEBUG_LOG + emu->out_debug_log("FDC: SECTOR NOT FOUND (TRK=%d SIDE=%d ID=%2x,%2x,%2x,%2x)\n", trk, side, id[0], id[1], id[2], id[3]); + #endif + if(cy == -1) { + return ST0_AT | ST1_MA; + } + if(cy != id[0] && cy != -1) { + if(cy == 0xff) { + return ST0_AT | ST1_ND | ST2_BC; } else { return ST0_AT | ST1_ND | ST2_NC; } @@ -1104,11 +1110,14 @@ uint32 UPD765A::write_sector(bool deleted) if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { continue; } - // sector number is matched - int size = 0x80 << (id[3] & 7); - memcpy(disk[drv]->sector, buffer, __min(size, disk[drv]->sector_size.sd)); - disk[drv]->set_deleted(deleted); - return 0; + if(disk[drv]->sector_size.sd == 0) { + continue; + } + // sector number is matched + int size = 0x80 << min((int)id[3], 7); + memcpy(disk[drv]->sector, buffer, __min(size, disk[drv]->sector_size.sd)); + disk[drv]->set_deleted(deleted); + return 0; } if(cy != id[0] && cy != -1) { if(cy == 0xff) { @@ -1146,13 +1155,19 @@ uint32 UPD765A::find_id() if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] /*|| disk[drv]->id[3] != id[3]*/) { continue; } - // sector number is matched - fdc[drv].next_trans_position = disk[drv]->data_position[i]; - return 0; - } - if(cy != id[0] && cy != -1) { - if(cy == 0xff) { - return ST0_AT | ST1_ND | ST2_BC; + if(disk[drv]->sector_size.sd == 0) { + continue; + } + // sector number is matched + fdc[drv].next_trans_position = disk[drv]->data_position[i]; + return 0; + } + if(cy == -1) { + return ST0_AT | ST1_MA; + } + if(cy != id[0] && cy != -1) { + if(cy == 0xff) { + return ST0_AT | ST1_ND | ST2_BC; } else { return ST0_AT | ST1_ND | ST2_NC; } From 08e3dc8eb6f43b093cc37e722e60ce5c7fadbbde Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 10:22:17 +0900 Subject: [PATCH 06/34] =?UTF-8?q?upd765a=E3=81=AEread=5Fid/write=5Fid?= =?UTF-8?q?=E3=81=AE=E7=B5=90=E6=9E=9C=E6=95=B4=E5=90=88=E3=82=92=E8=AA=BF?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 6d499da..46dc497 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1338,15 +1338,15 @@ uint32 UPD765A::read_id() fdc[drv].next_trans_position = disk[drv]->id_position[index] + 6; return 0; } - return ST0_AT | ST1_ND; + return ST0_AT | ST1_MA; } - -uint32 UPD765A::write_id() -{ - int drv = hdu & DRIVE_MASK; - int trk = fdc[drv].track; - int side = (hdu >> 2) & 1; - int length = 0x80 << (id[3] & 7); + +uint32 UPD765A::write_id() +{ + int drv = hdu & DRIVE_MASK; + int trk = fdc[drv].track; + int side = (hdu >> 2) & 1; + int length = 0x80 << min((int)id[3], 7); if((result = check_cond(true)) != 0) { return result; From b00e7ae75b2986167cb3ae58e287e84ced0529b5 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 10:52:26 +0900 Subject: [PATCH 07/34] =?UTF-8?q?noise/vm=5Ftemplate=E3=82=92=E7=8F=BE?= =?UTF-8?q?=E8=A1=8Cxm8=E5=90=91=E3=81=91=E3=81=AB=E6=95=B4=E5=82=99?= =?UTF-8?q?=E3=81=97=E3=83=93=E3=83=AB=E3=83=89=E3=81=B8=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 3 +- Source/ePC-8801MA/vm/noise.cpp | 247 +++++++++++++++++++++++++++++ Source/ePC-8801MA/vm/noise.h | 69 ++++++++ Source/ePC-8801MA/vm/vm_template.h | 15 ++ 4 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 Source/ePC-8801MA/vm/noise.cpp create mode 100644 Source/ePC-8801MA/vm/noise.h create mode 100644 Source/ePC-8801MA/vm/vm_template.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 62a6b3d..375ab6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,6 +127,7 @@ set(SRCS Source/ePC-8801MA/vm/i8255.cpp Source/ePC-8801MA/vm/disksub.cpp Source/ePC-8801MA/vm/pcm1bit.cpp + Source/ePC-8801MA/vm/noise.cpp Source/ePC-8801MA/vm/upd765a.cpp Source/ePC-8801MA/vm/upd1990a.cpp Source/ePC-8801MA/vm/fmsound.cpp @@ -238,4 +239,4 @@ if(ENABLE_PACKAGING) set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) include(CPack) -endif() \ No newline at end of file +endif() diff --git a/Source/ePC-8801MA/vm/noise.cpp b/Source/ePC-8801MA/vm/noise.cpp new file mode 100644 index 0000000..e698e8f --- /dev/null +++ b/Source/ePC-8801MA/vm/noise.cpp @@ -0,0 +1,247 @@ +/* + Skelton for retropc emulator + + Author : Takeda.Toshiya + Date : 2017.03.08- + + [ noise player ] +*/ + +#include "noise.h" + +#include + +#define EVENT_SAMPLE 0 + +#pragma pack(push, 1) +typedef struct { + char id[4]; + uint32 size; +} wav_chunk_t; + +typedef struct { + char riff[4]; + uint32 file_size; + char wave[4]; + wav_chunk_t fmt_chunk; + uint16 format_id; + uint16 channels; + uint32 sample_rate; + uint32 data_speed; + uint16 block_size; + uint16 sample_bits; +} wav_header_t; +#pragma pack(pop) + +static int noise_decibel_to_volume(int decibel) +{ + // +1 equals +0.5dB (same as fmgen/common_source_project). + const double step = 1.0592537251772889; + double factor = 1.0; + if(decibel >= 0) { + for(int i = 0; i < decibel; i++) { + factor *= step; + } + } else { + for(int i = 0; i < -decibel; i++) { + factor /= step; + } + } + return (int)(1024.0 * factor + 0.5); +} + +static int32 noise_apply_volume(int32 sample, int volume) +{ + return (sample * volume) / 1024; +} + +void NOISE::initialize() +{ + register_id = -1; + ptr = 0; + sample_l = sample_r = 0; +} + +void NOISE::release() +{ + if(buffer_l != NULL) { + free(buffer_l); + buffer_l = NULL; + } + if(buffer_r != NULL) { + free(buffer_r); + buffer_r = NULL; + } +} + +void NOISE::reset() +{ + stop(); +} + +void NOISE::event_callback(int event_id, int err) +{ + if(++ptr < samples) { + get_sample(); + } else if(loop) { + ptr = 0; + get_sample(); + } else { + stop(); + } +} + +void NOISE::mix(int32* buffer, int cnt) +{ + if(register_id != -1 && !mute) { + int32 val_l = noise_apply_volume(sample_l, volume_l); + int32 val_r = noise_apply_volume(sample_r, volume_r); + + for(int i = 0; i < cnt; i++) { + *buffer++ += val_l; // L + *buffer++ += val_r; // R + } + } +} + +void NOISE::set_volume(int ch, int decibel_l, int decibel_r) +{ + volume_l = noise_decibel_to_volume(decibel_l); + volume_r = noise_decibel_to_volume(decibel_r); +} + +bool NOISE::load_wav_file(const _TCHAR *file_name) +{ + if(samples != 0) { + // already loaded + return true; + } + FILEIO *fio = new FILEIO(); + bool result = false; + + _TCHAR path[_MAX_PATH]; + _tcscpy_s(path, array_length(path), file_name); + if(fio->Fopen(path, FILEIO_READ_BINARY)) { + wav_header_t header; + wav_chunk_t chunk; + + fio->Fread(&header, sizeof(header), 1); + + if(header.format_id == 1 && (header.sample_bits == 8 || header.sample_bits == 16)) { + if(header.fmt_chunk.size > 16) { + fio->Fseek(header.fmt_chunk.size - 16, FILEIO_SEEK_CUR); + } + while(1) { + if(fio->Fread(&chunk, sizeof(chunk), 1) != 1) { + break; + } + if(strncmp(chunk.id, "data", 4) == 0) { + break; + } + fio->Fseek(chunk.size, FILEIO_SEEK_CUR); + } + if(strncmp(chunk.id, "data", 4) == 0 && header.channels > 0 && + (samples = chunk.size / header.channels) > 0) { + if(header.sample_bits == 16) { + samples /= 2; + } + sample_rate = header.sample_rate; + + buffer_l = (int16 *)malloc(samples * sizeof(int16)); + buffer_r = (int16 *)malloc(samples * sizeof(int16)); + + for(int i = 0; i < samples; i++) { + int sample_lr[2] = {0, 0}; + for(int ch = 0; ch < header.channels; ch++) { + int16 sample = 0; + if(header.sample_bits == 16) { + union { + int16 s16; + struct { + uint8 l, h; + } b; + } pair; + pair.b.l = fio->FgetUint8(); + pair.b.h = fio->FgetUint8(); + sample = pair.s16; + } else { + sample = (int16)(fio->FgetUint8()); + sample = (sample - 128) * 256; + } + if(ch < 2) sample_lr[ch] = sample; + } + buffer_l[i] = sample_lr[0]; + buffer_r[i] = sample_lr[(header.channels > 1) ? 1 : 0]; + } + result = true; + } + } + fio->Fclose(); + } + delete fio; + + return result; +} + +void NOISE::play() +{ + if(samples > 0 && register_id == -1 && !mute) { + register_event(this, EVENT_SAMPLE, 1000000.0 / sample_rate, true, ®ister_id); + ptr = 0; + get_sample(); + } +} + +void NOISE::stop() +{ + if(samples > 0 && register_id != -1) { + cancel_event(this, register_id); + register_id = -1; + sample_l = sample_r = 0; + } +} + +void NOISE::get_sample() +{ + if(buffer_l != NULL && ptr < samples) { + sample_l = buffer_l[ptr]; + } else { + sample_l = 0; + } + if(buffer_r != NULL && ptr < samples) { + sample_r = buffer_r[ptr]; + } else { + sample_r = 0; + } +} + +#define STATE_VERSION 1 + +bool NOISE::process_state(FILEIO* state_fio, bool loading) +{ + if(loading) { + if(state_fio->FgetUint32() != STATE_VERSION) { + return false; + } + if(state_fio->FgetInt32() != this_device_id) { + return false; + } + register_id = state_fio->FgetInt32(); + ptr = state_fio->FgetInt32(); + sample_l = state_fio->FgetInt32(); + sample_r = state_fio->FgetInt32(); + loop = state_fio->FgetBool(); + mute = state_fio->FgetBool(); + } else { + state_fio->FputUint32(STATE_VERSION); + state_fio->FputInt32(this_device_id); + state_fio->FputInt32(register_id); + state_fio->FputInt32(ptr); + state_fio->FputInt32(sample_l); + state_fio->FputInt32(sample_r); + state_fio->FputBool(loop); + state_fio->FputBool(mute); + } + return true; +} + diff --git a/Source/ePC-8801MA/vm/noise.h b/Source/ePC-8801MA/vm/noise.h new file mode 100644 index 0000000..8e8fff4 --- /dev/null +++ b/Source/ePC-8801MA/vm/noise.h @@ -0,0 +1,69 @@ +/* + Skelton for retropc emulator + + Author : Takeda.Toshiya + Date : 2017.03.08- + + [ noise player ] +*/ + +#ifndef _NOISE_H_ +#define _NOISE_H_ + +#include "vm_template.h" +#include "../emu.h" +#include "device.h" + +class NOISE : public DEVICE +{ +private: + int16* buffer_l; + int16* buffer_r; + int samples; + int sample_rate; + int register_id; + int ptr; + int sample_l, sample_r; + int volume_l, volume_r; + bool loop; + bool mute; + + void get_sample(); + +public: + NOISE(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) + { + buffer_l = buffer_r = NULL; + samples = 0; + volume_l = volume_r = 1024; + loop = false; + mute = false; + set_device_name(_T("Noise Player")); + } + ~NOISE() {} + + // common functions + void initialize(); + void release(); + void reset(); + void event_callback(int event_id, int err); + void mix(int32* buffer, int cnt); + void set_volume(int ch, int decibel_l, int decibel_r); + bool process_state(FILEIO* state_fio, bool loading); + + // unique functions + bool load_wav_file(const _TCHAR *file_name); + void play(); + void stop(); + void set_loop(bool value) + { + loop = value; + } + void set_mute(bool value) + { + mute = value; + } +}; + +#endif + diff --git a/Source/ePC-8801MA/vm/vm_template.h b/Source/ePC-8801MA/vm/vm_template.h new file mode 100644 index 0000000..b59613a --- /dev/null +++ b/Source/ePC-8801MA/vm/vm_template.h @@ -0,0 +1,15 @@ +/* + Skelton for retropc emulator + + [ vm template compatibility header ] +*/ + +#ifndef _VM_TEMPLATE_H_ +#define _VM_TEMPLATE_H_ + +#include "vm.h" + +// Compatibility alias for common_source_project code. +typedef VM VM_TEMPLATE; + +#endif /* _VM_TEMPLATE_H_ */ From 6d1dd9b63073df56e41957cab73991e72a04df25 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 11:10:25 +0900 Subject: [PATCH 08/34] =?UTF-8?q?pc8801/upd765a=E3=81=ABFDD=E3=83=8E?= =?UTF-8?q?=E3=82=A4=E3=82=BA=E9=85=8D=E7=B7=9A=E3=82=92=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=E3=81=97seek=E6=99=82=E3=81=AB=E5=86=8D=E7=94=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/pc8801/pc8801.cpp | 52 ++++++++++-------- Source/ePC-8801MA/vm/pc8801/pc8801.h | 4 ++ Source/ePC-8801MA/vm/upd765a.cpp | 74 +++++++++++++++++--------- 3 files changed, 85 insertions(+), 45 deletions(-) diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp index d2b879f..3b77d73 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp @@ -22,9 +22,10 @@ #include "../fmsound.h" #include "../z80.h" -#include "../disk.h" -#include "../disksub.h" -#include "../upd765a.h" +#include "../disk.h" +#include "../disksub.h" +#include "../noise.h" +#include "../upd765a.h" #ifdef USE_DEBUGGER #include "../debugger.h" @@ -72,10 +73,10 @@ VM::VM(EMU* parent_emu) : emu(parent_emu) // pc88sub->set_context_event_manager(pc88event); pc88pio_sub = new I8255(this, emu); // pc88pio_sub->set_context_event_manager(pc88event); - pc88fdc_sub = new UPD765A(this, emu); -// pc88fdc_sub->set_context_event_manager(pc88event); - pc88cpu_sub = new Z80(this, emu); -// pc88cpu_sub->set_context_event_manager(pc88event); + pc88fdc_sub = new UPD765A(this, emu); +// pc88fdc_sub->set_context_event_manager(pc88event); + pc88cpu_sub = new Z80(this, emu); +// pc88cpu_sub->set_context_event_manager(pc88event); #ifdef SUPPORT_PC88_PCG8100 pc88pit = new I8253(this, emu); @@ -87,7 +88,10 @@ VM::VM(EMU* parent_emu) : emu(parent_emu) pc88pcm2 = new PCM1BIT(this, emu); // pc88pcm->set_context_event_manager(pc88event); #endif - pc88sb2 = new FMSound(this, emu); + pc88sb2 = new FMSound(this, emu); + pc88noise_seek = new NOISE(this, emu); + pc88noise_head_down = new NOISE(this, emu); + pc88noise_head_up = new NOISE(this, emu); #ifdef SUPPORT_PC88_HIGH_CLOCK @@ -96,12 +100,15 @@ VM::VM(EMU* parent_emu) : emu(parent_emu) pc88event->set_context_cpu(pc88cpu, 3993624); #endif pc88event->set_context_cpu(pc88cpu_sub, 3993624); - pc88event->set_context_sound(pc88opn); - pc88event->set_context_sound(pc88sb2); - pc88event->set_context_sound(pc88pcm); -#ifdef SUPPORT_PC88_PCG8100 - pc88event->set_context_sound(pc88pcm0); - pc88event->set_context_sound(pc88pcm1); + pc88event->set_context_sound(pc88opn); + pc88event->set_context_sound(pc88sb2); + pc88event->set_context_sound(pc88pcm); + pc88event->set_context_sound(pc88noise_seek); + pc88event->set_context_sound(pc88noise_head_down); + pc88event->set_context_sound(pc88noise_head_up); +#ifdef SUPPORT_PC88_PCG8100 + pc88event->set_context_sound(pc88pcm0); + pc88event->set_context_sound(pc88pcm1); pc88event->set_context_sound(pc88pcm2); #endif @@ -139,13 +146,16 @@ VM::VM(EMU* parent_emu) : emu(parent_emu) pc88pio->clear_ports_by_cmdreg = true; pc88pio_sub->set_context_port_a(pc88pio, SIG_I8255_PORT_B, 0xff, 0); pc88pio_sub->set_context_port_b(pc88pio, SIG_I8255_PORT_A, 0xff, 0); - pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4); - pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4); - pc88pio_sub->clear_ports_by_cmdreg = true; - pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1); - pc88cpu_sub->set_context_mem(pc88sub); - pc88cpu_sub->set_context_io(pc88sub); - pc88cpu_sub->set_context_intr(pc88sub); + pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0x0f, 4); + pc88pio_sub->set_context_port_c(pc88pio, SIG_I8255_PORT_C, 0xf0, -4); + pc88pio_sub->clear_ports_by_cmdreg = true; + pc88fdc_sub->set_context_irq(pc88cpu_sub, SIG_CPU_IRQ, 1); + pc88fdc_sub->set_context_noise_seek(pc88noise_seek); + pc88fdc_sub->set_context_noise_head_down(pc88noise_head_down); + pc88fdc_sub->set_context_noise_head_up(pc88noise_head_up); + pc88cpu_sub->set_context_mem(pc88sub); + pc88cpu_sub->set_context_io(pc88sub); + pc88cpu_sub->set_context_intr(pc88sub); #ifdef USE_DEBUGGER pc88cpu_sub->set_context_debugger(new DEBUGGER(this, emu)); #endif diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.h b/Source/ePC-8801MA/vm/pc8801/pc8801.h index a8dee3b..0a9c5d3 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.h +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.h @@ -115,6 +115,7 @@ class DiskSub; class PC80S31K; #endif // SDL class UPD765A; +class NOISE; #ifdef SUPPORT_PC88_PCG8100 class I8253; @@ -149,6 +150,9 @@ class VM #endif // SDL I8255* pc88pio_sub; UPD765A* pc88fdc_sub; + NOISE* pc88noise_seek; + NOISE* pc88noise_head_down; + NOISE* pc88noise_head_up; Z80* pc88cpu_sub; #ifdef SUPPORT_PC88_PCG8100 diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 46dc497..e972e16 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -8,8 +8,9 @@ [ uPD765A ] */ -#include "upd765a.h" -#include "disk.h" +#include "upd765a.h" +#include "disk.h" +#include "noise.h" #define EVENT_PHASE 0 #define EVENT_DRQ 1 @@ -141,16 +142,37 @@ } \ } -void UPD765A::initialize() -{ - // initialize d88 handler - for(int i = 0; i < 4; i++) { - disk[i] = new DISK(emu); - } - - // initialize fdc - memset(fdc, 0, sizeof(fdc)); - memset(buffer, 0, sizeof(buffer)); +void UPD765A::initialize() +{ + // initialize d88 handler + for(int i = 0; i < 4; i++) { + disk[i] = new DISK(emu); + } + + // initialize optional drive noise players + if(d_noise_seek != NULL) { + d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)")); + if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) { + if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) { + d_noise_seek->load_wav_file(_T("SEEK.WAV")); + } + } + d_noise_seek->set_mute(false); + } + if(d_noise_head_down != NULL) { + d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)")); + d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV")); + d_noise_head_down->set_mute(false); + } + if(d_noise_head_up != NULL) { + d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)")); + d_noise_head_up->load_wav_file(_T("HEADUP.WAV")); + d_noise_head_up->set_mute(false); + } + + // initialize fdc + memset(fdc, 0, sizeof(fdc)); + memset(buffer, 0, sizeof(buffer)); phase = prevphase = PHASE_IDLE; status = S_RQM; @@ -687,24 +709,28 @@ void UPD765A::cmd_recalib() } } -void UPD765A::seek(int drv, int trk) -{ - // get distance - int seektime = 32 - 2 * step_rate_time; - if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { - seektime /= 2; - } +void UPD765A::seek(int drv, int trk) +{ + // get distance + int prev_track = fdc[drv].track; + int seektime = 32 - 2 * step_rate_time; + if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { + seektime /= 2; + } seektime = (trk == fdc[drv].track) ? 120 : seektime * abs(trk - fdc[drv].track) + 500; //usec if(drv >= MAX_DRIVE) { // invalid drive number fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; set_irq(true); - } else { - fdc[drv].track = trk; -#ifdef UPD765A_DONT_WAIT_SEEK - seek_event(drv); -#else + } else { + fdc[drv].track = trk; + if(prev_track != trk && d_noise_seek != NULL) { + d_noise_seek->play(); + } +#ifdef UPD765A_DONT_WAIT_SEEK + seek_event(drv); +#else if(seek_id[drv] != -1) { cancel_event(this, seek_id[drv]); } From 9874ac49c84c36c22b8bbff9fd12bf492c510d1a Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 11:22:50 +0900 Subject: [PATCH 09/34] =?UTF-8?q?Windows=E3=83=97=E3=83=AD=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=82=AF=E3=83=88=E3=81=ABnoise.cpp/noise.h=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=81=97=E3=81=A6=E3=83=AA=E3=83=B3=E3=82=AF?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=82=92=E8=A7=A3=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Builder/Windows/XM8.vcxproj | 16 +++++++++------- Builder/Windows/XM8.vcxproj.filters | 20 +++++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Builder/Windows/XM8.vcxproj b/Builder/Windows/XM8.vcxproj index e0758aa..45d137d 100644 --- a/Builder/Windows/XM8.vcxproj +++ b/Builder/Windows/XM8.vcxproj @@ -366,9 +366,10 @@ - - - + + + + @@ -416,9 +417,10 @@ - - - + + + + @@ -452,4 +454,4 @@ - \ No newline at end of file + diff --git a/Builder/Windows/XM8.vcxproj.filters b/Builder/Windows/XM8.vcxproj.filters index ba82036..1085d49 100644 --- a/Builder/Windows/XM8.vcxproj.filters +++ b/Builder/Windows/XM8.vcxproj.filters @@ -105,9 +105,12 @@ ソース ファイル\ePC-8801MA\vm\pc8801 - - ソース ファイル\ePC-8801MA\vm\pc8801 - + + ソース ファイル\ePC-8801MA\vm\pc8801 + + + ソース ファイル\ePC-8801MA\vm + ソース ファイル\UI @@ -236,9 +239,12 @@ ヘッダー ファイル\ePC-8801MA\vm - - ヘッダー ファイル\ePC-8801MA\vm\pc8801 - + + ヘッダー ファイル\ePC-8801MA\vm\pc8801 + + + ヘッダー ファイル\ePC-8801MA\vm + ヘッダー ファイル\UI @@ -332,4 +338,4 @@ リソース ファイル - \ No newline at end of file + From 40904db00957339c4abd5443be576ca61ec790ca Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 11:33:35 +0900 Subject: [PATCH 10/34] =?UTF-8?q?upd765a=E3=81=AB=E3=83=98=E3=83=83?= =?UTF-8?q?=E3=83=89=E3=83=AD=E3=83=BC=E3=83=89/=E3=82=A2=E3=83=B3?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=89=E5=88=B6=E5=BE=A1=E3=82=92=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D=E3=81=97FDD=E3=83=98=E3=83=83=E3=83=89=E3=83=8E?= =?UTF-8?q?=E3=82=A4=E3=82=BA=E3=82=92=E5=86=8D=E7=94=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 356 +++++++++++++++++++------------ Source/ePC-8801MA/vm/upd765a.h | 52 ++--- 2 files changed, 246 insertions(+), 162 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index e972e16..764cef8 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -15,9 +15,10 @@ #define EVENT_PHASE 0 #define EVENT_DRQ 1 #define EVENT_LOST 2 -#define EVENT_RESULT7 3 -#define EVENT_INDEX 4 -#define EVENT_SEEK 5 +#define EVENT_RESULT7 3 +#define EVENT_INDEX 4 +#define EVENT_SEEK 5 +#define EVENT_UNLOAD 9 #define PHASE_IDLE 0 #define PHASE_CMD 1 @@ -134,13 +135,17 @@ cancel_event(this, result7_id); \ result7_id = -1; \ } \ - for(int d = 0; d < 4; d++) { \ - if(seek_id[d] != -1) { \ - cancel_event(this, seek_id[d]); \ - seek_id[d] = -1; \ - } \ - } \ -} + for(int d = 0; d < 4; d++) { \ + if(seek_id[d] != -1) { \ + cancel_event(this, seek_id[d]); \ + seek_id[d] = -1; \ + } \ + if(head_unload_id[d] != -1) { \ + cancel_event(this, head_unload_id[d]); \ + head_unload_id[d] = -1; \ + } \ + } \ +} void UPD765A::initialize() { @@ -172,15 +177,18 @@ void UPD765A::initialize() // initialize fdc memset(fdc, 0, sizeof(fdc)); + memset(head_load, 0, sizeof(head_load)); memset(buffer, 0, sizeof(buffer)); phase = prevphase = PHASE_IDLE; status = S_RQM; seekstat = 0; - bufptr = buffer; // temporary - phase_id = drq_id = lost_id = result7_id = -1; - seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; - no_dma_mode = false; + bufptr = buffer; // temporary + phase_id = drq_id = lost_id = result7_id = -1; + seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; + head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; + head_unload_time = 0; + no_dma_mode = false; motor_on = false; // motor off force_ready = false; reset_signal = true; @@ -211,16 +219,18 @@ void UPD765A::release() } } -void UPD765A::reset() -{ - shift_to_idle(); -// CANCEL_EVENT(); - phase_id = drq_id = lost_id = result7_id = -1; - seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; - - set_irq(false); - set_drq(false); -} +void UPD765A::reset() +{ + shift_to_idle(); +// CANCEL_EVENT(); + phase_id = drq_id = lost_id = result7_id = -1; + seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; + head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; + head_load[0] = head_load[1] = head_load[2] = head_load[3] = false; + + set_irq(false); + set_drq(false); +} void UPD765A::write_io8(uint32 addr, uint32 data) { @@ -503,10 +513,19 @@ void UPD765A::event_callback(int event_id, int err) write_signals(&outputs_index, now_index ? 0xffffffff : 0); prev_index = now_index; } - } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) { - int drv = event_id - EVENT_SEEK; - seek_id[drv] = -1; - seek_event(drv); + } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) { + int drv = event_id - EVENT_SEEK; + seek_id[drv] = -1; + seek_event(drv); + } else if(event_id >= EVENT_UNLOAD && event_id < EVENT_UNLOAD + 4) { + int drv = event_id - EVENT_UNLOAD; + if(head_load[drv]) { + if(d_noise_head_up != NULL) { + d_noise_head_up->play(); + } + head_load[drv] = false; + } + head_unload_id[drv] = -1; } } @@ -745,13 +764,11 @@ void UPD765A::seek(int drv, int trk) } } -void UPD765A::seek_event(int drv) -{ - int trk = fdc[drv].track; - - if(drv >= MAX_DRIVE) { - fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; - } else if(force_ready || disk[drv]->inserted) { +void UPD765A::seek_event(int drv) +{ + if(drv >= MAX_DRIVE) { + fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; + } else if(force_ready || disk[drv]->inserted) { fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE; } else { #ifdef UPD765A_NO_ST0_AT_FOR_SEEK @@ -768,16 +785,17 @@ void UPD765A::seek_event(int drv) disk[drv]->changed = false; } -void UPD765A::cmd_read_data() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(8); - break; - case PHASE_CMD: - get_sector_params(); - REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); - break; +void UPD765A::cmd_read_data() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(8); + break; + case PHASE_CMD: + get_sector_params(); + start_transfer(); + REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); + break; case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { @@ -810,16 +828,17 @@ void UPD765A::cmd_read_data() } } -void UPD765A::cmd_write_data() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(8); - break; - case PHASE_CMD: - get_sector_params(); - REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); - break; +void UPD765A::cmd_write_data() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(8); + break; + case PHASE_CMD: + get_sector_params(); + start_transfer(); + REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); + break; case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { @@ -876,17 +895,18 @@ void UPD765A::cmd_write_data() } } -void UPD765A::cmd_scan() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(9); - break; - case PHASE_CMD: - get_sector_params(); - dtl = dtl | 0x100; - REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); - break; +void UPD765A::cmd_scan() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(9); + break; + case PHASE_CMD: + get_sector_params(); + dtl = dtl | 0x100; + start_transfer(); + REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); + break; case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { @@ -920,16 +940,17 @@ void UPD765A::cmd_scan() } } -void UPD765A::cmd_read_diagnostic() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(8); - break; - case PHASE_CMD: - get_sector_params(); - REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); - break; +void UPD765A::cmd_read_diagnostic() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(8); + break; + case PHASE_CMD: + get_sector_params(); + start_transfer(); + REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); + break; case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { @@ -1250,16 +1271,17 @@ bool UPD765A::id_incr() return false; } -void UPD765A::cmd_read_id() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(1); - break; - case PHASE_CMD: - set_hdu(buffer[0]); -// break; - case PHASE_EXEC: +void UPD765A::cmd_read_id() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(1); + break; + case PHASE_CMD: + set_hdu(buffer[0]); + start_transfer(); +// break; + case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000); @@ -1287,11 +1309,11 @@ void UPD765A::cmd_read_id() } } -void UPD765A::cmd_write_id() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(5); +void UPD765A::cmd_write_id() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(5); break; case PHASE_CMD: set_hdu(buffer[0]); @@ -1299,13 +1321,14 @@ void UPD765A::cmd_write_id() eot = buffer[2]; gpl = buffer[3]; dtl = buffer[4]; // temporary - if(!eot) { - REGISTER_PHASE_EVENT(PHASE_TIMER, 1000000); - break; - } - fdc[hdu & DRIVE_MASK].next_trans_position = get_cur_position(hdu & DRIVE_MASK); - shift_to_write(4 * eot); - break; + if(!eot) { + REGISTER_PHASE_EVENT(PHASE_TIMER, 1000000); + break; + } + start_transfer(); + fdc[hdu & DRIVE_MASK].next_trans_position = get_cur_position(hdu & DRIVE_MASK); + shift_to_write(4 * eot); + break; case PHASE_TC: case PHASE_WRITE: REGISTER_PHASE_EVENT(PHASE_TIMER, 4000000); @@ -1397,12 +1420,13 @@ void UPD765A::cmd_specify() case PHASE_IDLE: shift_to_cmd(2); break; - case PHASE_CMD: - step_rate_time = buffer[0] >> 4; - no_dma_mode = ((buffer[1] & 1) != 0); - shift_to_idle(); - status = 0x80;//0xff; - break; + case PHASE_CMD: + step_rate_time = buffer[0] >> 4; + head_unload_time = buffer[1] >> 1; + no_dma_mode = ((buffer[1] & 1) != 0); + shift_to_idle(); + status = 0x80;//0xff; + break; } } @@ -1480,22 +1504,23 @@ void UPD765A::shift_to_result(int length) count = length; } -void UPD765A::shift_to_result7() -{ -#ifdef UPD765A_WAIT_RESULT7 +void UPD765A::shift_to_result7() +{ +#ifdef UPD765A_WAIT_RESULT7 if(result7_id != -1) { cancel_event(this, result7_id); result7_id = -1; } - if(phase != PHASE_TIMER) { - register_event(this, EVENT_RESULT7, 100, false, &result7_id); - } else -#endif - shift_to_result7_event(); -} + if(phase != PHASE_TIMER) { + register_event(this, EVENT_RESULT7, 100, false, &result7_id); + } else +#endif + shift_to_result7_event(); + finish_transfer(); +} -void UPD765A::shift_to_result7_event() -{ +void UPD765A::shift_to_result7_event() +{ #ifdef UPD765A_NO_ST1_EN_OR_FOR_RESULT7 // for NEC PC-9801 (XANADU) result &= ~(ST1_EN | ST1_OR); @@ -1507,9 +1532,41 @@ void UPD765A::shift_to_result7_event() buffer[4] = id[1]; buffer[5] = id[2]; buffer[6] = id[3]; - set_irq(true); - shift_to_result(7); -} + set_irq(true); + shift_to_result(7); +} + +void UPD765A::start_transfer() +{ + int drv = hdu & DRIVE_MASK; + + if(head_unload_id[drv] != -1) { + cancel_event(this, head_unload_id[drv]); + head_unload_id[drv] = -1; + } + if(!head_load[drv]) { + if(d_noise_head_down != NULL) { + d_noise_head_down->play(); + } + head_load[drv] = true; + } +} + +void UPD765A::finish_transfer() +{ + int drv = hdu & DRIVE_MASK; + + if(head_load[drv]) { + if(head_unload_id[drv] != -1) { + cancel_event(this, head_unload_id[drv]); + } + int time = (16 * (head_unload_time + 1)) * 1000; // msec -> usec + if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { + time /= 2; + } + register_event(this, EVENT_UNLOAD + drv, time, false, &head_unload_id[drv]); + } +} // ---------------------------------------------------------------------------- // timing @@ -1595,10 +1652,20 @@ void UPD765A::open_disk(int drv, _TCHAR path[], int bank) void UPD765A::close_disk(int drv) { - if(drv < MAX_DRIVE && disk[drv]->inserted) { - disk[drv]->close(); -#ifdef _FDC_DEBUG_LOG - emu->out_debug_log("FDC: Disk Ejected (Drive=%d)\n", drv); + if(drv < MAX_DRIVE && disk[drv]->inserted) { + if(head_unload_id[drv] != -1) { + cancel_event(this, head_unload_id[drv]); + head_unload_id[drv] = -1; + } + if(head_load[drv]) { + if(d_noise_head_up != NULL) { + d_noise_head_up->play(); + } + head_load[drv] = false; + } + disk[drv]->close(); +#ifdef _FDC_DEBUG_LOG + emu->out_debug_log("FDC: Disk Ejected (Drive=%d)\n", drv); #endif if(raise_irq_when_media_changed) { fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI; @@ -1687,10 +1754,10 @@ void UPD765A::set_drive_mfm(int drv, bool mfm) } } -#define STATE_VERSION 1 +#define STATE_VERSION 2 -void UPD765A::save_state(FILEIO* state_fio) -{ +void UPD765A::save_state(FILEIO* state_fio) +{ state_fio->FputUint32(STATE_VERSION); state_fio->FputInt32(this_device_id); @@ -1731,18 +1798,22 @@ void UPD765A::save_state(FILEIO* state_fio) state_fio->FputInt32(lost_id); state_fio->FputInt32(result7_id); state_fio->Fwrite(seek_id, sizeof(seek_id), 1); - state_fio->FputBool(force_ready); - state_fio->FputBool(reset_signal); - state_fio->FputBool(prev_index); - state_fio->FputUint32(prev_drq_clock); -} - + state_fio->FputBool(force_ready); + state_fio->FputBool(reset_signal); + state_fio->FputBool(prev_index); + state_fio->FputUint32(prev_drq_clock); + state_fio->Fwrite(head_load, sizeof(head_load), 1); + state_fio->FputInt32(head_unload_time); + state_fio->Fwrite(head_unload_id, sizeof(head_unload_id), 1); +} + bool UPD765A::load_state(FILEIO* state_fio) { - if(state_fio->FgetUint32() != STATE_VERSION) { - return false; - } - if(state_fio->FgetInt32() != this_device_id) { + uint32 state_version = state_fio->FgetUint32(); + if(state_version < 1 || state_version > STATE_VERSION) { + return false; + } + if(state_fio->FgetInt32() != this_device_id) { return false; } state_fio->Fread(fdc, sizeof(fdc), 1); @@ -1784,10 +1855,19 @@ bool UPD765A::load_state(FILEIO* state_fio) lost_id = state_fio->FgetInt32(); result7_id = state_fio->FgetInt32(); state_fio->Fread(seek_id, sizeof(seek_id), 1); - force_ready = state_fio->FgetBool(); - reset_signal = state_fio->FgetBool(); - prev_index = state_fio->FgetBool(); + force_ready = state_fio->FgetBool(); + reset_signal = state_fio->FgetBool(); + prev_index = state_fio->FgetBool(); prev_drq_clock = state_fio->FgetUint32(); + if(state_version >= 2) { + state_fio->Fread(head_load, sizeof(head_load), 1); + head_unload_time = state_fio->FgetInt32(); + state_fio->Fread(head_unload_id, sizeof(head_unload_id), 1); + } else { + head_load[0] = head_load[1] = head_load[2] = head_load[3] = false; + head_unload_time = 0; + head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; + } return true; } diff --git a/Source/ePC-8801MA/vm/upd765a.h b/Source/ePC-8801MA/vm/upd765a.h index c69299c..c560152 100644 --- a/Source/ePC-8801MA/vm/upd765a.h +++ b/Source/ePC-8801MA/vm/upd765a.h @@ -42,37 +42,39 @@ class UPD765A : public DEVICE NOISE* d_noise_head_up; // fdc - struct { - uint8 track; - uint8 result; - bool access; + struct { + uint8 track; + uint8 result; + bool access; // timing int cur_position; - int next_trans_position; - uint32 prev_clock; - } fdc[4]; - DISK* disk[4]; + int next_trans_position; + uint32 prev_clock; + } fdc[4]; + bool head_load[4]; + DISK* disk[4]; uint8 hdu, hdue, id[4], eot, gpl, dtl; int phase, prevphase; - uint8 status, seekstat, command; - uint32 result; - int step_rate_time; - bool no_dma_mode, motor_on; + uint8 status, seekstat, command; + uint32 result; + int step_rate_time; + int head_unload_time; + bool no_dma_mode, motor_on; #ifdef UPD765A_DMA_MODE bool dma_data_lost; #endif bool irq_masked, drq_masked; - uint8* bufptr; - uint8 buffer[0x8000]; - int count; - int event_phase; - int phase_id, drq_id, lost_id, result7_id, seek_id[4]; - bool force_ready; - bool reset_signal; - bool prev_index; + uint8* bufptr; + uint8 buffer[0x8000]; + int count; + int event_phase; + int phase_id, drq_id, lost_id, result7_id, seek_id[4], head_unload_id[4]; + bool force_ready; + bool reset_signal; + bool prev_index; // timing uint32 prev_drq_clock; @@ -91,10 +93,12 @@ class UPD765A : public DEVICE void shift_to_exec(); void shift_to_read(int length); void shift_to_write(int length); - void shift_to_scan(int length); - void shift_to_result(int length); - void shift_to_result7(); - void shift_to_result7_event(); + void shift_to_scan(int length); + void shift_to_result(int length); + void shift_to_result7(); + void shift_to_result7_event(); + void start_transfer(); + void finish_transfer(); // command void process_cmd(int cmd); From 9d3fec5266e3136de12d29df23a96c36fb242fe0 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 11:46:00 +0900 Subject: [PATCH 11/34] =?UTF-8?q?EVENT=E3=81=AE=E3=82=B5=E3=82=A6=E3=83=B3?= =?UTF-8?q?=E3=83=89=E7=99=BB=E9=8C=B2=E4=B8=8A=E9=99=90=E8=B6=85=E9=81=8E?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=E3=81=97=E3=82=B2=E3=83=BC=E3=83=A0?= =?UTF-8?q?=E9=9F=B3=E6=B6=88=E5=A4=B1=E3=82=92=E8=A7=A3=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/event.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Source/ePC-8801MA/vm/event.h b/Source/ePC-8801MA/vm/event.h index 0575d5f..80cea41 100644 --- a/Source/ePC-8801MA/vm/event.h +++ b/Source/ePC-8801MA/vm/event.h @@ -14,8 +14,8 @@ #include "../emu.h" #include "device.h" -#define MAX_CPU 8 -#define MAX_SOUND 8 +#define MAX_CPU 8 +#define MAX_SOUND 16 #define MAX_LINES 1024 #define MAX_EVENT 64 #define NO_EVENT -1 @@ -201,10 +201,12 @@ class EVENT : public DEVICE { set_context_cpu(device, CPU_CLOCKS); } - void set_context_sound(DEVICE* device) - { - d_sound[dcount_sound++] = device; - } + void set_context_sound(DEVICE* device) + { + if(dcount_sound < MAX_SOUND) { + d_sound[dcount_sound++] = device; + } + } bool now_skip(); #ifdef SDL void abort_main_cpu() { d_cpu[0].device->write_signal(SIG_CPU_FIRQ, 1, 1); } From 084cf4622c13591b828d31a4d71eddbefd19eec6 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 11:55:25 +0900 Subject: [PATCH 12/34] =?UTF-8?q?disk=E3=81=AEtrack=5Fmfm=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E3=82=92=E5=B0=8E=E5=85=A5=E3=81=97write=5Fid?= =?UTF-8?q?=E3=81=AEFM/MFM=E5=8F=8D=E6=98=A0=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/disk.cpp | 159 ++++++++++++++++++------------- Source/ePC-8801MA/vm/disk.h | 26 ++--- Source/ePC-8801MA/vm/upd765a.cpp | 17 ++-- 3 files changed, 117 insertions(+), 85 deletions(-) diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index cee1ba6..db57803 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -397,11 +397,12 @@ void DISK::close() } ejected = true; } - inserted = write_protected = false; - file_size.d = 0; - sector_size.sd = sector_num.sd = 0; - sector = NULL; -} + inserted = write_protected = false; + file_size.d = 0; + sector_size.sd = sector_num.sd = 0; + sector = NULL; + track_mfm = drive_mfm; +} bool DISK::get_track(int trk, int side) { @@ -429,36 +430,53 @@ bool DISK::get_track(int trk, int side) return false; } - // track found - sector = buffer + offset.d; - sector_num.read_2bytes_le_from(sector + 4); - pair data_size; - data_size.read_2bytes_le_from(sector + 14); - - // create each sector position in track - int sync_size = drive_mfm ? 12 : 6; - int am_size = drive_mfm ? 3 : 0; - int gap0_size = drive_mfm ? 80 : 40; - int gap1_size = drive_mfm ? 50 : 26; - int gap2_size = drive_mfm ? 22 : 11; - int gap3_size = 0, gap4_size; - - if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) { - if(drive_mfm) { - if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54; - if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84; - if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116; - } else { - if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27; + // track found + sector = buffer + offset.d; + sector_num.read_2bytes_le_from(sector + 4); + pair data_size; + data_size.read_2bytes_le_from(sector + 14); + + // detect actual density from sector headers in this track. + track_mfm = false; + if(sector_num.sd == 0) { + track_mfm = drive_mfm; + } else { + uint8* t = sector; + for(int i = 0; i < sector_num.sd; i++) { + data_size.read_2bytes_le_from(t + 14); + // t[6]: 0x00 = MFM(double-density), 0x40 = FM(single-density) + if(t[6] == 0x00) { + track_mfm = true; + break; + } + t += data_size.sd + 0x10; + } + } + + // create each sector position in track + int sync_size = track_mfm ? 12 : 6; + int am_size = track_mfm ? 3 : 0; + int gap0_size = track_mfm ? 80 : 40; + int gap1_size = track_mfm ? 50 : 26; + int gap2_size = track_mfm ? 22 : 11; + int gap3_size = 0, gap4_size; + + if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) { + if(track_mfm) { + if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54; + if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84; + if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116; + } else { + if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27; if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42; if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58; } } else { - if(drive_mfm) { - if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51; - if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80; - if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116; - } else { + if(track_mfm) { + if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51; + if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80; + if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116; + } else { if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27; if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42; if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58; @@ -524,11 +542,11 @@ bool DISK::make_track(int trk, int side) return false; } - // make track image - int sync_size = drive_mfm ? 12 : 6; - int am_size = drive_mfm ? 3 : 0; - int gap2_size = drive_mfm ? 22 : 11; - uint8 gap_data = drive_mfm ? 0x4e : 0xff; + // make track image + int sync_size = track_mfm ? 12 : 6; + int am_size = track_mfm ? 3 : 0; + int gap2_size = track_mfm ? 22 : 11; + uint8 gap_data = track_mfm ? 0x4e : 0xff; // preamble memset(track, gap_data, track_size); @@ -753,10 +771,11 @@ bool DISK::format_track(int trk, int side) offset.d = DISK_BUFFER_SIZE; offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4); - trim_required = true; - sector_num.sd = 0; - return true; -} + trim_required = true; + sector_num.sd = 0; + track_mfm = drive_mfm; + return true; +} void DISK::insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool crc_error, uint8 fill_data, int length) { @@ -776,7 +795,7 @@ void DISK::insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool t[3] = n; t[4] = sector_num.b.l; t[5] = sector_num.b.h; - t[6] = drive_mfm ? 0 : 0x40; + t[6] = track_mfm ? 0 : 0x40; t[7] = deleted ? 0x10 : 0; t[8] = crc_error ? 0xb0 : t[7]; // FIXME: always data crc error ? t[14] = (length >> 0) & 0xff; @@ -881,12 +900,12 @@ int DISK::get_max_tracks() int DISK::get_track_size() { - if(inserted) { - return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100; - } else { - return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100; - } -} + if(inserted) { + return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100; + } else { + return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100; + } +} double DISK::get_usec_per_bytes(int bytes) { @@ -1553,11 +1572,11 @@ bool DISK::standard_to_d88(int type, int ncyl, int nside, int nsec, int size) return true; } -#define STATE_VERSION 4 +#define STATE_VERSION 5 -void DISK::save_state(FILEIO* state_fio) -{ - state_fio->FputUint32(STATE_VERSION); +void DISK::save_state(FILEIO* state_fio) +{ + state_fio->FputUint32(STATE_VERSION); state_fio->Fwrite(buffer, sizeof(buffer), 1); state_fio->Fwrite(orig_path, sizeof(orig_path), 1); @@ -1576,10 +1595,11 @@ void DISK::save_state(FILEIO* state_fio) state_fio->FputInt32(is_special_disk); state_fio->Fwrite(track, sizeof(track), 1); state_fio->FputInt32(sector_num.sd); - state_fio->FputBool(invalid_format); - state_fio->FputBool(no_skew); - state_fio->Fwrite(sync_position, sizeof(sync_position), 1); - state_fio->Fwrite(id_position, sizeof(id_position), 1); + state_fio->FputBool(invalid_format); + state_fio->FputBool(no_skew); + state_fio->FputBool(track_mfm); + state_fio->Fwrite(sync_position, sizeof(sync_position), 1); + state_fio->Fwrite(id_position, sizeof(id_position), 1); state_fio->Fwrite(data_position, sizeof(data_position), 1); state_fio->FputInt32(sector ? (int)(sector - buffer) : -1); state_fio->FputInt32(sector_size.sd); @@ -1594,9 +1614,10 @@ void DISK::save_state(FILEIO* state_fio) bool DISK::load_state(FILEIO* state_fio) { - if(state_fio->FgetUint32() != STATE_VERSION) { - return false; - } + uint32 state_version = state_fio->FgetUint32(); + if(state_version < 4 || state_version > STATE_VERSION) { + return false; + } state_fio->Fread(buffer, sizeof(buffer), 1); state_fio->Fread(orig_path, sizeof(orig_path), 1); state_fio->Fread(dest_path, sizeof(dest_path), 1); @@ -1613,11 +1634,16 @@ bool DISK::load_state(FILEIO* state_fio) is_fdi_image = state_fio->FgetBool(); is_special_disk = state_fio->FgetInt32(); state_fio->Fread(track, sizeof(track), 1); - sector_num.sd = state_fio->FgetInt32(); - invalid_format = state_fio->FgetBool(); - no_skew = state_fio->FgetBool(); - state_fio->Fread(sync_position, sizeof(sync_position), 1); - state_fio->Fread(id_position, sizeof(id_position), 1); + sector_num.sd = state_fio->FgetInt32(); + invalid_format = state_fio->FgetBool(); + no_skew = state_fio->FgetBool(); + if(state_version >= 5) { + track_mfm = state_fio->FgetBool(); + } else { + track_mfm = true; + } + state_fio->Fread(sync_position, sizeof(sync_position), 1); + state_fio->Fread(id_position, sizeof(id_position), 1); state_fio->Fread(data_position, sizeof(data_position), 1); int offset = state_fio->FgetInt32(); sector = (offset != -1) ? buffer + offset : NULL; @@ -1626,9 +1652,12 @@ bool DISK::load_state(FILEIO* state_fio) density = state_fio->FgetUint8(); deleted = state_fio->FgetBool(); crc_error = state_fio->FgetBool(); - drive_type = state_fio->FgetUint8(); - drive_rpm = state_fio->FgetInt32(); + drive_type = state_fio->FgetUint8(); + drive_rpm = state_fio->FgetInt32(); drive_mfm = state_fio->FgetBool(); + if(state_version < 5) { + track_mfm = drive_mfm; + } return true; } diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index 535a9f7..35c2d98 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -151,12 +151,13 @@ class DISK file_size.d = 0; sector_size.sd = sector_num.sd = 0; sector = NULL; - drive_type = DRIVE_TYPE_UNK; - drive_rpm = 0; - drive_mfm = true; - static int num = 0; - drive_num = num++; - } + drive_type = DRIVE_TYPE_UNK; + drive_rpm = 0; + drive_mfm = true; + track_mfm = true; + static int num = 0; + drive_num = num++; + } ~DISK() { if(inserted) { @@ -215,12 +216,13 @@ class DISK // track uint8 track[TRACK_BUFFER_SIZE]; pair sector_num; - bool invalid_format; - bool no_skew; - int cur_track, cur_side; - - int sync_position[256]; - int id_position[256]; + bool invalid_format; + bool no_skew; + int cur_track, cur_side; + bool track_mfm; + + int sync_position[256]; + int id_position[256]; int data_position[256]; // sector diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 764cef8..fd8a37f 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1400,14 +1400,15 @@ uint32 UPD765A::write_id() if((result = check_cond(true)) != 0) { return result; } - if(disk[drv]->write_protected) { - return ST0_AT | ST1_NW; - } - - disk[drv]->format_track(trk, side); - for(int i = 0; i < eot && i < 256; i++) { - for(int j = 0; j < 4; j++) { - id[j] = buffer[4 * i + j]; + if(disk[drv]->write_protected) { + return ST0_AT | ST1_NW; + } + + disk[drv]->track_mfm = ((command & 0x40) != 0); + disk[drv]->format_track(trk, side); + for(int i = 0; i < eot && i < 256; i++) { + for(int j = 0; j < 4; j++) { + id[j] = buffer[4 * i + j]; } disk[drv]->insert_sector(id[0], id[1], id[2], id[3], false, false, dtl, length); } From 994b01649cd92ab5a9fcd19b4c41012fd769e4b6 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 14:50:50 +0900 Subject: [PATCH 13/34] =?UTF-8?q?upd765a=E3=81=AE=E8=A8=BA=E6=96=AD?= =?UTF-8?q?=E8=AA=AD=E8=BE=BC=E5=88=A4=E5=AE=9A=E3=81=A8=E3=82=B5=E3=82=A4?= =?UTF-8?q?=E3=82=BA=E8=A8=88=E7=AE=97=E3=82=92common=E4=BA=92=E6=8F=9B?= =?UTF-8?q?=E3=81=B8=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 72 ++++++++++++++++---------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index fd8a37f..1f01036 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -805,11 +805,11 @@ void UPD765A::cmd_read_data() #endif // SDL read_data((command & 0x1f) == 12, false); break; - case PHASE_READ: - if(result) { - shift_to_result7(); - break; - } + case PHASE_READ: + if(result) { + shift_to_result7(); + break; + } if(!id_incr()) { REGISTER_PHASE_EVENT(PHASE_TIMER, 2000); break; @@ -820,13 +820,13 @@ void UPD765A::cmd_read_data() CANCEL_EVENT(); shift_to_result7(); break; - case PHASE_TIMER: -// result = ST0_AT | ST1_EN; - result = ST1_EN; - shift_to_result7(); - break; - } -} + case PHASE_TIMER: +// result = ST0_AT | ST1_EN; + result = ST1_EN; + shift_to_result7(); + break; + } +} void UPD765A::cmd_write_data() { @@ -857,11 +857,11 @@ void UPD765A::cmd_write_data() if(result) { shift_to_result7(); } else { - int length = 0x80 << (id[3] & 7); - if(!(id[3] & 7)) { - length = __min(dtl, 0x80); - memset(buffer + length, 0, 0x80 - length); - } + int length = 0x80 << min((int)id[3], 7); + if(id[3] == 0) { + length = __min(dtl, 0x80); + memset(buffer + length, 0, 0x80 - length); + } shift_to_write(length); } break; @@ -960,11 +960,11 @@ void UPD765A::cmd_read_diagnostic() #endif // SDL read_diagnostic(); break; - case PHASE_READ: - if(result) { - shift_to_result7(); - break; - } + case PHASE_READ: + if(result & ~ST1_ND) { + shift_to_result7(); + break; + } if(!id_incr()) { REGISTER_PHASE_EVENT(PHASE_TIMER, 2000); break; @@ -975,13 +975,13 @@ void UPD765A::cmd_read_diagnostic() CANCEL_EVENT(); shift_to_result7(); break; - case PHASE_TIMER: -// result = ST0_AT | ST1_EN; - result = ST1_EN; - shift_to_result7(); - break; - } -} + case PHASE_TIMER: +// result = ST0_AT | ST1_EN; + result |= ST1_EN; + shift_to_result7(); + break; + } +} void UPD765A::read_data(bool deleted, bool scan) { @@ -1006,7 +1006,7 @@ void UPD765A::read_data(bool deleted, bool scan) REGISTER_PHASE_EVENT(PHASE_TIMER, 100000); return; } - int length = (id[3] & 7) ? (0x80 << (id[3] & 7)) : (__min(dtl, 0x80)); + int length = (id[3] != 0) ? (0x80 << min((int)id[3], 7)) : (__min(dtl, 0x80)); if(!scan) { shift_to_read(length); } else { @@ -1051,7 +1051,7 @@ void UPD765A::read_diagnostic() memcpy(buffer + disk[drv]->get_track_size() - disk[drv]->data_position[0], disk[drv]->track, disk[drv]->data_position[0]); fdc[drv].next_trans_position = disk[drv]->data_position[0]; - shift_to_read(0x80 << (id[3] & 7)); + shift_to_read(0x80 << min((int)id[3], 7)); return; } @@ -1638,11 +1638,11 @@ void UPD765A::open_disk(int drv, const _TCHAR* path, int bank) #ifdef _FDC_DEBUG_LOG emu->out_debug_log("FDC: Disk Changed (Drive=%d)\n", drv); #endif - if(raise_irq_when_media_changed) { - fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI; - set_irq(true); - } - } + if(raise_irq_when_media_changed) { + fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI | ST0_NR; + set_irq(true); + } + } } } From 8bb63083767c498cd56d12c2f40b4e51625327eb Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 14:52:12 +0900 Subject: [PATCH 14/34] =?UTF-8?q?upd765a:=20INDEX=E4=BF=A1=E5=8F=B7?= =?UTF-8?q?=E5=B9=85=E3=81=A8=E7=8F=BE=E5=9C=A8=E4=BD=8D=E7=BD=AE=E8=A8=88?= =?UTF-8?q?=E7=AE=97=E3=82=92=E6=9C=80=E6=96=B0=E5=AE=9F=E8=A3=85=E5=AF=84?= =?UTF-8?q?=E3=82=8A=E3=81=AB=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 1f01036..f4be43e 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -506,13 +506,15 @@ void UPD765A::event_callback(int event_id, int err) } else if(event_id == EVENT_RESULT7) { result7_id = -1; shift_to_result7_event(); - } else if(event_id == EVENT_INDEX) { - int drv = hdu & DRIVE_MASK; - bool now_index = (disk[drv]->inserted && get_cur_position(drv) == 0); - if(prev_index != now_index) { - write_signals(&outputs_index, now_index ? 0xffffffff : 0); - prev_index = now_index; - } + } else if(event_id == EVENT_INDEX) { + int drv = hdu & DRIVE_MASK; + // index hole signal width is approximately 5ms. + bool now_index = (disk[drv]->inserted && + get_cur_position(drv) < disk[drv]->get_bytes_per_usec(5000)); + if(prev_index != now_index) { + write_signals(&outputs_index, now_index ? 0xffffffff : 0); + prev_index = now_index; + } } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) { int drv = event_id - EVENT_SEEK; seek_id[drv] = -1; @@ -1573,10 +1575,10 @@ void UPD765A::finish_transfer() // timing // ---------------------------------------------------------------------------- -int UPD765A::get_cur_position(int drv) -{ - return (int)(fdc[drv].cur_position + passed_usec(fdc[drv].prev_clock) / disk[drv]->get_usec_per_bytes(1)) % disk[drv]->get_track_size(); -} +int UPD765A::get_cur_position(int drv) +{ + return (fdc[drv].cur_position + disk[drv]->get_bytes_per_usec(passed_usec(fdc[drv].prev_clock))) % disk[drv]->get_track_size(); +} double UPD765A::get_usec_to_exec_phase() { From c843f0d8a3703ca6b47b8c52dbd98cdea36bac4c Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 14:55:01 +0900 Subject: [PATCH 15/34] =?UTF-8?q?upd1990a:=20STB=E3=83=A9=E3=83=83?= =?UTF-8?q?=E3=83=81=E5=88=A4=E5=AE=9A=E3=82=92CLK=E9=9D=9E=E4=BE=9D?= =?UTF-8?q?=E5=AD=98=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd1990a.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd1990a.cpp b/Source/ePC-8801MA/vm/upd1990a.cpp index 62bfd84..84b2587 100644 --- a/Source/ePC-8801MA/vm/upd1990a.cpp +++ b/Source/ePC-8801MA/vm/upd1990a.cpp @@ -59,9 +59,10 @@ void UPD1990A::write_signal(int id, uint32 data, uint32 mask) #endif } clk = next; - } else if(id == SIG_UPD1990A_STB) { - bool next = ((data & mask) != 0); - if(!stb && next && !clk) { + } else if(id == SIG_UPD1990A_STB) { + bool next = ((data & mask) != 0); + // Accept strobe on rising edge regardless of current CLK level. + if(!stb && next) { #ifdef HAS_UPD4990A if(cmd == 7) { mode = shift_cmd | 0x80; From d82dffdeb19f7af1e7fdee0f2c5546d624da735b Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 14:56:27 +0900 Subject: [PATCH 16/34] =?UTF-8?q?upd1990a:=20RTC=E3=83=87=E3=83=90?= =?UTF-8?q?=E3=82=A4=E3=82=B9=E5=90=8D=E3=82=92=E6=98=8E=E7=A4=BA=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd1990a.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd1990a.h b/Source/ePC-8801MA/vm/upd1990a.h index 651b36c..1bba2b8 100644 --- a/Source/ePC-8801MA/vm/upd1990a.h +++ b/Source/ePC-8801MA/vm/upd1990a.h @@ -54,10 +54,13 @@ class UPD1990A : public DEVICE hold = false; dout = 0; dout_changed = false; -#ifdef HAS_UPD4990A - shift_cmd = 0; -#endif - } +#ifdef HAS_UPD4990A + shift_cmd = 0; + set_device_name(_T("uPD4990A RTC")); +#else + set_device_name(_T("uPD1990A RTC")); +#endif + } ~UPD1990A() {} // common functions From 684a5ab45c83282b5660127bf6d7a5bffe34f8f7 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 14:57:19 +0900 Subject: [PATCH 17/34] =?UTF-8?q?i8251:=20=E3=83=AA=E3=82=BB=E3=83=83?= =?UTF-8?q?=E3=83=88=E6=99=82=E3=81=AETXEN=E5=88=9D=E6=9C=9F=E5=80=A4?= =?UTF-8?q?=E3=82=92=E6=9C=80=E6=96=B0=E6=8C=99=E5=8B=95=E3=81=AB=E5=90=88?= =?UTF-8?q?=E3=82=8F=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/i8251.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Source/ePC-8801MA/vm/i8251.cpp b/Source/ePC-8801MA/vm/i8251.cpp index fb6eb7f..cf5e57d 100644 --- a/Source/ePC-8801MA/vm/i8251.cpp +++ b/Source/ePC-8801MA/vm/i8251.cpp @@ -60,10 +60,12 @@ void I8251::reset() #else recv = 0xff; #endif // SDL - // dont reset dsr - status &= DSR; - status |= TXRDY | TXE; - txen = rxen = loopback = false; + // dont reset dsr + status &= DSR; + status |= TXRDY | TXE; + // XM8 v1.10 behavior: transmitter remains enabled after reset. + txen = true; + rxen = loopback = false; recv_buffer->clear(); send_buffer->clear(); From f863149e417bc7b85b0544c7687e1592168809b4 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 14:57:45 +0900 Subject: [PATCH 18/34] =?UTF-8?q?i8251:=20=E3=83=87=E3=83=90=E3=82=A4?= =?UTF-8?q?=E3=82=B9=E5=90=8D=E3=82=92=E6=98=8E=E7=A4=BA=E8=A8=AD=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/i8251.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/ePC-8801MA/vm/i8251.h b/Source/ePC-8801MA/vm/i8251.h index 81e48fa..7b974c3 100644 --- a/Source/ePC-8801MA/vm/i8251.h +++ b/Source/ePC-8801MA/vm/i8251.h @@ -55,6 +55,7 @@ class I8251 : public DEVICE init_output_signals(&outputs_dtr); init_output_signals(&outputs_rst); init_output_signals(&outputs_rts); + set_device_name(_T("8251 SIO")); } ~I8251() {} From 7a7d1ae7e087571fefbd623dcf7b99419d0a0bb9 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 14:58:25 +0900 Subject: [PATCH 19/34] =?UTF-8?q?i8253:=20=E3=83=87=E3=83=90=E3=82=A4?= =?UTF-8?q?=E3=82=B9=E5=90=8D=E3=82=92=E6=98=8E=E7=A4=BA=E8=A8=AD=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/i8253.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/ePC-8801MA/vm/i8253.h b/Source/ePC-8801MA/vm/i8253.h index cebf57b..5dd0473 100644 --- a/Source/ePC-8801MA/vm/i8253.h +++ b/Source/ePC-8801MA/vm/i8253.h @@ -75,6 +75,7 @@ class I8253 : public DEVICE counter[i].freq = 0; } device_model = INTEL_8253; + set_device_name(_T("8253 PIT")); } ~I8253() {} From 93312be43366981aea1f306881a9618e1838cc0c Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 14:59:03 +0900 Subject: [PATCH 20/34] =?UTF-8?q?i8255:=20=E3=83=87=E3=83=90=E3=82=A4?= =?UTF-8?q?=E3=82=B9=E5=90=8D=E3=82=92=E6=98=8E=E7=A4=BA=E8=A8=AD=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/i8255.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/ePC-8801MA/vm/i8255.h b/Source/ePC-8801MA/vm/i8255.h index c5e4630..4950aa0 100644 --- a/Source/ePC-8801MA/vm/i8255.h +++ b/Source/ePC-8801MA/vm/i8255.h @@ -34,12 +34,13 @@ class I8255 : public DEVICE public: I8255(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) { - for(int i = 0; i < 3; i++) { - init_output_signals(&port[i].outputs); - port[i].wreg = port[i].rreg = 0;//0xff; - } - clear_ports_by_cmdreg = false; - } + for(int i = 0; i < 3; i++) { + init_output_signals(&port[i].outputs); + port[i].wreg = port[i].rreg = 0;//0xff; + } + clear_ports_by_cmdreg = false; + set_device_name(_T("8255 PIO")); + } ~I8255() {} // common functions From 2039c44303c474189679a393b3a524d5c2a52ebd Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:28:13 +0900 Subject: [PATCH 21/34] =?UTF-8?q?i8251:=20BREAK=E5=87=BA=E5=8A=9B=E7=B5=8C?= =?UTF-8?q?=E8=B7=AF=E3=81=A8=E5=88=B6=E5=BE=A1=E3=83=93=E3=83=83=E3=83=88?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E3=82=92common=E4=BA=92=E6=8F=9B=E3=81=AB?= =?UTF-8?q?=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/i8251.cpp | 148 ++++++++++++++++----------------- Source/ePC-8801MA/vm/i8251.h | 19 +++-- 2 files changed, 81 insertions(+), 86 deletions(-) diff --git a/Source/ePC-8801MA/vm/i8251.cpp b/Source/ePC-8801MA/vm/i8251.cpp index cf5e57d..b4f9ea7 100644 --- a/Source/ePC-8801MA/vm/i8251.cpp +++ b/Source/ePC-8801MA/vm/i8251.cpp @@ -51,15 +51,11 @@ void I8251::release() delete send_buffer; } -void I8251::reset() -{ - mode = MODE_CLEAR; -#ifdef SDL - // version 1.10 - recv = 0x00; -#else - recv = 0xff; -#endif // SDL +void I8251::reset() +{ + mode = MODE_CLEAR; + recv = 0x00; // XM8 version 1.10 +// recv = 0xff; // dont reset dsr status &= DSR; status |= TXRDY | TXE; @@ -97,22 +93,22 @@ void I8251::write_io8(uint32 addr, uint32 data) mode = MODE_CLEAR; break; } - if(data & 0x10) { - status &= ~(PE | OE | FE); - } + if(data & 0x10) { + status &= ~(PE | OE | FE); + } // dtr - write_signals(&outputs_dtr, (data & 2) ? 0xffffffff : 0); - // rst/sbrk - write_signals(&outputs_rst, (data & 8) ? 0xffffffff : 0); + write_signals(&outputs_dtr, (data & 0x02) ? 0xffffffff : 0); + // break + write_signals(&outputs_brk, (data & 0x08) ? 0xffffffff : 0); // rts write_signals(&outputs_rts, (data & 0x20) ? 0xffffffff : 0); // rxen - rxen = ((data & 4) != 0); + rxen = ((data & 0x04) != 0); if(rxen && !recv_buffer->empty() && recv_id == -1) { register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id); } // txen - txen = ((data & 1) != 0); + txen = ((data & 0x01) != 0); if(txen && !send_buffer->empty() && send_id == -1) { register_event(this, EVENT_SEND, SEND_DELAY, false, &send_id); } @@ -138,17 +134,15 @@ void I8251::write_io8(uint32 addr, uint32 data) } } -uint32 I8251::read_io8(uint32 addr) -{ - if(addr & 1) { -#ifdef SDL - // version 1.10 - if (txen == false) { - return status & ~(TXRDY | TXE); - } -#endif // SDL - return status; - } else { +uint32 I8251::read_io8(uint32 addr) +{ + if(addr & 1) { + // XM8 version 1.10 + if(!txen) { + return status & ~(TXRDY | TXE); + } + return status; + } else { if(status & RXRDY) { status &= ~RXRDY; write_signals(&outputs_rxrdy, 0); @@ -192,15 +186,15 @@ void I8251::event_callback(int event_id, int err) if(rxen && !(status & RXRDY)) { if(!recv_buffer->empty()) { int val = recv_buffer->read(); - if(val == RECV_BREAK) { - // break - status |= SYNDET; - write_signals(&outputs_syndet, 0xffffffff); - } else { - recv = (uint8)val; - status |= RXRDY; - write_signals(&outputs_rxrdy, 0xffffffff); - } + if(val == RECV_BREAK) { + // break + status |= SYNDET; + write_signals(&outputs_syndet, 0xffffffff); + } else { + recv = (uint8_t)val; + status |= RXRDY; + write_signals(&outputs_rxrdy, 0xffffffff); + } } } // if data is still left in buffer, register event for next data @@ -209,9 +203,9 @@ void I8251::event_callback(int event_id, int err) } else { recv_id = -1; } - } else if(event_id == EVENT_SEND) { - if(txen && !send_buffer->empty()) { - uint8 send = send_buffer->read(); + } else if(event_id == EVENT_SEND) { + if(txen && !send_buffer->empty()) { + uint8_t send = send_buffer->read(); if(loopback) { // send to this device write_signal(SIG_I8251_RECV, send, 0xff); @@ -237,45 +231,45 @@ void I8251::event_callback(int event_id, int err) } } -#define STATE_VERSION 1 - -void I8251::save_state(FILEIO* state_fio) -{ - state_fio->FputUint32(STATE_VERSION); - state_fio->FputInt32(this_device_id); - - state_fio->FputUint8(recv); - state_fio->FputUint8(status); - state_fio->FputUint8(mode); - state_fio->FputBool(txen); - state_fio->FputBool(rxen); - state_fio->FputBool(loopback); - recv_buffer->save_state((void *)state_fio); - send_buffer->save_state((void *)state_fio); - state_fio->FputInt32(recv_id); - state_fio->FputInt32(send_id); -} - +#define STATE_VERSION 1 + +void I8251::save_state(FILEIO* state_fio) +{ + state_fio->FputUint32(STATE_VERSION); + state_fio->FputInt32(this_device_id); + + state_fio->FputUint8(recv); + state_fio->FputUint8(status); + state_fio->FputUint8(mode); + state_fio->FputBool(txen); + state_fio->FputBool(rxen); + state_fio->FputBool(loopback); + recv_buffer->save_state((void *)state_fio); + send_buffer->save_state((void *)state_fio); + state_fio->FputInt32(recv_id); + state_fio->FputInt32(send_id); +} + bool I8251::load_state(FILEIO* state_fio) { - if(state_fio->FgetUint32() != STATE_VERSION) { - return false; - } - if(state_fio->FgetInt32() != this_device_id) { - return false; - } - recv = state_fio->FgetUint8(); - status = state_fio->FgetUint8(); - mode = state_fio->FgetUint8(); - txen = state_fio->FgetBool(); - rxen = state_fio->FgetBool(); - loopback = state_fio->FgetBool(); - if(!recv_buffer->load_state((void *)state_fio)) { - return false; - } - if(!send_buffer->load_state((void *)state_fio)) { - return false; - } + if(state_fio->FgetUint32() != STATE_VERSION) { + return false; + } + if(state_fio->FgetInt32() != this_device_id) { + return false; + } + recv = state_fio->FgetUint8(); + status = state_fio->FgetUint8(); + mode = state_fio->FgetUint8(); + txen = state_fio->FgetBool(); + rxen = state_fio->FgetBool(); + loopback = state_fio->FgetBool(); + if(!recv_buffer->load_state((void *)state_fio)) { + return false; + } + if(!send_buffer->load_state((void *)state_fio)) { + return false; + } recv_id = state_fio->FgetInt32(); send_id = state_fio->FgetInt32(); return true; diff --git a/Source/ePC-8801MA/vm/i8251.h b/Source/ePC-8801MA/vm/i8251.h index 7b974c3..ee0d290 100644 --- a/Source/ePC-8801MA/vm/i8251.h +++ b/Source/ePC-8801MA/vm/i8251.h @@ -36,7 +36,7 @@ class I8251 : public DEVICE outputs_t outputs_txrdy; outputs_t outputs_txe; outputs_t outputs_dtr; - outputs_t outputs_rst; + outputs_t outputs_brk; outputs_t outputs_rts; // buffer @@ -49,11 +49,11 @@ class I8251 : public DEVICE { init_output_signals(&outputs_out); init_output_signals(&outputs_rxrdy); - init_output_signals(&outputs_syndet); + init_output_signals(&outputs_syndet); init_output_signals(&outputs_txrdy); init_output_signals(&outputs_txe); init_output_signals(&outputs_dtr); - init_output_signals(&outputs_rst); + init_output_signals(&outputs_brk); init_output_signals(&outputs_rts); set_device_name(_T("8251 SIO")); } @@ -63,8 +63,8 @@ class I8251 : public DEVICE void initialize(); void release(); void reset(); - void write_io8(uint32 addr, uint32 data); - uint32 read_io8(uint32 addr); + void write_io8(uint32 addr, uint32 data); + uint32 read_io8(uint32 addr); void write_signal(int id, uint32 data, uint32 mask); void event_callback(int event_id, int err); void save_state(FILEIO* state_fio); @@ -100,13 +100,14 @@ class I8251 : public DEVICE { register_output_signal(&outputs_dtr, device, id, mask); } - void set_context_rst(DEVICE* device, int id, uint32 mask) + void set_context_brk(DEVICE* device, int id, uint32 mask) { - register_output_signal(&outputs_rst, device, id, mask); + register_output_signal(&outputs_brk, device, id, mask); } - void set_context_brk(DEVICE* device, int id, uint32 mask) + void set_context_rst(DEVICE* device, int id, uint32 mask) { - set_context_rst(device, id, mask); + // Backward-compatible alias. + set_context_brk(device, id, mask); } void set_context_rts(DEVICE* device, int id, uint32 mask) { From e785e50c3325096dadd533664d857d132bea5363 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:31:06 +0900 Subject: [PATCH 22/34] =?UTF-8?q?upd765a:=20seek=20step/end=E3=82=A4?= =?UTF-8?q?=E3=83=99=E3=83=B3=E3=83=88=E3=82=92=E5=88=86=E9=9B=A2=E3=81=97?= =?UTF-8?q?=E3=82=B7=E3=83=BC=E3=82=AF=E3=83=8E=E3=82=A4=E3=82=BA=E6=8C=99?= =?UTF-8?q?=E5=8B=95=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 125 +++++++++++++++++++++---------- Source/ePC-8801MA/vm/upd765a.h | 3 +- 2 files changed, 89 insertions(+), 39 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 2478815..b1d2a39 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -13,12 +13,13 @@ #include "noise.h" #define EVENT_PHASE 0 -#define EVENT_DRQ 1 -#define EVENT_LOST 2 +#define EVENT_DRQ 1 +#define EVENT_LOST 2 #define EVENT_RESULT7 3 #define EVENT_INDEX 4 -#define EVENT_SEEK 5 -#define EVENT_UNLOAD 9 +#define EVENT_SEEK_STEP 5 +#define EVENT_SEEK 9 +#define EVENT_UNLOAD 13 #define PHASE_IDLE 0 #define PHASE_CMD 1 @@ -140,6 +141,11 @@ cancel_event(this, seek_id[d]); \ seek_id[d] = -1; \ } \ + if(seek_step_id[d] != -1) { \ + cancel_event(this, seek_step_id[d]); \ + seek_step_id[d] = -1; \ + } \ + seek_step_remain[d] = 0; \ if(head_unload_id[d] != -1) { \ cancel_event(this, head_unload_id[d]); \ head_unload_id[d] = -1; \ @@ -180,12 +186,14 @@ void UPD765A::initialize() memset(head_load, 0, sizeof(head_load)); memset(buffer, 0, sizeof(buffer)); - phase = prevphase = PHASE_IDLE; - status = S_RQM; - seekstat = 0; + phase = prevphase = PHASE_IDLE; + status = S_RQM; + seekstat = 0; bufptr = buffer; // temporary phase_id = drq_id = lost_id = result7_id = -1; seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; + seek_step_id[0] = seek_step_id[1] = seek_step_id[2] = seek_step_id[3] = -1; + seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; head_unload_time = 0; no_dma_mode = false; @@ -225,6 +233,8 @@ void UPD765A::reset() // CANCEL_EVENT(); phase_id = drq_id = lost_id = result7_id = -1; seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; + seek_step_id[0] = seek_step_id[1] = seek_step_id[2] = seek_step_id[3] = -1; + seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; head_load[0] = head_load[1] = head_load[2] = head_load[3] = false; @@ -515,8 +525,25 @@ void UPD765A::event_callback(int event_id, int err) write_signals(&outputs_index, now_index ? 0xffffffff : 0); prev_index = now_index; } + } else if(event_id >= EVENT_SEEK_STEP && event_id < EVENT_SEEK_STEP + 4) { + int drv = event_id - EVENT_SEEK_STEP; + if(seek_step_remain[drv] > 0) { + seek_step_remain[drv]--; + if(d_noise_seek != NULL) { + d_noise_seek->play(); + } + } + if(seek_step_remain[drv] <= 0 && seek_step_id[drv] != -1) { + cancel_event(this, seek_step_id[drv]); + seek_step_id[drv] = -1; + } } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) { int drv = event_id - EVENT_SEEK; + if(seek_step_id[drv] != -1) { + cancel_event(this, seek_step_id[drv]); + seek_step_id[drv] = -1; + } + seek_step_remain[drv] = 0; seek_id[drv] = -1; seek_event(drv); } else if(event_id >= EVENT_UNLOAD && event_id < EVENT_UNLOAD + 4) { @@ -733,38 +760,51 @@ void UPD765A::cmd_recalib() void UPD765A::seek(int drv, int trk) { // get distance - int prev_track = fdc[drv].track; - int seektime = 32 - 2 * step_rate_time; + int distance = abs(trk - fdc[drv].track); + int steptime = 16 - step_rate_time; if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { - seektime /= 2; + steptime /= 2; } - seektime = (trk == fdc[drv].track) ? 120 : seektime * abs(trk - fdc[drv].track) + 500; //usec - - if(drv >= MAX_DRIVE) { - // invalid drive number - fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; - set_irq(true); + if(steptime <= 0) { + steptime = 1; + } + int seektime = (distance == 0) ? 120 : steptime * distance + 500; // usec + + if(drv >= MAX_DRIVE) { + // invalid drive number + fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; + set_irq(true); } else { fdc[drv].track = trk; - if(prev_track != trk && d_noise_seek != NULL) { +#ifdef UPD765A_DONT_WAIT_SEEK + if(distance > 0 && d_noise_seek != NULL) { d_noise_seek->play(); } -#ifdef UPD765A_DONT_WAIT_SEEK seek_event(drv); #else - if(seek_id[drv] != -1) { - cancel_event(this, seek_id[drv]); - } -#ifdef SDL - if (config.ignore_crc) { - seektime = 100; - } -#endif // SDL - register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]); - seekstat |= 1 << drv; -#endif - } -} + if(seek_step_id[drv] != -1) { + cancel_event(this, seek_step_id[drv]); + } + if(seek_id[drv] != -1) { + cancel_event(this, seek_id[drv]); + } + seek_step_id[drv] = -1; + seek_step_remain[drv] = 0; +#ifdef SDL + if (config.ignore_crc) { + seektime = 100; + distance = 0; + } +#endif // SDL + if(distance > 0) { + seek_step_remain[drv] = distance; + register_event(this, EVENT_SEEK_STEP + drv, steptime, true, &seek_step_id[drv]); + } + register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]); + seekstat |= 1 << drv; +#endif + } +} void UPD765A::seek_event(int drv) { @@ -1757,7 +1797,7 @@ void UPD765A::set_drive_mfm(int drv, bool mfm) } } -#define STATE_VERSION 2 +#define STATE_VERSION 3 void UPD765A::save_state(FILEIO* state_fio) { @@ -1798,9 +1838,11 @@ void UPD765A::save_state(FILEIO* state_fio) state_fio->FputInt32(event_phase); state_fio->FputInt32(phase_id); state_fio->FputInt32(drq_id); - state_fio->FputInt32(lost_id); - state_fio->FputInt32(result7_id); - state_fio->Fwrite(seek_id, sizeof(seek_id), 1); + state_fio->FputInt32(lost_id); + state_fio->FputInt32(result7_id); + state_fio->Fwrite(seek_id, sizeof(seek_id), 1); + state_fio->Fwrite(seek_step_id, sizeof(seek_step_id), 1); + state_fio->Fwrite(seek_step_remain, sizeof(seek_step_remain), 1); state_fio->FputBool(force_ready); state_fio->FputBool(reset_signal); state_fio->FputBool(prev_index); @@ -1855,9 +1897,16 @@ bool UPD765A::load_state(FILEIO* state_fio) event_phase = state_fio->FgetInt32(); phase_id = state_fio->FgetInt32(); drq_id = state_fio->FgetInt32(); - lost_id = state_fio->FgetInt32(); - result7_id = state_fio->FgetInt32(); - state_fio->Fread(seek_id, sizeof(seek_id), 1); + lost_id = state_fio->FgetInt32(); + result7_id = state_fio->FgetInt32(); + state_fio->Fread(seek_id, sizeof(seek_id), 1); + if(state_version >= 3) { + state_fio->Fread(seek_step_id, sizeof(seek_step_id), 1); + state_fio->Fread(seek_step_remain, sizeof(seek_step_remain), 1); + } else { + seek_step_id[0] = seek_step_id[1] = seek_step_id[2] = seek_step_id[3] = -1; + seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; + } force_ready = state_fio->FgetBool(); reset_signal = state_fio->FgetBool(); prev_index = state_fio->FgetBool(); diff --git a/Source/ePC-8801MA/vm/upd765a.h b/Source/ePC-8801MA/vm/upd765a.h index c560152..ba804c6 100644 --- a/Source/ePC-8801MA/vm/upd765a.h +++ b/Source/ePC-8801MA/vm/upd765a.h @@ -71,7 +71,8 @@ class UPD765A : public DEVICE uint8 buffer[0x8000]; int count; int event_phase; - int phase_id, drq_id, lost_id, result7_id, seek_id[4], head_unload_id[4]; + int phase_id, drq_id, lost_id, result7_id, seek_id[4], seek_step_id[4], head_unload_id[4]; + int seek_step_remain[4]; bool force_ready; bool reset_signal; bool prev_index; From 3c47067d1a12c8518eafcb4729b4b7f03d0eb385 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:38:39 +0900 Subject: [PATCH 23/34] =?UTF-8?q?upd765a:=20seek=E3=82=B9=E3=83=86?= =?UTF-8?q?=E3=83=83=E3=83=97=E6=99=82=E9=96=93=E3=82=92=E6=97=A7=E5=AE=9F?= =?UTF-8?q?=E8=A3=85=E4=BA=92=E6=8F=9B=E3=81=AE=E8=A8=88=E7=AE=97=E5=BC=8F?= =?UTF-8?q?=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index b1d2a39..b5621de 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -761,7 +761,7 @@ void UPD765A::seek(int drv, int trk) { // get distance int distance = abs(trk - fdc[drv].track); - int steptime = 16 - step_rate_time; + int steptime = 32 - 2 * step_rate_time; if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { steptime /= 2; } From a19436c1173d9c235e84c572559c0df044d5a6d2 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:39:27 +0900 Subject: [PATCH 24/34] =?UTF-8?q?upd765a:=20get=5Fdevstat=E3=81=AEST3?= =?UTF-8?q?=E7=94=9F=E6=88=90=E3=82=92common=E4=BA=92=E6=8F=9B=E3=81=AB?= =?UTF-8?q?=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index b5621de..31fda90 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -716,20 +716,18 @@ void UPD765A::cmd_sence_intstat() // status &= ~S_CB; } -uint8 UPD765A::get_devstat(int drv) -{ - if(drv >= MAX_DRIVE) { - return 0x80 | drv; - } -#ifdef SDL - if(!disk[drv]->inserted && !force_ready) { -#else - if(!disk[drv]->inserted) { -#endif // SDL - return drv; - } - return 0x28 | drv | (fdc[drv].track ? 0 : 0x10) | ((fdc[drv].track & 1) ? 0x04 : 0) | (disk[drv]->write_protected ? 0x40 : 0); -} +uint8 UPD765A::get_devstat(int drv) +{ + if(drv >= MAX_DRIVE) { + return ST3_FT | drv; + } + return drv | + ((fdc[drv].track & 1) ? ST3_HD : 0) | + ST3_TS | + (fdc[drv].track ? 0 : ST3_T0) | + ((force_ready || disk[drv]->inserted) ? ST3_RY : 0) | + (disk[drv]->write_protected ? ST3_WP : 0); +} void UPD765A::cmd_seek() { From 3d5a4f85558f474dc58c3ca269176c80533279b8 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:41:36 +0900 Subject: [PATCH 25/34] =?UTF-8?q?upd765a:=20seek=E4=B8=AD=E3=81=AE?= =?UTF-8?q?=E7=8F=BE=E5=9C=A8=E3=83=88=E3=83=A9=E3=83=83=E3=82=AF=E8=BF=BD?= =?UTF-8?q?=E8=B7=A1=E3=82=92=E8=BF=BD=E5=8A=A0=E3=81=97ST3=E5=BF=9C?= =?UTF-8?q?=E7=AD=94=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 37 +++++++++++++++++++++++++++----- Source/ePC-8801MA/vm/upd765a.h | 5 +++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 31fda90..0e08d4c 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -183,6 +183,7 @@ void UPD765A::initialize() // initialize fdc memset(fdc, 0, sizeof(fdc)); + memset(cur_track, 0, sizeof(cur_track)); memset(head_load, 0, sizeof(head_load)); memset(buffer, 0, sizeof(buffer)); @@ -237,6 +238,10 @@ void UPD765A::reset() seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; head_load[0] = head_load[1] = head_load[2] = head_load[3] = false; + cur_track[0] = fdc[0].track; + cur_track[1] = fdc[1].track; + cur_track[2] = fdc[2].track; + cur_track[3] = fdc[3].track; set_irq(false); set_drq(false); @@ -527,13 +532,18 @@ void UPD765A::event_callback(int event_id, int err) } } else if(event_id >= EVENT_SEEK_STEP && event_id < EVENT_SEEK_STEP + 4) { int drv = event_id - EVENT_SEEK_STEP; + if(cur_track[drv] < fdc[drv].track) { + cur_track[drv]++; + } else if(cur_track[drv] > fdc[drv].track) { + cur_track[drv]--; + } if(seek_step_remain[drv] > 0) { seek_step_remain[drv]--; if(d_noise_seek != NULL) { d_noise_seek->play(); } } - if(seek_step_remain[drv] <= 0 && seek_step_id[drv] != -1) { + if((cur_track[drv] == fdc[drv].track || seek_step_remain[drv] <= 0) && seek_step_id[drv] != -1) { cancel_event(this, seek_step_id[drv]); seek_step_id[drv] = -1; } @@ -544,6 +554,7 @@ void UPD765A::event_callback(int event_id, int err) seek_step_id[drv] = -1; } seek_step_remain[drv] = 0; + cur_track[drv] = fdc[drv].track; seek_id[drv] = -1; seek_event(drv); } else if(event_id >= EVENT_UNLOAD && event_id < EVENT_UNLOAD + 4) { @@ -722,9 +733,9 @@ uint8 UPD765A::get_devstat(int drv) return ST3_FT | drv; } return drv | - ((fdc[drv].track & 1) ? ST3_HD : 0) | + ((cur_track[drv] & 1) ? ST3_HD : 0) | ST3_TS | - (fdc[drv].track ? 0 : ST3_T0) | + (cur_track[drv] ? 0 : ST3_T0) | ((force_ready || disk[drv]->inserted) ? ST3_RY : 0) | (disk[drv]->write_protected ? ST3_WP : 0); } @@ -758,7 +769,7 @@ void UPD765A::cmd_recalib() void UPD765A::seek(int drv, int trk) { // get distance - int distance = abs(trk - fdc[drv].track); + int distance = abs(trk - cur_track[drv]); int steptime = 32 - 2 * step_rate_time; if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { steptime /= 2; @@ -778,6 +789,7 @@ void UPD765A::seek(int drv, int trk) if(distance > 0 && d_noise_seek != NULL) { d_noise_seek->play(); } + cur_track[drv] = fdc[drv].track; seek_event(drv); #else if(seek_step_id[drv] != -1) { @@ -797,6 +809,8 @@ void UPD765A::seek(int drv, int trk) if(distance > 0) { seek_step_remain[drv] = distance; register_event(this, EVENT_SEEK_STEP + drv, steptime, true, &seek_step_id[drv]); + } else { + cur_track[drv] = fdc[drv].track; } register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]); seekstat |= 1 << drv; @@ -1795,7 +1809,7 @@ void UPD765A::set_drive_mfm(int drv, bool mfm) } } -#define STATE_VERSION 3 +#define STATE_VERSION 4 void UPD765A::save_state(FILEIO* state_fio) { @@ -1841,6 +1855,7 @@ void UPD765A::save_state(FILEIO* state_fio) state_fio->Fwrite(seek_id, sizeof(seek_id), 1); state_fio->Fwrite(seek_step_id, sizeof(seek_step_id), 1); state_fio->Fwrite(seek_step_remain, sizeof(seek_step_remain), 1); + state_fio->Fwrite(cur_track, sizeof(cur_track), 1); state_fio->FputBool(force_ready); state_fio->FputBool(reset_signal); state_fio->FputBool(prev_index); @@ -1901,9 +1916,21 @@ bool UPD765A::load_state(FILEIO* state_fio) if(state_version >= 3) { state_fio->Fread(seek_step_id, sizeof(seek_step_id), 1); state_fio->Fread(seek_step_remain, sizeof(seek_step_remain), 1); + if(state_version >= 4) { + state_fio->Fread(cur_track, sizeof(cur_track), 1); + } else { + cur_track[0] = fdc[0].track; + cur_track[1] = fdc[1].track; + cur_track[2] = fdc[2].track; + cur_track[3] = fdc[3].track; + } } else { seek_step_id[0] = seek_step_id[1] = seek_step_id[2] = seek_step_id[3] = -1; seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; + cur_track[0] = fdc[0].track; + cur_track[1] = fdc[1].track; + cur_track[2] = fdc[2].track; + cur_track[3] = fdc[3].track; } force_ready = state_fio->FgetBool(); reset_signal = state_fio->FgetBool(); diff --git a/Source/ePC-8801MA/vm/upd765a.h b/Source/ePC-8801MA/vm/upd765a.h index ba804c6..de8e2f1 100644 --- a/Source/ePC-8801MA/vm/upd765a.h +++ b/Source/ePC-8801MA/vm/upd765a.h @@ -46,11 +46,12 @@ class UPD765A : public DEVICE uint8 track; uint8 result; bool access; - // timing - int cur_position; + // timing + int cur_position; int next_trans_position; uint32 prev_clock; } fdc[4]; + uint8 cur_track[4]; bool head_load[4]; DISK* disk[4]; From b25239aa8e9181174e2d4ee5985944cfe516d705 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:48:59 +0900 Subject: [PATCH 26/34] =?UTF-8?q?i8253:=20i8254=20read-back=E7=8A=B6?= =?UTF-8?q?=E6=85=8B=E3=82=92=E5=B8=B8=E6=99=82=E4=BF=9D=E6=8C=81=E3=81=97?= =?UTF-8?q?=E3=82=B9=E3=83=86=E3=83=BC=E3=83=88=E4=BA=92=E6=8F=9B=E3=82=92?= =?UTF-8?q?=E6=8B=A1=E5=BC=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/i8253.cpp | 138 +++++++++++++++------------------ Source/ePC-8801MA/vm/i8253.h | 22 +++--- 2 files changed, 73 insertions(+), 87 deletions(-) diff --git a/Source/ePC-8801MA/vm/i8253.cpp b/Source/ePC-8801MA/vm/i8253.cpp index 2bb943c..1ebc4f7 100644 --- a/Source/ePC-8801MA/vm/i8253.cpp +++ b/Source/ePC-8801MA/vm/i8253.cpp @@ -21,16 +21,14 @@ void I8253::initialize() counter[ch].mode = 3; counter[ch].count_latched = false; counter[ch].low_read = counter[ch].high_read = false; - counter[ch].low_write = counter[ch].high_write = false; - counter[ch].delay = false; - counter[ch].start = false; -#ifdef HAS_I8254 - // 8254 read-back command - counter[ch].null_count = true; - counter[ch].status_latched = false; -#endif - } -} + counter[ch].low_write = counter[ch].high_write = false; + counter[ch].delay = false; + counter[ch].start = false; + // 8254 read-back command + counter[ch].null_count = true; + counter[ch].status_latched = false; + } +} void I8253::reset() { @@ -69,10 +67,8 @@ void I8253::write_io8(uint32 addr, uint32 data) } counter[ch].high_write = false; } -#ifdef HAS_I8254 - counter[ch].null_count = true; -#endif - // set signal + counter[ch].null_count = true; + // set signal if(counter[ch].mode == 0) { set_signal(ch, false); } else { @@ -93,13 +89,11 @@ void I8253::write_io8(uint32 addr, uint32 data) } break; - case 3: // ctrl reg - if((data & 0xc0) == 0xc0) { -#ifdef HAS_I8254 + case 3: // ctrl reg + if((data & 0xc0) == 0xc0) { // i8254 read-back command if(device_model == INTEL_8254) { for(ch = 0; ch < 3; ch++) { - uint8 bit = 2 << ch; if(!(data & 0x10) && !counter[ch].status_latched) { counter[ch].status = counter[ch].ctrl_reg & 0x3f; if(counter[ch].prev_out) { @@ -115,9 +109,8 @@ void I8253::write_io8(uint32 addr, uint32 data) } } } -#endif - break; - } + break; + } ch = (data >> 6) & 3; if(data & 0x30) { @@ -139,12 +132,10 @@ void I8253::write_io8(uint32 addr, uint32 data) stop_count(ch); counter[ch].count_reg = 0; // } -#ifdef HAS_I8254 - counter[ch].null_count = true; -#endif - } else if(!counter[ch].count_latched) { - latch_count(ch); - } + counter[ch].null_count = true; + } else if(!counter[ch].count_latched) { + latch_count(ch); + } break; } } @@ -153,19 +144,17 @@ uint32 I8253::read_io8(uint32 addr) { int ch = addr & 3; - switch(ch) { - case 0: - case 1: - case 2: -#ifdef HAS_I8254 + switch(ch) { + case 0: + case 1: + case 2: if(device_model == INTEL_8254) { if(counter[ch].status_latched) { counter[ch].status_latched = false; return counter[ch].status; } } -#endif - // if not latched, through current count + // if not latched, through current count if(!counter[ch].count_latched) { if(!counter[ch].low_read && !counter[ch].high_read) { latch_count(ch); @@ -242,14 +231,12 @@ void I8253::input_clock(int ch, int clock) if(!(counter[ch].start && clock)) { return; } - if(counter[ch].delay) { - clock -= 1; - counter[ch].delay = false; - counter[ch].count = COUNT_VALUE(ch); -#ifdef HAS_I8254 - counter[ch].null_count = false; -#endif - } + if(counter[ch].delay) { + clock -= 1; + counter[ch].delay = false; + counter[ch].count = COUNT_VALUE(ch); + counter[ch].null_count = false; + } // update counter counter[ch].count -= clock; @@ -268,14 +255,12 @@ void I8253::input_clock(int ch, int clock) set_signal(ch, true); } } - if(counter[ch].count <= 0) { - if(counter[ch].mode == 0 || counter[ch].mode == 2 || counter[ch].mode == 3) { - counter[ch].count += tmp; -#ifdef HAS_I8254 - counter[ch].null_count = false; -#endif - goto loop; - } else { + if(counter[ch].count <= 0) { + if(counter[ch].mode == 0 || counter[ch].mode == 2 || counter[ch].mode == 3) { + counter[ch].count += tmp; + counter[ch].null_count = false; + goto loop; + } else { counter[ch].start = false; counter[ch].count = 0x10000; } @@ -410,7 +395,7 @@ int I8253::get_next_count(int ch) return counter[ch].count; } -#define STATE_VERSION 1 +#define STATE_VERSION 2 void I8253::save_state(FILEIO* state_fio) { @@ -429,16 +414,14 @@ void I8253::save_state(FILEIO* state_fio) state_fio->FputBool(counter[i].low_read); state_fio->FputBool(counter[i].high_read); state_fio->FputBool(counter[i].low_write); - state_fio->FputBool(counter[i].high_write); - state_fio->FputInt32(counter[i].mode); - state_fio->FputBool(counter[i].delay); - state_fio->FputBool(counter[i].start); -#ifdef HAS_I8254 - state_fio->FputBool(counter[i].null_count); - state_fio->FputBool(counter[i].status_latched); - state_fio->FputUint8(counter[i].status); -#endif - state_fio->FputUint64(counter[i].freq); + state_fio->FputBool(counter[i].high_write); + state_fio->FputInt32(counter[i].mode); + state_fio->FputBool(counter[i].delay); + state_fio->FputBool(counter[i].start); + state_fio->FputBool(counter[i].null_count); + state_fio->FputBool(counter[i].status_latched); + state_fio->FputUint8(counter[i].status); + state_fio->FputUint64(counter[i].freq); state_fio->FputInt32(counter[i].register_id); state_fio->FputUint32(counter[i].input_clk); state_fio->FputInt32(counter[i].period); @@ -449,10 +432,11 @@ void I8253::save_state(FILEIO* state_fio) bool I8253::load_state(FILEIO* state_fio) { - if(state_fio->FgetUint32() != STATE_VERSION) { - return false; - } - if(state_fio->FgetInt32() != this_device_id) { + uint32 state_version = state_fio->FgetUint32(); + if(state_version < 1 || state_version > STATE_VERSION) { + return false; + } + if(state_fio->FgetInt32() != this_device_id) { return false; } for(int i = 0; i < 3; i++) { @@ -467,16 +451,20 @@ bool I8253::load_state(FILEIO* state_fio) counter[i].low_read = state_fio->FgetBool(); counter[i].high_read = state_fio->FgetBool(); counter[i].low_write = state_fio->FgetBool(); - counter[i].high_write = state_fio->FgetBool(); - counter[i].mode = state_fio->FgetInt32(); - counter[i].delay = state_fio->FgetBool(); - counter[i].start = state_fio->FgetBool(); -#ifdef HAS_I8254 - counter[i].null_count = state_fio->FgetBool(); - counter[i].status_latched = state_fio->FgetBool(); - counter[i].status = state_fio->FgetUint8(); -#endif - counter[i].freq = state_fio->FgetUint64(); + counter[i].high_write = state_fio->FgetBool(); + counter[i].mode = state_fio->FgetInt32(); + counter[i].delay = state_fio->FgetBool(); + counter[i].start = state_fio->FgetBool(); + if(state_version >= 2) { + counter[i].null_count = state_fio->FgetBool(); + counter[i].status_latched = state_fio->FgetBool(); + counter[i].status = state_fio->FgetUint8(); + } else { + counter[i].null_count = true; + counter[i].status_latched = false; + counter[i].status = 0; + } + counter[i].freq = state_fio->FgetUint64(); counter[i].register_id = state_fio->FgetInt32(); counter[i].input_clk = state_fio->FgetUint32(); counter[i].period = state_fio->FgetInt32(); diff --git a/Source/ePC-8801MA/vm/i8253.h b/Source/ePC-8801MA/vm/i8253.h index 5dd0473..0a0209c 100644 --- a/Source/ePC-8801MA/vm/i8253.h +++ b/Source/ePC-8801MA/vm/i8253.h @@ -38,18 +38,16 @@ class I8253 : public DEVICE uint16 count_reg; uint8 ctrl_reg; bool count_latched; - bool low_read, high_read; - bool low_write, high_write; - int mode; - bool delay; - bool start; -#ifdef HAS_I8254 - bool null_count; - bool status_latched; - uint8 status; -#endif - // constant clock - uint64 freq; + bool low_read, high_read; + bool low_write, high_write; + int mode; + bool delay; + bool start; + bool null_count; + bool status_latched; + uint8 status; + // constant clock + uint64 freq; int register_id; uint32 input_clk; int period; From 658d84f7db58a110cdf8cc9056bee9c1cb4f7c50 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:51:02 +0900 Subject: [PATCH 27/34] =?UTF-8?q?upd1990a:=201=E7=A7=92=E3=82=A4=E3=83=99?= =?UTF-8?q?=E3=83=B3=E3=83=88=E5=91=A8=E6=9C=9F=E3=82=92=E5=85=B1=E9=80=9A?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=E4=BA=92=E6=8F=9B=E3=81=AB=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd1990a.cpp | 83 ++++++++++++------------------- Source/ePC-8801MA/vm/upd1990a.h | 9 ++-- 2 files changed, 37 insertions(+), 55 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd1990a.cpp b/Source/ePC-8801MA/vm/upd1990a.cpp index 84b2587..f4d777d 100644 --- a/Source/ePC-8801MA/vm/upd1990a.cpp +++ b/Source/ePC-8801MA/vm/upd1990a.cpp @@ -12,20 +12,15 @@ #define EVENT_1SEC 0 #define EVENT_TP 1 -void UPD1990A::initialize() -{ - // initialize rtc - emu->get_host_time(&cur_time); - - // register events -#ifdef SDL - register_event(this, EVENT_1SEC, 100000.0, true, ®ister_id_1sec); - event_count = 0; -#else - register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); -#endif // SDL - register_id_tp = -1; -} +void UPD1990A::initialize() +{ + // initialize rtc + emu->get_host_time(&cur_time); + + // register events + register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); + register_id_tp = -1; +} void UPD1990A::write_signal(int id, uint32 data, uint32 mask) { @@ -161,21 +156,17 @@ void UPD1990A::write_signal(int id, uint32 data, uint32 mask) } // reset counter hold switch(mode & 0x0f) { - case 0x00: - case 0x01: - case 0x03: - if(hold) { - // restart event - cancel_event(this, register_id_1sec); -#ifdef SDL - register_event(this, EVENT_1SEC, 100000.0, true, ®ister_id_1sec); -#else - register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); -#endif // SDL - hold = false; - } - break; - } + case 0x00: + case 0x01: + case 0x03: + if(hold) { + // restart event + cancel_event(this, register_id_1sec); + register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); + hold = false; + } + break; + } } stb = next; } else if(id == SIG_UPD1990A_CMD) { @@ -195,21 +186,13 @@ void UPD1990A::write_signal(int id, uint32 data, uint32 mask) } } -void UPD1990A::event_callback(int event_id, int err) -{ - if(event_id == EVENT_1SEC) { -#ifdef SDL - event_count++; - if (event_count < 10) { - return; - } - event_count = 0; -#endif // SDL - - if(cur_time.initialized) { - if(!hold) { - cur_time.increment(); - } +void UPD1990A::event_callback(int event_id, int err) +{ + if(event_id == EVENT_1SEC) { + if(cur_time.initialized) { + if(!hold) { + cur_time.increment(); + } if(dout_changed) { dout_changed = false; } else { @@ -276,12 +259,12 @@ bool UPD1990A::load_state(FILEIO* state_fio) dout = state_fio->FgetUint32(); dout_changed = state_fio->FgetBool(); register_id_tp = state_fio->FgetInt32(); -#ifdef HAS_UPD4990A - shift_cmd = state_fio->FgetUint8(); -#endif - - // version 1.60 - adjust_event(register_id_1sec, 100000.0); +#ifdef HAS_UPD4990A + shift_cmd = state_fio->FgetUint8(); +#endif + + // version 1.60 + adjust_event(register_id_1sec, 1000000.0); return true; } diff --git a/Source/ePC-8801MA/vm/upd1990a.h b/Source/ePC-8801MA/vm/upd1990a.h index 1bba2b8..c5276f7 100644 --- a/Source/ePC-8801MA/vm/upd1990a.h +++ b/Source/ePC-8801MA/vm/upd1990a.h @@ -83,11 +83,10 @@ class UPD1990A : public DEVICE { register_output_signal(&outputs_tp, device, id, mask); } -#ifdef SDL - void resync(void) { cur_time.initialized = false; } - uint32 event_count; -#endif // SDL -}; +#ifdef SDL + void resync(void) { cur_time.initialized = false; } +#endif // SDL +}; #endif From de1aca7f537fda20b2d2ad651f00646468def6ee Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:56:55 +0900 Subject: [PATCH 28/34] =?UTF-8?q?event/device:=20common=E4=BA=92=E6=8F=9B?= =?UTF-8?q?=E3=82=A4=E3=83=99=E3=83=B3=E3=83=88API=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=81=97=E7=A7=BB=E6=A4=8D=E5=8F=97=E3=81=91=E7=9A=BF?= =?UTF-8?q?=E3=82=92=E6=8B=A1=E5=BC=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/device.h | 76 ++++++++++++-- Source/ePC-8801MA/vm/event.cpp | 177 ++++++++++++++++++++++++--------- Source/ePC-8801MA/vm/event.h | 145 ++++++++++++++++++--------- 3 files changed, 291 insertions(+), 107 deletions(-) diff --git a/Source/ePC-8801MA/vm/device.h b/Source/ePC-8801MA/vm/device.h index 98faee9..2d5cc7a 100644 --- a/Source/ePC-8801MA/vm/device.h +++ b/Source/ePC-8801MA/vm/device.h @@ -624,16 +624,72 @@ class DEVICE } event_manager->set_frames_per_sec(frames); } - virtual void set_lines_per_frame(int lines) - { - if(event_manager == NULL) { - event_manager = vm->first_device->next_device; - } - event_manager->set_lines_per_frame(lines); - } -#ifdef SDL - virtual void abort_main_cpu() - { + virtual void set_lines_per_frame(int lines) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + event_manager->set_lines_per_frame(lines); + } + virtual int get_lines_per_frame() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_lines_per_frame(); + } + virtual void update_event_in_op(int clock) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + event_manager->update_event_in_op(clock); + } + virtual uint32 get_event_remaining_clock(int register_id) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_event_remaining_clock(register_id); + } + virtual double get_event_remaining_usec(int register_id) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_event_remaining_usec(register_id); + } + virtual uint32 get_passed_clock_since_vline() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_passed_clock_since_vline(); + } + virtual double get_passed_usec_since_vline() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_passed_usec_since_vline(); + } + virtual int get_cur_vline() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_cur_vline(); + } + virtual int get_cur_vline_clocks() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_cur_vline_clocks(); + } +#ifdef SDL + virtual void abort_main_cpu() + { if(event_manager == NULL) { event_manager = vm->first_device->next_device; } diff --git a/Source/ePC-8801MA/vm/event.cpp b/Source/ePC-8801MA/vm/event.cpp index 547551a..d4c91ee 100644 --- a/Source/ePC-8801MA/vm/event.cpp +++ b/Source/ePC-8801MA/vm/event.cpp @@ -107,12 +107,14 @@ void EVENT::reset() single_exec_clock = 0; #endif // SDL - event_remain = 0; - cpu_remain = cpu_accum = cpu_done = 0; - - // reset sound - if(sound_buffer) { - memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2); + event_remain = 0; + cpu_remain = cpu_accum = cpu_done = 0; + cur_vline = 0; + vline_start_clock = current_clock(); + + // reset sound + if(sound_buffer) { + memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2); } if(sound_tmp) { memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32) * 2); @@ -192,16 +194,19 @@ void EVENT::drive() for(int i = 0; i < frame_event_count; i++) { frame_event[i]->event_frame(); } -#ifdef SDL - for(int v = 0; v < lines_per_frame;) { - int exec_lines; - int min_event_clock; - int main_cpu_exec; - int sub_cpu_exec; - int sub_cpu_done; - - // get execute lines from PC88::event_vline() - exec_lines = vline_event[0]->event_vline(v); +#ifdef SDL + for(int v = 0; v < lines_per_frame;) { + int exec_lines; + int min_event_clock; + int main_cpu_exec; + int sub_cpu_exec; + int sub_cpu_done; + + cur_vline = v; + vline_start_clock = current_clock(); + + // get execute lines from PC88::event_vline() + exec_lines = vline_event[0]->event_vline(v); if (exec_lines == 1) { // V-DISP @@ -304,12 +309,15 @@ void EVENT::drive() // mix sound at the end of frame mix_sound_block(); -#else - for(int v = 0; v < lines_per_frame; v++) { - // run virtual machine per line - for(int i = 0; i < vline_event_count; i++) { - vline_event[i]->event_vline(v, vclocks[v]); - } +#else + for(int v = 0; v < lines_per_frame; v++) { + cur_vline = v; + vline_start_clock = current_clock(); + + // run virtual machine per line + for(int i = 0; i < vline_event_count; i++) { + vline_event[i]->event_vline(v, vclocks[v]); + } if(event_remain < 0) { if(-event_remain > vclocks[v]) { @@ -361,11 +369,38 @@ void EVENT::drive() } } } -#endif // SDL -} - -void EVENT::update_event(int clock) -{ +#endif // SDL +} + +void EVENT::update_event_in_op(int clock) +{ +#ifdef SDL + // SDL path updates events in drive(). Keep this as a compatibility no-op. + (void)clock; +#else + if(clock <= 0) { + return; + } + cpu_remain -= clock; + cpu_accum += clock; + int event_done = cpu_accum >> power; + cpu_accum -= event_done << power; + + if(event_done > 0) { + if(event_remain > 0) { + if(event_done > event_remain) { + update_event(event_remain); + } else { + update_event(event_done); + } + } + event_remain -= event_done; + } +#endif // SDL +} + +void EVENT::update_event(int clock) +{ #ifdef SDL event_t *event_handle; @@ -518,14 +553,24 @@ uint32 EVENT::passed_clock(uint32 prev) return (current > prev) ? current - prev : current + (0xffffffff - prev) + 1; } -double EVENT::passed_usec(uint32 prev) -{ - return 1000000.0 * passed_clock(prev) / d_cpu[0].cpu_clocks; -} - -uint32 EVENT::get_cpu_pc(int index) -{ - return d_cpu[index].device->get_pc(); +double EVENT::passed_usec(uint32 prev) +{ + return 1000000.0 * passed_clock(prev) / d_cpu[0].cpu_clocks; +} + +uint32 EVENT::get_passed_clock_since_vline() +{ + return passed_clock(vline_start_clock); +} + +double EVENT::get_passed_usec_since_vline() +{ + return passed_usec(vline_start_clock); +} + +uint32 EVENT::get_cpu_pc(int index) +{ + return d_cpu[index].device->get_pc(); } void EVENT::register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id) @@ -750,27 +795,61 @@ void EVENT::cancel_event(DEVICE* device, int register_id) } } -void EVENT::register_frame_event(DEVICE* dev) -{ - if(frame_event_count < MAX_EVENT) { - frame_event[frame_event_count++] = dev; - } else { -#ifdef _DEBUG_LOG +void EVENT::register_frame_event(DEVICE* dev) +{ + if(frame_event_count < MAX_EVENT) { + for(int i = 0; i < frame_event_count; i++) { + if(frame_event[i] == dev) { + return; + } + } + frame_event[frame_event_count++] = dev; + } else { +#ifdef _DEBUG_LOG emu->out_debug_log(_T("EVENT: too many frame events !!!\n")); #endif } } -void EVENT::register_vline_event(DEVICE* dev) -{ - if(vline_event_count < MAX_EVENT) { - vline_event[vline_event_count++] = dev; - } else { -#ifdef _DEBUG_LOG +void EVENT::register_vline_event(DEVICE* dev) +{ + if(vline_event_count < MAX_EVENT) { + for(int i = 0; i < vline_event_count; i++) { + if(vline_event[i] == dev) { + return; + } + } + vline_event[vline_event_count++] = dev; + } else { +#ifdef _DEBUG_LOG emu->out_debug_log(_T("EVENT: too many vline events !!!\n")); #endif - } -} + } +} + +uint32 EVENT::get_event_remaining_clock(int register_id) +{ + if(0 <= register_id && register_id < MAX_EVENT) { + event_t *event_handle = &event[register_id]; + if(event_handle->active) { +#ifdef SDL + if(event_handle->remain_clock > event_handle->passed_clock) { + return (event_handle->remain_clock - event_handle->passed_clock + 0x3ff) >> 10; + } +#else + if(event_handle->expired_clock > event_clocks) { + return (uint32)(event_handle->expired_clock - event_clocks); + } +#endif // SDL + } + } + return 0; +} + +double EVENT::get_event_remaining_usec(int register_id) +{ + return 1000000.0 * get_event_remaining_clock(register_id) / d_cpu[0].cpu_clocks; +} #ifdef SDL void EVENT::adjust_event(int register_id, double usec) diff --git a/Source/ePC-8801MA/vm/event.h b/Source/ePC-8801MA/vm/event.h index 80cea41..6ad6012 100644 --- a/Source/ePC-8801MA/vm/event.h +++ b/Source/ePC-8801MA/vm/event.h @@ -70,11 +70,13 @@ class EVENT : public DEVICE DEVICE* vline_event[MAX_EVENT]; int frame_event_count, vline_event_count; - double frames_per_sec, next_frames_per_sec; - int lines_per_frame, next_lines_per_frame; - - void update_event(int clock); - void insert_event(event_t *event_handle); + double frames_per_sec, next_frames_per_sec; + int lines_per_frame, next_lines_per_frame; + uint32 vline_start_clock; + int cur_vline; + + void update_event(int clock); + void insert_event(event_t *event_handle); // sound manager DEVICE* d_sound[MAX_SOUND]; @@ -110,13 +112,15 @@ class EVENT : public DEVICE event[i].index = i; event[i].next = (i + 1 < MAX_EVENT) ? &event[i + 1] : NULL; } - first_free_event = &event[0]; - first_fire_event = NULL; - - event_clocks = 0; - - // force update timing in the first frame - frames_per_sec = 0.0; + first_free_event = &event[0]; + first_fire_event = NULL; + + event_clocks = 0; + vline_start_clock = 0; + cur_vline = 0; + + // force update timing in the first frame + frames_per_sec = 0.0; lines_per_frame = 0; next_frames_per_sec = FRAMES_PER_SEC; next_lines_per_frame = LINES_PER_FRAME; @@ -140,43 +144,84 @@ class EVENT : public DEVICE bool load_state(FILEIO* state_fio); // common event functions - int event_manager_id() - { - return this_device_id; - } - void set_frames_per_sec(double new_frames_per_sec) - { - next_frames_per_sec = new_frames_per_sec; - } - void set_lines_per_frame(int new_lines_per_frame) - { - next_lines_per_frame = new_lines_per_frame; - } - void register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id); -#ifdef SDL - void register_event_by_clock(DEVICE* device, int event_id, uint32 clock, bool loop, int* register_id); -#else - void register_event_by_clock(DEVICE* device, int event_id, uint64 clock, bool loop, int* register_id); -#endif - void cancel_event(DEVICE* device, int register_id); - void register_frame_event(DEVICE* device); - void register_vline_event(DEVICE* device); - uint32 current_clock(); - uint32 passed_clock(uint32 prev); - double passed_usec(uint32 prev); - uint32 get_cpu_pc(int index); - void request_skip_frames(); + int event_manager_id() + { + return this_device_id; + } + int get_event_manager_id() + { + return event_manager_id(); + } + void set_frames_per_sec(double new_frames_per_sec) + { + next_frames_per_sec = new_frames_per_sec; + } + void set_lines_per_frame(int new_lines_per_frame) + { + next_lines_per_frame = new_lines_per_frame; + } + int get_lines_per_frame() + { + return next_lines_per_frame; + } + void update_event_in_op(int clock); + void register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id); +#ifdef SDL + void register_event_by_clock(DEVICE* device, int event_id, uint32 clock, bool loop, int* register_id); +#else + void register_event_by_clock(DEVICE* device, int event_id, uint64 clock, bool loop, int* register_id); +#endif + void cancel_event(DEVICE* device, int register_id); + void register_frame_event(DEVICE* device); + void register_vline_event(DEVICE* device); + uint32 get_event_remaining_clock(int register_id); + double get_event_remaining_usec(int register_id); + uint32 current_clock(); + uint32 get_current_clock() + { + return current_clock(); + } + uint32 passed_clock(uint32 prev); + uint32 get_passed_clock(uint32 prev) + { + return passed_clock(prev); + } + double passed_usec(uint32 prev); + double get_passed_usec(uint32 prev) + { + return passed_usec(prev); + } + uint32 get_passed_clock_since_vline(); + double get_passed_usec_since_vline(); + int get_cur_vline() + { + return cur_vline; + } + int get_cur_vline_clocks() + { + return (0 <= cur_vline && cur_vline < lines_per_frame) ? vclocks[cur_vline] : 0; + } + uint32 get_cpu_pc(int index); + void request_skip_frames(); // unique functions - double frame_rate() - { - return next_frames_per_sec; - } - void drive(); - - void initialize_sound(int rate, int samples); - uint16* create_sound(int* extra_frames); - int sound_buffer_ptr(); + double frame_rate() + { + return next_frames_per_sec; + } + double get_frame_rate() + { + return frame_rate(); + } + void drive(); + + void initialize_sound(int rate, int samples); + uint16* create_sound(int* extra_frames); + int sound_buffer_ptr(); + int get_sound_buffer_ptr() + { + return sound_buffer_ptr(); + } void set_context_cpu(DEVICE* device, uint32 clocks) { @@ -207,7 +252,11 @@ class EVENT : public DEVICE d_sound[dcount_sound++] = device; } } - bool now_skip(); + bool now_skip(); + bool is_frame_skippable() + { + return now_skip(); + } #ifdef SDL void abort_main_cpu() { d_cpu[0].device->write_signal(SIG_CPU_FIRQ, 1, 1); } void abort_sub_cpu() { d_cpu[1].device->write_signal(SIG_CPU_FIRQ, 1, 1); } From 1ca61807c978a573b2b7e00a5fe0da05f899d10d Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 15:59:39 +0900 Subject: [PATCH 29/34] =?UTF-8?q?pc8801=20VM:=20common=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E3=81=AE=E4=BA=92=E6=8F=9B=E3=83=A9=E3=83=83=E3=83=91=E3=83=BC?= =?UTF-8?q?=E3=82=92=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/pc8801/pc8801.h | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.h b/Source/ePC-8801MA/vm/pc8801/pc8801.h index 0a9c5d3..d89d985 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.h +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.h @@ -182,6 +182,10 @@ class VM void reset(); void run(); double frame_rate(); + double get_frame_rate() + { + return frame_rate(); + } #ifdef USE_DEBUGGER // debugger @@ -196,6 +200,10 @@ class VM void initialize_sound(int rate, int samples); uint16* create_sound(int* extra_frames); int sound_buffer_ptr(); + int get_sound_buffer_ptr() + { + return sound_buffer_ptr(); + } // notify key void key_down(int code, bool repeat); @@ -203,13 +211,49 @@ class VM // user interface void open_disk(int drv, _TCHAR* file_path, int bank); + void open_floppy_disk(int drv, const _TCHAR* file_path, int bank) + { + open_disk(drv, const_cast<_TCHAR*>(file_path), bank); + } void close_disk(int drv); + void close_floppy_disk(int drv) + { + close_disk(drv); + } bool disk_inserted(int drv); + bool is_floppy_disk_inserted(int drv) + { + return disk_inserted(drv); + } void play_tape(_TCHAR* file_path); + void play_tape(int drv, const _TCHAR* file_path) + { + (void)drv; + play_tape(const_cast<_TCHAR*>(file_path)); + } void rec_tape(_TCHAR* file_path); + void rec_tape(int drv, const _TCHAR* file_path) + { + (void)drv; + rec_tape(const_cast<_TCHAR*>(file_path)); + } void close_tape(); + void close_tape(int drv) + { + (void)drv; + close_tape(); + } bool tape_inserted(); + bool is_tape_inserted(int drv) + { + (void)drv; + return tape_inserted(); + } bool now_skip(); + bool is_frame_skippable() + { + return now_skip(); + } void update_config(); void save_state(FILEIO* state_fio); From 3330fcd28402e1c101bc99b4a344997d68fb779e Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 18:15:20 +0900 Subject: [PATCH 30/34] =?UTF-8?q?upd1990a:=208MHz=E6=99=82=E3=81=AERTC?= =?UTF-8?q?=E3=82=A4=E3=83=99=E3=83=B3=E3=83=88=E5=91=A8=E6=9C=9F=E3=82=92?= =?UTF-8?q?=E5=88=86=E5=89=B2=E3=81=97=E3=83=87=E3=82=A3=E3=82=B9=E3=82=AF?= =?UTF-8?q?=E8=AA=AD=E8=BE=BC=E4=B8=8D=E8=89=AF=E3=82=92=E5=9B=9E=E9=81=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd1990a.cpp | 31 +++++++++++++++++++++++++++---- Source/ePC-8801MA/vm/upd1990a.h | 1 + 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd1990a.cpp b/Source/ePC-8801MA/vm/upd1990a.cpp index f4d777d..67edd07 100644 --- a/Source/ePC-8801MA/vm/upd1990a.cpp +++ b/Source/ePC-8801MA/vm/upd1990a.cpp @@ -18,7 +18,13 @@ void UPD1990A::initialize() emu->get_host_time(&cur_time); // register events +#ifdef SDL + // Keep period under the SDL event manager's long-loop edge case at high CPU clocks. + register_event(this, EVENT_1SEC, 100000.0, true, ®ister_id_1sec); + event_count = 0; +#else register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); +#endif // SDL register_id_tp = -1; } @@ -162,12 +168,17 @@ void UPD1990A::write_signal(int id, uint32 data, uint32 mask) if(hold) { // restart event cancel_event(this, register_id_1sec); +#ifdef SDL + register_event(this, EVENT_1SEC, 100000.0, true, ®ister_id_1sec); + event_count = 0; +#else register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); +#endif // SDL hold = false; } break; } - } + } stb = next; } else if(id == SIG_UPD1990A_CMD) { cmd = (cmd & ~mask) | (data & mask); @@ -189,6 +200,13 @@ void UPD1990A::write_signal(int id, uint32 data, uint32 mask) void UPD1990A::event_callback(int event_id, int err) { if(event_id == EVENT_1SEC) { +#ifdef SDL + event_count++; + if(event_count < 10) { + return; + } + event_count = 0; +#endif // SDL if(cur_time.initialized) { if(!hold) { cur_time.increment(); @@ -264,8 +282,13 @@ bool UPD1990A::load_state(FILEIO* state_fio) #endif // version 1.60 +#ifdef SDL + adjust_event(register_id_1sec, 100000.0); + event_count = 0; +#else adjust_event(register_id_1sec, 1000000.0); - - return true; -} +#endif // SDL + + return true; +} diff --git a/Source/ePC-8801MA/vm/upd1990a.h b/Source/ePC-8801MA/vm/upd1990a.h index c5276f7..87728ca 100644 --- a/Source/ePC-8801MA/vm/upd1990a.h +++ b/Source/ePC-8801MA/vm/upd1990a.h @@ -85,6 +85,7 @@ class UPD1990A : public DEVICE } #ifdef SDL void resync(void) { cur_time.initialized = false; } + uint32 event_count; #endif // SDL }; From bc6d43f5c6ebade4ef47c2c912718d9cfd99ac9d Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 18:22:06 +0900 Subject: [PATCH 31/34] =?UTF-8?q?pc8801:=20common=E4=BA=92=E6=8F=9BAPI?= =?UTF-8?q?=E3=82=92=E6=8B=A1=E5=BC=B5=E3=81=97FDD=E7=8A=B6=E6=85=8B?= =?UTF-8?q?=E5=8F=96=E5=BE=97=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/pc8801/pc88.h | 56 ++++++++++++++++++------ Source/ePC-8801MA/vm/pc8801/pc8801.cpp | 59 +++++++++++++++++++++++--- Source/ePC-8801MA/vm/pc8801/pc8801.h | 21 +++++++-- 3 files changed, 114 insertions(+), 22 deletions(-) diff --git a/Source/ePC-8801MA/vm/pc8801/pc88.h b/Source/ePC-8801MA/vm/pc8801/pc88.h index adf6dbc..592ff82 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc88.h +++ b/Source/ePC-8801MA/vm/pc8801/pc88.h @@ -288,10 +288,26 @@ class PC88 : public DEVICE #else void event_vline(int v, int clock); #endif // SDL - uint32 intr_ack(); - void intr_ei(); - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); + uint32 intr_ack(); + void intr_ei(); + uint32 get_intr_ack() + { + return intr_ack(); + } + void notify_intr_ei() + { + intr_ei(); + } + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading) + { + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; + } // unique functions void set_context_cpu(Z80* device) @@ -347,16 +363,32 @@ class PC88 : public DEVICE d_pcg_pcm2 = device; } #endif - void key_down(int code, bool repeat); - - void play_tape(_TCHAR* file_path); + void key_down(int code, bool repeat); + bool get_caps_locked() + { + return key_caps != 0; + } + bool get_kana_locked() + { + return key_kana != 0; + } + + void play_tape(_TCHAR* file_path); void rec_tape(_TCHAR* file_path); void close_tape(); - bool tape_inserted() - { - return (cmt_play || cmt_rec); - } - bool now_skip(); + bool tape_inserted() + { + return (cmt_play || cmt_rec); + } + bool is_tape_inserted() + { + return tape_inserted(); + } + bool now_skip(); + bool is_frame_skippable() + { + return now_skip(); + } void draw_screen(); diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp index 3b77d73..2c1469e 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp @@ -333,9 +333,19 @@ void VM::key_down(int code, bool repeat) pc88->key_down(code, repeat); } -void VM::key_up(int code) -{ -} +void VM::key_up(int code) +{ +} + +bool VM::get_caps_locked() +{ + return pc88->get_caps_locked(); +} + +bool VM::get_kana_locked() +{ + return pc88->get_kana_locked(); +} // ---------------------------------------------------------------------------- // user interface @@ -351,10 +361,45 @@ void VM::close_disk(int drv) pc88fdc_sub->close_disk(drv); } -bool VM::disk_inserted(int drv) -{ - return pc88fdc_sub->disk_inserted(drv); -} +bool VM::disk_inserted(int drv) +{ + return pc88fdc_sub->disk_inserted(drv); +} + +bool VM::is_floppy_disk_connected(int drv) +{ + if(pc88fdc_sub == NULL) { + return false; + } + return (drv >= 0 && drv < 2 && pc88fdc_sub->get_disk_handler(drv) != NULL); +} + +void VM::is_floppy_disk_protected(int drv, bool value) +{ + pc88fdc_sub->is_disk_protected(drv, value); +} + +bool VM::is_floppy_disk_protected(int drv) +{ + return pc88fdc_sub->is_disk_protected(drv); +} + +uint32 VM::is_floppy_disk_accessed() +{ + if(pc88fdc_sub == NULL) { + return 0; + } + return (uint32)(pc88fdc_sub->read_signal(0) & 0x03); +} + +uint32 VM::floppy_disk_indicator_color() +{ + if(pc88fdc_sub == NULL) { + return 0; + } + return ((pc88fdc_sub->get_drive_type(0) == DRIVE_TYPE_2HD) ? 1 : 0) | + ((pc88fdc_sub->get_drive_type(1) == DRIVE_TYPE_2HD) ? 2 : 0); +} void VM::play_tape(_TCHAR* file_path) { diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.h b/Source/ePC-8801MA/vm/pc8801/pc8801.h index d89d985..abf04ee 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.h +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.h @@ -208,6 +208,8 @@ class VM // notify key void key_down(int code, bool repeat); void key_up(int code); + bool get_caps_locked(); + bool get_kana_locked(); // user interface void open_disk(int drv, _TCHAR* file_path, int bank); @@ -221,10 +223,15 @@ class VM close_disk(drv); } bool disk_inserted(int drv); + bool is_floppy_disk_connected(int drv); bool is_floppy_disk_inserted(int drv) { return disk_inserted(drv); } + void is_floppy_disk_protected(int drv, bool value); + bool is_floppy_disk_protected(int drv); + uint32 is_floppy_disk_accessed(); + uint32 floppy_disk_indicator_color(); void play_tape(_TCHAR* file_path); void play_tape(int drv, const _TCHAR* file_path) { @@ -255,9 +262,17 @@ class VM return now_skip(); } - void update_config(); - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); + void update_config(); + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading) + { + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; + } // ---------------------------------------- // for each device From 12aae3d3ebe7bb07fb482ee6b943b7bec43fb162 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 18:32:52 +0900 Subject: [PATCH 32/34] =?UTF-8?q?pc88:=20DMA=E6=9B=B8=E8=BE=BCAPI=E3=81=A8?= =?UTF-8?q?low-map=E4=BA=92=E6=8F=9B=E3=82=A8=E3=83=B3=E3=83=88=E3=83=AA?= =?UTF-8?q?=E3=82=92=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/pc8801/pc88.cpp | 42 ++++++++++++++++------------ Source/ePC-8801MA/vm/pc8801/pc88.h | 27 ++++++++++++++---- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Source/ePC-8801MA/vm/pc8801/pc88.cpp b/Source/ePC-8801MA/vm/pc8801/pc88.cpp index 2459b9d..40a65a3 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc88.cpp +++ b/Source/ePC-8801MA/vm/pc8801/pc88.cpp @@ -2474,24 +2474,30 @@ uint32 PC88::read_io8_debug(uint32 addr) return 0xff; } -uint32 PC88::read_dma_data8(uint32 addr) -{ -#if defined(_PC8001SR) - return ram[addr & 0xffff]; -#else - if((addr & 0xf000) == 0xf000 && (config.boot_mode == MODE_PC88_V1H || config.boot_mode == MODE_PC88_V2)) { - return tvram[addr & 0xfff]; - } else { - return ram[addr & 0xffff]; - } -#endif -} - -void PC88::write_dma_io8(uint32 addr, uint32 data) -{ - // to crtc - crtc.write_buffer(data); -} +uint32 PC88::read_dma_data8(uint32 addr) +{ +#if defined(_PC8001SR) + return ram[addr & 0xffff]; +#else + if((addr & 0xf000) == 0xf000 && (config.boot_mode == MODE_PC88_V1H || config.boot_mode == MODE_PC88_V2)) { + return tvram[addr & 0xfff]; + } else { + return ram[addr & 0xffff]; + } +#endif +} + +void PC88::write_dma_data8(uint32 addr, uint32 data) +{ + // DMA memory write path used by common-source compatibility code. + ram[addr & 0xffff] = (uint8)data; +} + +void PC88::write_dma_io8(uint32 addr, uint32 data) +{ + // to crtc + crtc.write_buffer(data); +} void PC88::update_timing() { diff --git a/Source/ePC-8801MA/vm/pc8801/pc88.h b/Source/ePC-8801MA/vm/pc8801/pc88.h index 592ff82..9acad4c 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc88.h +++ b/Source/ePC-8801MA/vm/pc8801/pc88.h @@ -277,8 +277,9 @@ class PC88 : public DEVICE uint32 read_io8_debug(uint32 addr); #endif - uint32 read_dma_data8(uint32 addr); - void write_dma_io8(uint32 addr, uint32 data); + uint32 read_dma_data8(uint32 addr); + void write_dma_data8(uint32 addr, uint32 data); + void write_dma_io8(uint32 addr, uint32 data); void write_signal(int id, uint32 data, uint32 mask); void event_callback(int event_id, int err); @@ -420,9 +421,25 @@ class PC88 : public DEVICE int get_tvram_wait(int pattern, bool read); int get_gvram_wait(int pattern, bool read); int get_m1_wait(int pattern, uint32 addr); - void create_pattern(int pattern, bool read); - void update_memmap(int pattern, bool read); - void insert_gvram_wait(int index, int *wait); + void create_pattern(int pattern, bool read); + void update_memmap(int pattern, bool read); + void update_low_read() + { + update_memmap(-1, true); + } + void update_low_read_sub() + { + update_memmap(-1, true); + } + void update_low_write() + { + update_memmap(-1, false); + } + void update_low_write_sub() + { + update_memmap(-1, false); + } + void insert_gvram_wait(int index, int *wait); uint32 port30_in(); void port31_out(uint8 mod); uint32 port31_in(); From ce6d87a8460166df6682519c0a8ed7310dfd73f1 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 18:33:36 +0900 Subject: [PATCH 33/34] =?UTF-8?q?pc8801:=20FDD=E3=82=B3=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=A9=E5=8F=96=E5=BE=97=E3=83=98=E3=83=AB?= =?UTF-8?q?=E3=83=91=E3=83=BC=E3=82=92=E8=BF=BD=E5=8A=A0=E3=81=97=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E7=B3=BB=E3=82=92=E5=85=B1=E9=80=9A=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/pc8801/pc8801.cpp | 98 +++++++++++++++++--------- Source/ePC-8801MA/vm/pc8801/pc8801.h | 12 ++-- 2 files changed, 74 insertions(+), 36 deletions(-) diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp index 2c1469e..1df1364 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp @@ -214,15 +214,32 @@ VM::~VM() } } -DEVICE* VM::get_device(int id) -{ - for(DEVICE* device = first_device; device; device = device->next_device) { - if(device->this_device_id == id) { - return device; - } - } - return NULL; -} +DEVICE* VM::get_device(int id) +{ + for(DEVICE* device = first_device; device; device = device->next_device) { + if(device->this_device_id == id) { + return device; + } + } + return NULL; +} + +UPD765A* VM::get_floppy_disk_controller(int drv) +{ + if(drv == 0 || drv == 1) { + return pc88fdc_sub; + } + return NULL; +} + +DISK* VM::get_floppy_disk_handler(int drv) +{ + UPD765A* controller = get_floppy_disk_controller(drv); + if(controller != NULL) { + return controller->get_disk_handler(drv & 1); + } + return NULL; +} // ---------------------------------------------------------------------------- // drive virtual machine @@ -351,54 +368,71 @@ bool VM::get_kana_locked() // user interface // ---------------------------------------------------------------------------- -void VM::open_disk(int drv, _TCHAR* file_path, int bank) -{ - pc88fdc_sub->open_disk(drv, file_path, bank); -} - -void VM::close_disk(int drv) -{ - pc88fdc_sub->close_disk(drv); -} - +void VM::open_disk(int drv, _TCHAR* file_path, int bank) +{ + UPD765A* controller = get_floppy_disk_controller(drv); + if(controller != NULL) { + controller->open_disk(drv & 1, file_path, bank); + } +} + +void VM::close_disk(int drv) +{ + UPD765A* controller = get_floppy_disk_controller(drv); + if(controller != NULL) { + controller->close_disk(drv & 1); + } +} + bool VM::disk_inserted(int drv) { - return pc88fdc_sub->disk_inserted(drv); + UPD765A* controller = get_floppy_disk_controller(drv); + if(controller != NULL) { + return controller->disk_inserted(drv & 1); + } + return false; } bool VM::is_floppy_disk_connected(int drv) { - if(pc88fdc_sub == NULL) { - return false; - } - return (drv >= 0 && drv < 2 && pc88fdc_sub->get_disk_handler(drv) != NULL); + return (get_floppy_disk_handler(drv) != NULL); } void VM::is_floppy_disk_protected(int drv, bool value) { - pc88fdc_sub->is_disk_protected(drv, value); + DISK* handler = get_floppy_disk_handler(drv); + if(handler != NULL) { + handler->write_protected = value; + } } bool VM::is_floppy_disk_protected(int drv) { - return pc88fdc_sub->is_disk_protected(drv); + DISK* handler = get_floppy_disk_handler(drv); + if(handler != NULL) { + return handler->write_protected; + } + return false; } uint32 VM::is_floppy_disk_accessed() { - if(pc88fdc_sub == NULL) { - return 0; + uint32 status = 0; + UPD765A* controller = get_floppy_disk_controller(0); + if(controller != NULL) { + status |= (uint32)(controller->read_signal(0) & 0x03); } - return (uint32)(pc88fdc_sub->read_signal(0) & 0x03); + return status; } uint32 VM::floppy_disk_indicator_color() { - if(pc88fdc_sub == NULL) { + UPD765A* controller = get_floppy_disk_controller(0); + if(controller == NULL) { return 0; } - return ((pc88fdc_sub->get_drive_type(0) == DRIVE_TYPE_2HD) ? 1 : 0) | - ((pc88fdc_sub->get_drive_type(1) == DRIVE_TYPE_2HD) ? 2 : 0); + return ((controller->get_drive_type(0) == DRIVE_TYPE_2HD) ? 1 : 0) | + ((controller->get_drive_type(1) == DRIVE_TYPE_2HD) ? 2 : 0); } void VM::play_tape(_TCHAR* file_path) diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.h b/Source/ePC-8801MA/vm/pc8801/pc8801.h index abf04ee..5a8e82c 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.h +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.h @@ -114,8 +114,9 @@ class DiskSub; #else class PC80S31K; #endif // SDL -class UPD765A; -class NOISE; +class UPD765A; +class NOISE; +class DISK; #ifdef SUPPORT_PC88_PCG8100 class I8253; @@ -164,8 +165,11 @@ class VM PC88* pc88; - int boot_mode; - + int boot_mode; + + UPD765A* get_floppy_disk_controller(int drv); + DISK* get_floppy_disk_handler(int drv); + public: // ---------------------------------------- // initialize From 08f894baca21d2eb45fad326d1b509d0df971bd7 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 18:35:31 +0900 Subject: [PATCH 34/34] =?UTF-8?q?pc8801:=20=E5=85=B1=E9=80=9AAPI=E4=B8=8D?= =?UTF-8?q?=E8=B6=B3=E5=88=86=E3=81=A8=E3=81=97=E3=81=A6=E9=9F=B3=E9=87=8F?= =?UTF-8?q?IF=E3=81=A8CD=E7=B3=BB=E3=82=B9=E3=82=BF=E3=83=96=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/pc8801/pc8801.cpp | 66 +++++++++++++++++++------- Source/ePC-8801MA/vm/pc8801/pc8801.h | 25 ++++++---- 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp index 1df1364..9e19d21 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp @@ -336,14 +336,22 @@ uint16* VM::create_sound(int* extra_frames) return pc88event->create_sound(extra_frames); } -int VM::sound_buffer_ptr() -{ - return pc88event->sound_buffer_ptr(); -} - -// ---------------------------------------------------------------------------- -// notify key -// ---------------------------------------------------------------------------- +int VM::sound_buffer_ptr() +{ + return pc88event->sound_buffer_ptr(); +} + +void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r) +{ + // XM8 SDL core does not expose per-chip volume control in common format. + (void)ch; + (void)decibel_l; + (void)decibel_r; +} + +// ---------------------------------------------------------------------------- +// notify key +// ---------------------------------------------------------------------------- void VM::key_down(int code, bool repeat) { @@ -450,16 +458,38 @@ void VM::close_tape() pc88->close_tape(); } -bool VM::tape_inserted() -{ - return pc88->tape_inserted(); -} - -bool VM::now_skip() -{ -// return event->now_skip(); - return pc88->now_skip(); -} +bool VM::tape_inserted() +{ + return pc88->tape_inserted(); +} + +void VM::open_compact_disc(int drv, const _TCHAR* file_path) +{ + (void)drv; + (void)file_path; +} + +void VM::close_compact_disc(int drv) +{ + (void)drv; +} + +bool VM::is_compact_disc_inserted(int drv) +{ + (void)drv; + return false; +} + +uint32 VM::is_compact_disc_accessed() +{ + return 0; +} + +bool VM::now_skip() +{ +// return event->now_skip(); + return pc88->now_skip(); +} void VM::update_config() { diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.h b/Source/ePC-8801MA/vm/pc8801/pc8801.h index 5a8e82c..38a98a4 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.h +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.h @@ -204,11 +204,12 @@ class VM void initialize_sound(int rate, int samples); uint16* create_sound(int* extra_frames); int sound_buffer_ptr(); - int get_sound_buffer_ptr() - { - return sound_buffer_ptr(); - } - + int get_sound_buffer_ptr() + { + return sound_buffer_ptr(); + } + void set_sound_device_volume(int ch, int decibel_l, int decibel_r); + // notify key void key_down(int code, bool repeat); void key_up(int code); @@ -255,11 +256,15 @@ class VM close_tape(); } bool tape_inserted(); - bool is_tape_inserted(int drv) - { - (void)drv; - return tape_inserted(); - } + bool is_tape_inserted(int drv) + { + (void)drv; + return tape_inserted(); + } + void open_compact_disc(int drv, const _TCHAR* file_path); + void close_compact_disc(int drv); + bool is_compact_disc_inserted(int drv); + uint32 is_compact_disc_accessed(); bool now_skip(); bool is_frame_skippable() {