From cf303a1fc84bf1ee783392ce85269deca4d70c9c Mon Sep 17 00:00:00 2001 From: bubio Date: Thu, 12 Feb 2026 23:20:05 +0900 Subject: [PATCH 01/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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/20] =?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