diff --git a/Source/ePC-8801MA/vm/device.h b/Source/ePC-8801MA/vm/device.h index 98faee9..2d5cc7a 100644 --- a/Source/ePC-8801MA/vm/device.h +++ b/Source/ePC-8801MA/vm/device.h @@ -624,16 +624,72 @@ class DEVICE } event_manager->set_frames_per_sec(frames); } - virtual void set_lines_per_frame(int lines) - { - if(event_manager == NULL) { - event_manager = vm->first_device->next_device; - } - event_manager->set_lines_per_frame(lines); - } -#ifdef SDL - virtual void abort_main_cpu() - { + virtual void set_lines_per_frame(int lines) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + event_manager->set_lines_per_frame(lines); + } + virtual int get_lines_per_frame() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_lines_per_frame(); + } + virtual void update_event_in_op(int clock) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + event_manager->update_event_in_op(clock); + } + virtual uint32 get_event_remaining_clock(int register_id) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_event_remaining_clock(register_id); + } + virtual double get_event_remaining_usec(int register_id) + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_event_remaining_usec(register_id); + } + virtual uint32 get_passed_clock_since_vline() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_passed_clock_since_vline(); + } + virtual double get_passed_usec_since_vline() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_passed_usec_since_vline(); + } + virtual int get_cur_vline() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_cur_vline(); + } + virtual int get_cur_vline_clocks() + { + if(event_manager == NULL) { + event_manager = vm->first_device->next_device; + } + return event_manager->get_cur_vline_clocks(); + } +#ifdef SDL + virtual void abort_main_cpu() + { if(event_manager == NULL) { event_manager = vm->first_device->next_device; } diff --git a/Source/ePC-8801MA/vm/event.cpp b/Source/ePC-8801MA/vm/event.cpp index 547551a..d4c91ee 100644 --- a/Source/ePC-8801MA/vm/event.cpp +++ b/Source/ePC-8801MA/vm/event.cpp @@ -107,12 +107,14 @@ void EVENT::reset() single_exec_clock = 0; #endif // SDL - event_remain = 0; - cpu_remain = cpu_accum = cpu_done = 0; - - // reset sound - if(sound_buffer) { - memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2); + event_remain = 0; + cpu_remain = cpu_accum = cpu_done = 0; + cur_vline = 0; + vline_start_clock = current_clock(); + + // reset sound + if(sound_buffer) { + memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2); } if(sound_tmp) { memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32) * 2); @@ -192,16 +194,19 @@ void EVENT::drive() for(int i = 0; i < frame_event_count; i++) { frame_event[i]->event_frame(); } -#ifdef SDL - for(int v = 0; v < lines_per_frame;) { - int exec_lines; - int min_event_clock; - int main_cpu_exec; - int sub_cpu_exec; - int sub_cpu_done; - - // get execute lines from PC88::event_vline() - exec_lines = vline_event[0]->event_vline(v); +#ifdef SDL + for(int v = 0; v < lines_per_frame;) { + int exec_lines; + int min_event_clock; + int main_cpu_exec; + int sub_cpu_exec; + int sub_cpu_done; + + cur_vline = v; + vline_start_clock = current_clock(); + + // get execute lines from PC88::event_vline() + exec_lines = vline_event[0]->event_vline(v); if (exec_lines == 1) { // V-DISP @@ -304,12 +309,15 @@ void EVENT::drive() // mix sound at the end of frame mix_sound_block(); -#else - for(int v = 0; v < lines_per_frame; v++) { - // run virtual machine per line - for(int i = 0; i < vline_event_count; i++) { - vline_event[i]->event_vline(v, vclocks[v]); - } +#else + for(int v = 0; v < lines_per_frame; v++) { + cur_vline = v; + vline_start_clock = current_clock(); + + // run virtual machine per line + for(int i = 0; i < vline_event_count; i++) { + vline_event[i]->event_vline(v, vclocks[v]); + } if(event_remain < 0) { if(-event_remain > vclocks[v]) { @@ -361,11 +369,38 @@ void EVENT::drive() } } } -#endif // SDL -} - -void EVENT::update_event(int clock) -{ +#endif // SDL +} + +void EVENT::update_event_in_op(int clock) +{ +#ifdef SDL + // SDL path updates events in drive(). Keep this as a compatibility no-op. + (void)clock; +#else + if(clock <= 0) { + return; + } + cpu_remain -= clock; + cpu_accum += clock; + int event_done = cpu_accum >> power; + cpu_accum -= event_done << power; + + if(event_done > 0) { + if(event_remain > 0) { + if(event_done > event_remain) { + update_event(event_remain); + } else { + update_event(event_done); + } + } + event_remain -= event_done; + } +#endif // SDL +} + +void EVENT::update_event(int clock) +{ #ifdef SDL event_t *event_handle; @@ -518,14 +553,24 @@ uint32 EVENT::passed_clock(uint32 prev) return (current > prev) ? current - prev : current + (0xffffffff - prev) + 1; } -double EVENT::passed_usec(uint32 prev) -{ - return 1000000.0 * passed_clock(prev) / d_cpu[0].cpu_clocks; -} - -uint32 EVENT::get_cpu_pc(int index) -{ - return d_cpu[index].device->get_pc(); +double EVENT::passed_usec(uint32 prev) +{ + return 1000000.0 * passed_clock(prev) / d_cpu[0].cpu_clocks; +} + +uint32 EVENT::get_passed_clock_since_vline() +{ + return passed_clock(vline_start_clock); +} + +double EVENT::get_passed_usec_since_vline() +{ + return passed_usec(vline_start_clock); +} + +uint32 EVENT::get_cpu_pc(int index) +{ + return d_cpu[index].device->get_pc(); } void EVENT::register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id) @@ -750,27 +795,61 @@ void EVENT::cancel_event(DEVICE* device, int register_id) } } -void EVENT::register_frame_event(DEVICE* dev) -{ - if(frame_event_count < MAX_EVENT) { - frame_event[frame_event_count++] = dev; - } else { -#ifdef _DEBUG_LOG +void EVENT::register_frame_event(DEVICE* dev) +{ + if(frame_event_count < MAX_EVENT) { + for(int i = 0; i < frame_event_count; i++) { + if(frame_event[i] == dev) { + return; + } + } + frame_event[frame_event_count++] = dev; + } else { +#ifdef _DEBUG_LOG emu->out_debug_log(_T("EVENT: too many frame events !!!\n")); #endif } } -void EVENT::register_vline_event(DEVICE* dev) -{ - if(vline_event_count < MAX_EVENT) { - vline_event[vline_event_count++] = dev; - } else { -#ifdef _DEBUG_LOG +void EVENT::register_vline_event(DEVICE* dev) +{ + if(vline_event_count < MAX_EVENT) { + for(int i = 0; i < vline_event_count; i++) { + if(vline_event[i] == dev) { + return; + } + } + vline_event[vline_event_count++] = dev; + } else { +#ifdef _DEBUG_LOG emu->out_debug_log(_T("EVENT: too many vline events !!!\n")); #endif - } -} + } +} + +uint32 EVENT::get_event_remaining_clock(int register_id) +{ + if(0 <= register_id && register_id < MAX_EVENT) { + event_t *event_handle = &event[register_id]; + if(event_handle->active) { +#ifdef SDL + if(event_handle->remain_clock > event_handle->passed_clock) { + return (event_handle->remain_clock - event_handle->passed_clock + 0x3ff) >> 10; + } +#else + if(event_handle->expired_clock > event_clocks) { + return (uint32)(event_handle->expired_clock - event_clocks); + } +#endif // SDL + } + } + return 0; +} + +double EVENT::get_event_remaining_usec(int register_id) +{ + return 1000000.0 * get_event_remaining_clock(register_id) / d_cpu[0].cpu_clocks; +} #ifdef SDL void EVENT::adjust_event(int register_id, double usec) diff --git a/Source/ePC-8801MA/vm/event.h b/Source/ePC-8801MA/vm/event.h index 80cea41..6ad6012 100644 --- a/Source/ePC-8801MA/vm/event.h +++ b/Source/ePC-8801MA/vm/event.h @@ -70,11 +70,13 @@ class EVENT : public DEVICE DEVICE* vline_event[MAX_EVENT]; int frame_event_count, vline_event_count; - double frames_per_sec, next_frames_per_sec; - int lines_per_frame, next_lines_per_frame; - - void update_event(int clock); - void insert_event(event_t *event_handle); + double frames_per_sec, next_frames_per_sec; + int lines_per_frame, next_lines_per_frame; + uint32 vline_start_clock; + int cur_vline; + + void update_event(int clock); + void insert_event(event_t *event_handle); // sound manager DEVICE* d_sound[MAX_SOUND]; @@ -110,13 +112,15 @@ class EVENT : public DEVICE event[i].index = i; event[i].next = (i + 1 < MAX_EVENT) ? &event[i + 1] : NULL; } - first_free_event = &event[0]; - first_fire_event = NULL; - - event_clocks = 0; - - // force update timing in the first frame - frames_per_sec = 0.0; + first_free_event = &event[0]; + first_fire_event = NULL; + + event_clocks = 0; + vline_start_clock = 0; + cur_vline = 0; + + // force update timing in the first frame + frames_per_sec = 0.0; lines_per_frame = 0; next_frames_per_sec = FRAMES_PER_SEC; next_lines_per_frame = LINES_PER_FRAME; @@ -140,43 +144,84 @@ class EVENT : public DEVICE bool load_state(FILEIO* state_fio); // common event functions - int event_manager_id() - { - return this_device_id; - } - void set_frames_per_sec(double new_frames_per_sec) - { - next_frames_per_sec = new_frames_per_sec; - } - void set_lines_per_frame(int new_lines_per_frame) - { - next_lines_per_frame = new_lines_per_frame; - } - void register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id); -#ifdef SDL - void register_event_by_clock(DEVICE* device, int event_id, uint32 clock, bool loop, int* register_id); -#else - void register_event_by_clock(DEVICE* device, int event_id, uint64 clock, bool loop, int* register_id); -#endif - void cancel_event(DEVICE* device, int register_id); - void register_frame_event(DEVICE* device); - void register_vline_event(DEVICE* device); - uint32 current_clock(); - uint32 passed_clock(uint32 prev); - double passed_usec(uint32 prev); - uint32 get_cpu_pc(int index); - void request_skip_frames(); + int event_manager_id() + { + return this_device_id; + } + int get_event_manager_id() + { + return event_manager_id(); + } + void set_frames_per_sec(double new_frames_per_sec) + { + next_frames_per_sec = new_frames_per_sec; + } + void set_lines_per_frame(int new_lines_per_frame) + { + next_lines_per_frame = new_lines_per_frame; + } + int get_lines_per_frame() + { + return next_lines_per_frame; + } + void update_event_in_op(int clock); + void register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id); +#ifdef SDL + void register_event_by_clock(DEVICE* device, int event_id, uint32 clock, bool loop, int* register_id); +#else + void register_event_by_clock(DEVICE* device, int event_id, uint64 clock, bool loop, int* register_id); +#endif + void cancel_event(DEVICE* device, int register_id); + void register_frame_event(DEVICE* device); + void register_vline_event(DEVICE* device); + uint32 get_event_remaining_clock(int register_id); + double get_event_remaining_usec(int register_id); + uint32 current_clock(); + uint32 get_current_clock() + { + return current_clock(); + } + uint32 passed_clock(uint32 prev); + uint32 get_passed_clock(uint32 prev) + { + return passed_clock(prev); + } + double passed_usec(uint32 prev); + double get_passed_usec(uint32 prev) + { + return passed_usec(prev); + } + uint32 get_passed_clock_since_vline(); + double get_passed_usec_since_vline(); + int get_cur_vline() + { + return cur_vline; + } + int get_cur_vline_clocks() + { + return (0 <= cur_vline && cur_vline < lines_per_frame) ? vclocks[cur_vline] : 0; + } + uint32 get_cpu_pc(int index); + void request_skip_frames(); // unique functions - double frame_rate() - { - return next_frames_per_sec; - } - void drive(); - - void initialize_sound(int rate, int samples); - uint16* create_sound(int* extra_frames); - int sound_buffer_ptr(); + double frame_rate() + { + return next_frames_per_sec; + } + double get_frame_rate() + { + return frame_rate(); + } + void drive(); + + void initialize_sound(int rate, int samples); + uint16* create_sound(int* extra_frames); + int sound_buffer_ptr(); + int get_sound_buffer_ptr() + { + return sound_buffer_ptr(); + } void set_context_cpu(DEVICE* device, uint32 clocks) { @@ -207,7 +252,11 @@ class EVENT : public DEVICE d_sound[dcount_sound++] = device; } } - bool now_skip(); + bool now_skip(); + bool is_frame_skippable() + { + return now_skip(); + } #ifdef SDL void abort_main_cpu() { d_cpu[0].device->write_signal(SIG_CPU_FIRQ, 1, 1); } void abort_sub_cpu() { d_cpu[1].device->write_signal(SIG_CPU_FIRQ, 1, 1); } diff --git a/Source/ePC-8801MA/vm/i8251.cpp b/Source/ePC-8801MA/vm/i8251.cpp index cf5e57d..b4f9ea7 100644 --- a/Source/ePC-8801MA/vm/i8251.cpp +++ b/Source/ePC-8801MA/vm/i8251.cpp @@ -51,15 +51,11 @@ void I8251::release() delete send_buffer; } -void I8251::reset() -{ - mode = MODE_CLEAR; -#ifdef SDL - // version 1.10 - recv = 0x00; -#else - recv = 0xff; -#endif // SDL +void I8251::reset() +{ + mode = MODE_CLEAR; + recv = 0x00; // XM8 version 1.10 +// recv = 0xff; // dont reset dsr status &= DSR; status |= TXRDY | TXE; @@ -97,22 +93,22 @@ void I8251::write_io8(uint32 addr, uint32 data) mode = MODE_CLEAR; break; } - if(data & 0x10) { - status &= ~(PE | OE | FE); - } + if(data & 0x10) { + status &= ~(PE | OE | FE); + } // dtr - write_signals(&outputs_dtr, (data & 2) ? 0xffffffff : 0); - // rst/sbrk - write_signals(&outputs_rst, (data & 8) ? 0xffffffff : 0); + write_signals(&outputs_dtr, (data & 0x02) ? 0xffffffff : 0); + // break + write_signals(&outputs_brk, (data & 0x08) ? 0xffffffff : 0); // rts write_signals(&outputs_rts, (data & 0x20) ? 0xffffffff : 0); // rxen - rxen = ((data & 4) != 0); + rxen = ((data & 0x04) != 0); if(rxen && !recv_buffer->empty() && recv_id == -1) { register_event(this, EVENT_RECV, RECV_DELAY, false, &recv_id); } // txen - txen = ((data & 1) != 0); + txen = ((data & 0x01) != 0); if(txen && !send_buffer->empty() && send_id == -1) { register_event(this, EVENT_SEND, SEND_DELAY, false, &send_id); } @@ -138,17 +134,15 @@ void I8251::write_io8(uint32 addr, uint32 data) } } -uint32 I8251::read_io8(uint32 addr) -{ - if(addr & 1) { -#ifdef SDL - // version 1.10 - if (txen == false) { - return status & ~(TXRDY | TXE); - } -#endif // SDL - return status; - } else { +uint32 I8251::read_io8(uint32 addr) +{ + if(addr & 1) { + // XM8 version 1.10 + if(!txen) { + return status & ~(TXRDY | TXE); + } + return status; + } else { if(status & RXRDY) { status &= ~RXRDY; write_signals(&outputs_rxrdy, 0); @@ -192,15 +186,15 @@ void I8251::event_callback(int event_id, int err) if(rxen && !(status & RXRDY)) { if(!recv_buffer->empty()) { int val = recv_buffer->read(); - if(val == RECV_BREAK) { - // break - status |= SYNDET; - write_signals(&outputs_syndet, 0xffffffff); - } else { - recv = (uint8)val; - status |= RXRDY; - write_signals(&outputs_rxrdy, 0xffffffff); - } + if(val == RECV_BREAK) { + // break + status |= SYNDET; + write_signals(&outputs_syndet, 0xffffffff); + } else { + recv = (uint8_t)val; + status |= RXRDY; + write_signals(&outputs_rxrdy, 0xffffffff); + } } } // if data is still left in buffer, register event for next data @@ -209,9 +203,9 @@ void I8251::event_callback(int event_id, int err) } else { recv_id = -1; } - } else if(event_id == EVENT_SEND) { - if(txen && !send_buffer->empty()) { - uint8 send = send_buffer->read(); + } else if(event_id == EVENT_SEND) { + if(txen && !send_buffer->empty()) { + uint8_t send = send_buffer->read(); if(loopback) { // send to this device write_signal(SIG_I8251_RECV, send, 0xff); @@ -237,45 +231,45 @@ void I8251::event_callback(int event_id, int err) } } -#define STATE_VERSION 1 - -void I8251::save_state(FILEIO* state_fio) -{ - state_fio->FputUint32(STATE_VERSION); - state_fio->FputInt32(this_device_id); - - state_fio->FputUint8(recv); - state_fio->FputUint8(status); - state_fio->FputUint8(mode); - state_fio->FputBool(txen); - state_fio->FputBool(rxen); - state_fio->FputBool(loopback); - recv_buffer->save_state((void *)state_fio); - send_buffer->save_state((void *)state_fio); - state_fio->FputInt32(recv_id); - state_fio->FputInt32(send_id); -} - +#define STATE_VERSION 1 + +void I8251::save_state(FILEIO* state_fio) +{ + state_fio->FputUint32(STATE_VERSION); + state_fio->FputInt32(this_device_id); + + state_fio->FputUint8(recv); + state_fio->FputUint8(status); + state_fio->FputUint8(mode); + state_fio->FputBool(txen); + state_fio->FputBool(rxen); + state_fio->FputBool(loopback); + recv_buffer->save_state((void *)state_fio); + send_buffer->save_state((void *)state_fio); + state_fio->FputInt32(recv_id); + state_fio->FputInt32(send_id); +} + bool I8251::load_state(FILEIO* state_fio) { - if(state_fio->FgetUint32() != STATE_VERSION) { - return false; - } - if(state_fio->FgetInt32() != this_device_id) { - return false; - } - recv = state_fio->FgetUint8(); - status = state_fio->FgetUint8(); - mode = state_fio->FgetUint8(); - txen = state_fio->FgetBool(); - rxen = state_fio->FgetBool(); - loopback = state_fio->FgetBool(); - if(!recv_buffer->load_state((void *)state_fio)) { - return false; - } - if(!send_buffer->load_state((void *)state_fio)) { - return false; - } + if(state_fio->FgetUint32() != STATE_VERSION) { + return false; + } + if(state_fio->FgetInt32() != this_device_id) { + return false; + } + recv = state_fio->FgetUint8(); + status = state_fio->FgetUint8(); + mode = state_fio->FgetUint8(); + txen = state_fio->FgetBool(); + rxen = state_fio->FgetBool(); + loopback = state_fio->FgetBool(); + if(!recv_buffer->load_state((void *)state_fio)) { + return false; + } + if(!send_buffer->load_state((void *)state_fio)) { + return false; + } recv_id = state_fio->FgetInt32(); send_id = state_fio->FgetInt32(); return true; diff --git a/Source/ePC-8801MA/vm/i8251.h b/Source/ePC-8801MA/vm/i8251.h index 7b974c3..ee0d290 100644 --- a/Source/ePC-8801MA/vm/i8251.h +++ b/Source/ePC-8801MA/vm/i8251.h @@ -36,7 +36,7 @@ class I8251 : public DEVICE outputs_t outputs_txrdy; outputs_t outputs_txe; outputs_t outputs_dtr; - outputs_t outputs_rst; + outputs_t outputs_brk; outputs_t outputs_rts; // buffer @@ -49,11 +49,11 @@ class I8251 : public DEVICE { init_output_signals(&outputs_out); init_output_signals(&outputs_rxrdy); - init_output_signals(&outputs_syndet); + init_output_signals(&outputs_syndet); init_output_signals(&outputs_txrdy); init_output_signals(&outputs_txe); init_output_signals(&outputs_dtr); - init_output_signals(&outputs_rst); + init_output_signals(&outputs_brk); init_output_signals(&outputs_rts); set_device_name(_T("8251 SIO")); } @@ -63,8 +63,8 @@ class I8251 : public DEVICE void initialize(); void release(); void reset(); - void write_io8(uint32 addr, uint32 data); - uint32 read_io8(uint32 addr); + void write_io8(uint32 addr, uint32 data); + uint32 read_io8(uint32 addr); void write_signal(int id, uint32 data, uint32 mask); void event_callback(int event_id, int err); void save_state(FILEIO* state_fio); @@ -100,13 +100,14 @@ class I8251 : public DEVICE { register_output_signal(&outputs_dtr, device, id, mask); } - void set_context_rst(DEVICE* device, int id, uint32 mask) + void set_context_brk(DEVICE* device, int id, uint32 mask) { - register_output_signal(&outputs_rst, device, id, mask); + register_output_signal(&outputs_brk, device, id, mask); } - void set_context_brk(DEVICE* device, int id, uint32 mask) + void set_context_rst(DEVICE* device, int id, uint32 mask) { - set_context_rst(device, id, mask); + // Backward-compatible alias. + set_context_brk(device, id, mask); } void set_context_rts(DEVICE* device, int id, uint32 mask) { diff --git a/Source/ePC-8801MA/vm/i8253.cpp b/Source/ePC-8801MA/vm/i8253.cpp index 2bb943c..1ebc4f7 100644 --- a/Source/ePC-8801MA/vm/i8253.cpp +++ b/Source/ePC-8801MA/vm/i8253.cpp @@ -21,16 +21,14 @@ void I8253::initialize() counter[ch].mode = 3; counter[ch].count_latched = false; counter[ch].low_read = counter[ch].high_read = false; - counter[ch].low_write = counter[ch].high_write = false; - counter[ch].delay = false; - counter[ch].start = false; -#ifdef HAS_I8254 - // 8254 read-back command - counter[ch].null_count = true; - counter[ch].status_latched = false; -#endif - } -} + counter[ch].low_write = counter[ch].high_write = false; + counter[ch].delay = false; + counter[ch].start = false; + // 8254 read-back command + counter[ch].null_count = true; + counter[ch].status_latched = false; + } +} void I8253::reset() { @@ -69,10 +67,8 @@ void I8253::write_io8(uint32 addr, uint32 data) } counter[ch].high_write = false; } -#ifdef HAS_I8254 - counter[ch].null_count = true; -#endif - // set signal + counter[ch].null_count = true; + // set signal if(counter[ch].mode == 0) { set_signal(ch, false); } else { @@ -93,13 +89,11 @@ void I8253::write_io8(uint32 addr, uint32 data) } break; - case 3: // ctrl reg - if((data & 0xc0) == 0xc0) { -#ifdef HAS_I8254 + case 3: // ctrl reg + if((data & 0xc0) == 0xc0) { // i8254 read-back command if(device_model == INTEL_8254) { for(ch = 0; ch < 3; ch++) { - uint8 bit = 2 << ch; if(!(data & 0x10) && !counter[ch].status_latched) { counter[ch].status = counter[ch].ctrl_reg & 0x3f; if(counter[ch].prev_out) { @@ -115,9 +109,8 @@ void I8253::write_io8(uint32 addr, uint32 data) } } } -#endif - break; - } + break; + } ch = (data >> 6) & 3; if(data & 0x30) { @@ -139,12 +132,10 @@ void I8253::write_io8(uint32 addr, uint32 data) stop_count(ch); counter[ch].count_reg = 0; // } -#ifdef HAS_I8254 - counter[ch].null_count = true; -#endif - } else if(!counter[ch].count_latched) { - latch_count(ch); - } + counter[ch].null_count = true; + } else if(!counter[ch].count_latched) { + latch_count(ch); + } break; } } @@ -153,19 +144,17 @@ uint32 I8253::read_io8(uint32 addr) { int ch = addr & 3; - switch(ch) { - case 0: - case 1: - case 2: -#ifdef HAS_I8254 + switch(ch) { + case 0: + case 1: + case 2: if(device_model == INTEL_8254) { if(counter[ch].status_latched) { counter[ch].status_latched = false; return counter[ch].status; } } -#endif - // if not latched, through current count + // if not latched, through current count if(!counter[ch].count_latched) { if(!counter[ch].low_read && !counter[ch].high_read) { latch_count(ch); @@ -242,14 +231,12 @@ void I8253::input_clock(int ch, int clock) if(!(counter[ch].start && clock)) { return; } - if(counter[ch].delay) { - clock -= 1; - counter[ch].delay = false; - counter[ch].count = COUNT_VALUE(ch); -#ifdef HAS_I8254 - counter[ch].null_count = false; -#endif - } + if(counter[ch].delay) { + clock -= 1; + counter[ch].delay = false; + counter[ch].count = COUNT_VALUE(ch); + counter[ch].null_count = false; + } // update counter counter[ch].count -= clock; @@ -268,14 +255,12 @@ void I8253::input_clock(int ch, int clock) set_signal(ch, true); } } - if(counter[ch].count <= 0) { - if(counter[ch].mode == 0 || counter[ch].mode == 2 || counter[ch].mode == 3) { - counter[ch].count += tmp; -#ifdef HAS_I8254 - counter[ch].null_count = false; -#endif - goto loop; - } else { + if(counter[ch].count <= 0) { + if(counter[ch].mode == 0 || counter[ch].mode == 2 || counter[ch].mode == 3) { + counter[ch].count += tmp; + counter[ch].null_count = false; + goto loop; + } else { counter[ch].start = false; counter[ch].count = 0x10000; } @@ -410,7 +395,7 @@ int I8253::get_next_count(int ch) return counter[ch].count; } -#define STATE_VERSION 1 +#define STATE_VERSION 2 void I8253::save_state(FILEIO* state_fio) { @@ -429,16 +414,14 @@ void I8253::save_state(FILEIO* state_fio) state_fio->FputBool(counter[i].low_read); state_fio->FputBool(counter[i].high_read); state_fio->FputBool(counter[i].low_write); - state_fio->FputBool(counter[i].high_write); - state_fio->FputInt32(counter[i].mode); - state_fio->FputBool(counter[i].delay); - state_fio->FputBool(counter[i].start); -#ifdef HAS_I8254 - state_fio->FputBool(counter[i].null_count); - state_fio->FputBool(counter[i].status_latched); - state_fio->FputUint8(counter[i].status); -#endif - state_fio->FputUint64(counter[i].freq); + state_fio->FputBool(counter[i].high_write); + state_fio->FputInt32(counter[i].mode); + state_fio->FputBool(counter[i].delay); + state_fio->FputBool(counter[i].start); + state_fio->FputBool(counter[i].null_count); + state_fio->FputBool(counter[i].status_latched); + state_fio->FputUint8(counter[i].status); + state_fio->FputUint64(counter[i].freq); state_fio->FputInt32(counter[i].register_id); state_fio->FputUint32(counter[i].input_clk); state_fio->FputInt32(counter[i].period); @@ -449,10 +432,11 @@ void I8253::save_state(FILEIO* state_fio) bool I8253::load_state(FILEIO* state_fio) { - if(state_fio->FgetUint32() != STATE_VERSION) { - return false; - } - if(state_fio->FgetInt32() != this_device_id) { + uint32 state_version = state_fio->FgetUint32(); + if(state_version < 1 || state_version > STATE_VERSION) { + return false; + } + if(state_fio->FgetInt32() != this_device_id) { return false; } for(int i = 0; i < 3; i++) { @@ -467,16 +451,20 @@ bool I8253::load_state(FILEIO* state_fio) counter[i].low_read = state_fio->FgetBool(); counter[i].high_read = state_fio->FgetBool(); counter[i].low_write = state_fio->FgetBool(); - counter[i].high_write = state_fio->FgetBool(); - counter[i].mode = state_fio->FgetInt32(); - counter[i].delay = state_fio->FgetBool(); - counter[i].start = state_fio->FgetBool(); -#ifdef HAS_I8254 - counter[i].null_count = state_fio->FgetBool(); - counter[i].status_latched = state_fio->FgetBool(); - counter[i].status = state_fio->FgetUint8(); -#endif - counter[i].freq = state_fio->FgetUint64(); + counter[i].high_write = state_fio->FgetBool(); + counter[i].mode = state_fio->FgetInt32(); + counter[i].delay = state_fio->FgetBool(); + counter[i].start = state_fio->FgetBool(); + if(state_version >= 2) { + counter[i].null_count = state_fio->FgetBool(); + counter[i].status_latched = state_fio->FgetBool(); + counter[i].status = state_fio->FgetUint8(); + } else { + counter[i].null_count = true; + counter[i].status_latched = false; + counter[i].status = 0; + } + counter[i].freq = state_fio->FgetUint64(); counter[i].register_id = state_fio->FgetInt32(); counter[i].input_clk = state_fio->FgetUint32(); counter[i].period = state_fio->FgetInt32(); diff --git a/Source/ePC-8801MA/vm/i8253.h b/Source/ePC-8801MA/vm/i8253.h index 5dd0473..0a0209c 100644 --- a/Source/ePC-8801MA/vm/i8253.h +++ b/Source/ePC-8801MA/vm/i8253.h @@ -38,18 +38,16 @@ class I8253 : public DEVICE uint16 count_reg; uint8 ctrl_reg; bool count_latched; - bool low_read, high_read; - bool low_write, high_write; - int mode; - bool delay; - bool start; -#ifdef HAS_I8254 - bool null_count; - bool status_latched; - uint8 status; -#endif - // constant clock - uint64 freq; + bool low_read, high_read; + bool low_write, high_write; + int mode; + bool delay; + bool start; + bool null_count; + bool status_latched; + uint8 status; + // constant clock + uint64 freq; int register_id; uint32 input_clk; int period; diff --git a/Source/ePC-8801MA/vm/pc8801/pc88.cpp b/Source/ePC-8801MA/vm/pc8801/pc88.cpp index 2459b9d..40a65a3 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc88.cpp +++ b/Source/ePC-8801MA/vm/pc8801/pc88.cpp @@ -2474,24 +2474,30 @@ uint32 PC88::read_io8_debug(uint32 addr) return 0xff; } -uint32 PC88::read_dma_data8(uint32 addr) -{ -#if defined(_PC8001SR) - return ram[addr & 0xffff]; -#else - if((addr & 0xf000) == 0xf000 && (config.boot_mode == MODE_PC88_V1H || config.boot_mode == MODE_PC88_V2)) { - return tvram[addr & 0xfff]; - } else { - return ram[addr & 0xffff]; - } -#endif -} - -void PC88::write_dma_io8(uint32 addr, uint32 data) -{ - // to crtc - crtc.write_buffer(data); -} +uint32 PC88::read_dma_data8(uint32 addr) +{ +#if defined(_PC8001SR) + return ram[addr & 0xffff]; +#else + if((addr & 0xf000) == 0xf000 && (config.boot_mode == MODE_PC88_V1H || config.boot_mode == MODE_PC88_V2)) { + return tvram[addr & 0xfff]; + } else { + return ram[addr & 0xffff]; + } +#endif +} + +void PC88::write_dma_data8(uint32 addr, uint32 data) +{ + // DMA memory write path used by common-source compatibility code. + ram[addr & 0xffff] = (uint8)data; +} + +void PC88::write_dma_io8(uint32 addr, uint32 data) +{ + // to crtc + crtc.write_buffer(data); +} void PC88::update_timing() { diff --git a/Source/ePC-8801MA/vm/pc8801/pc88.h b/Source/ePC-8801MA/vm/pc8801/pc88.h index adf6dbc..9acad4c 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc88.h +++ b/Source/ePC-8801MA/vm/pc8801/pc88.h @@ -277,8 +277,9 @@ class PC88 : public DEVICE uint32 read_io8_debug(uint32 addr); #endif - uint32 read_dma_data8(uint32 addr); - void write_dma_io8(uint32 addr, uint32 data); + uint32 read_dma_data8(uint32 addr); + void write_dma_data8(uint32 addr, uint32 data); + void write_dma_io8(uint32 addr, uint32 data); void write_signal(int id, uint32 data, uint32 mask); void event_callback(int event_id, int err); @@ -288,10 +289,26 @@ class PC88 : public DEVICE #else void event_vline(int v, int clock); #endif // SDL - uint32 intr_ack(); - void intr_ei(); - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); + uint32 intr_ack(); + void intr_ei(); + uint32 get_intr_ack() + { + return intr_ack(); + } + void notify_intr_ei() + { + intr_ei(); + } + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading) + { + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; + } // unique functions void set_context_cpu(Z80* device) @@ -347,16 +364,32 @@ class PC88 : public DEVICE d_pcg_pcm2 = device; } #endif - void key_down(int code, bool repeat); - - void play_tape(_TCHAR* file_path); + void key_down(int code, bool repeat); + bool get_caps_locked() + { + return key_caps != 0; + } + bool get_kana_locked() + { + return key_kana != 0; + } + + void play_tape(_TCHAR* file_path); void rec_tape(_TCHAR* file_path); void close_tape(); - bool tape_inserted() - { - return (cmt_play || cmt_rec); - } - bool now_skip(); + bool tape_inserted() + { + return (cmt_play || cmt_rec); + } + bool is_tape_inserted() + { + return tape_inserted(); + } + bool now_skip(); + bool is_frame_skippable() + { + return now_skip(); + } void draw_screen(); @@ -388,9 +421,25 @@ class PC88 : public DEVICE int get_tvram_wait(int pattern, bool read); int get_gvram_wait(int pattern, bool read); int get_m1_wait(int pattern, uint32 addr); - void create_pattern(int pattern, bool read); - void update_memmap(int pattern, bool read); - void insert_gvram_wait(int index, int *wait); + void create_pattern(int pattern, bool read); + void update_memmap(int pattern, bool read); + void update_low_read() + { + update_memmap(-1, true); + } + void update_low_read_sub() + { + update_memmap(-1, true); + } + void update_low_write() + { + update_memmap(-1, false); + } + void update_low_write_sub() + { + update_memmap(-1, false); + } + void insert_gvram_wait(int index, int *wait); uint32 port30_in(); void port31_out(uint8 mod); uint32 port31_in(); diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp index 3b77d73..9e19d21 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.cpp +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.cpp @@ -214,15 +214,32 @@ VM::~VM() } } -DEVICE* VM::get_device(int id) -{ - for(DEVICE* device = first_device; device; device = device->next_device) { - if(device->this_device_id == id) { - return device; - } - } - return NULL; -} +DEVICE* VM::get_device(int id) +{ + for(DEVICE* device = first_device; device; device = device->next_device) { + if(device->this_device_id == id) { + return device; + } + } + return NULL; +} + +UPD765A* VM::get_floppy_disk_controller(int drv) +{ + if(drv == 0 || drv == 1) { + return pc88fdc_sub; + } + return NULL; +} + +DISK* VM::get_floppy_disk_handler(int drv) +{ + UPD765A* controller = get_floppy_disk_controller(drv); + if(controller != NULL) { + return controller->get_disk_handler(drv & 1); + } + return NULL; +} // ---------------------------------------------------------------------------- // drive virtual machine @@ -319,42 +336,112 @@ uint16* VM::create_sound(int* extra_frames) return pc88event->create_sound(extra_frames); } -int VM::sound_buffer_ptr() -{ - return pc88event->sound_buffer_ptr(); -} - -// ---------------------------------------------------------------------------- -// notify key -// ---------------------------------------------------------------------------- +int VM::sound_buffer_ptr() +{ + return pc88event->sound_buffer_ptr(); +} + +void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r) +{ + // XM8 SDL core does not expose per-chip volume control in common format. + (void)ch; + (void)decibel_l; + (void)decibel_r; +} + +// ---------------------------------------------------------------------------- +// notify key +// ---------------------------------------------------------------------------- void VM::key_down(int code, bool repeat) { pc88->key_down(code, repeat); } -void VM::key_up(int code) -{ -} +void VM::key_up(int code) +{ +} + +bool VM::get_caps_locked() +{ + return pc88->get_caps_locked(); +} + +bool VM::get_kana_locked() +{ + return pc88->get_kana_locked(); +} // ---------------------------------------------------------------------------- // user interface // ---------------------------------------------------------------------------- -void VM::open_disk(int drv, _TCHAR* file_path, int bank) -{ - pc88fdc_sub->open_disk(drv, file_path, bank); -} - -void VM::close_disk(int drv) -{ - pc88fdc_sub->close_disk(drv); -} - -bool VM::disk_inserted(int drv) -{ - return pc88fdc_sub->disk_inserted(drv); -} +void VM::open_disk(int drv, _TCHAR* file_path, int bank) +{ + UPD765A* controller = get_floppy_disk_controller(drv); + if(controller != NULL) { + controller->open_disk(drv & 1, file_path, bank); + } +} + +void VM::close_disk(int drv) +{ + UPD765A* controller = get_floppy_disk_controller(drv); + if(controller != NULL) { + controller->close_disk(drv & 1); + } +} + +bool VM::disk_inserted(int drv) +{ + UPD765A* controller = get_floppy_disk_controller(drv); + if(controller != NULL) { + return controller->disk_inserted(drv & 1); + } + return false; +} + +bool VM::is_floppy_disk_connected(int drv) +{ + return (get_floppy_disk_handler(drv) != NULL); +} + +void VM::is_floppy_disk_protected(int drv, bool value) +{ + DISK* handler = get_floppy_disk_handler(drv); + if(handler != NULL) { + handler->write_protected = value; + } +} + +bool VM::is_floppy_disk_protected(int drv) +{ + DISK* handler = get_floppy_disk_handler(drv); + if(handler != NULL) { + return handler->write_protected; + } + return false; +} + +uint32 VM::is_floppy_disk_accessed() +{ + uint32 status = 0; + UPD765A* controller = get_floppy_disk_controller(0); + if(controller != NULL) { + status |= (uint32)(controller->read_signal(0) & 0x03); + } + return status; +} + +uint32 VM::floppy_disk_indicator_color() +{ + UPD765A* controller = get_floppy_disk_controller(0); + if(controller == NULL) { + return 0; + } + return ((controller->get_drive_type(0) == DRIVE_TYPE_2HD) ? 1 : 0) | + ((controller->get_drive_type(1) == DRIVE_TYPE_2HD) ? 2 : 0); +} void VM::play_tape(_TCHAR* file_path) { @@ -371,16 +458,38 @@ void VM::close_tape() pc88->close_tape(); } -bool VM::tape_inserted() -{ - return pc88->tape_inserted(); -} - -bool VM::now_skip() -{ -// return event->now_skip(); - return pc88->now_skip(); -} +bool VM::tape_inserted() +{ + return pc88->tape_inserted(); +} + +void VM::open_compact_disc(int drv, const _TCHAR* file_path) +{ + (void)drv; + (void)file_path; +} + +void VM::close_compact_disc(int drv) +{ + (void)drv; +} + +bool VM::is_compact_disc_inserted(int drv) +{ + (void)drv; + return false; +} + +uint32 VM::is_compact_disc_accessed() +{ + return 0; +} + +bool VM::now_skip() +{ +// return event->now_skip(); + return pc88->now_skip(); +} void VM::update_config() { diff --git a/Source/ePC-8801MA/vm/pc8801/pc8801.h b/Source/ePC-8801MA/vm/pc8801/pc8801.h index 0a9c5d3..38a98a4 100644 --- a/Source/ePC-8801MA/vm/pc8801/pc8801.h +++ b/Source/ePC-8801MA/vm/pc8801/pc8801.h @@ -114,8 +114,9 @@ class DiskSub; #else class PC80S31K; #endif // SDL -class UPD765A; -class NOISE; +class UPD765A; +class NOISE; +class DISK; #ifdef SUPPORT_PC88_PCG8100 class I8253; @@ -164,8 +165,11 @@ class VM PC88* pc88; - int boot_mode; - + int boot_mode; + + UPD765A* get_floppy_disk_controller(int drv); + DISK* get_floppy_disk_handler(int drv); + public: // ---------------------------------------- // initialize @@ -182,6 +186,10 @@ class VM void reset(); void run(); double frame_rate(); + double get_frame_rate() + { + return frame_rate(); + } #ifdef USE_DEBUGGER // debugger @@ -196,24 +204,84 @@ class VM void initialize_sound(int rate, int samples); uint16* create_sound(int* extra_frames); int sound_buffer_ptr(); - + int get_sound_buffer_ptr() + { + return sound_buffer_ptr(); + } + void set_sound_device_volume(int ch, int decibel_l, int decibel_r); + // notify key void key_down(int code, bool repeat); void key_up(int code); + bool get_caps_locked(); + bool get_kana_locked(); // user interface void open_disk(int drv, _TCHAR* file_path, int bank); + void open_floppy_disk(int drv, const _TCHAR* file_path, int bank) + { + open_disk(drv, const_cast<_TCHAR*>(file_path), bank); + } void close_disk(int drv); + void close_floppy_disk(int drv) + { + close_disk(drv); + } bool disk_inserted(int drv); + bool is_floppy_disk_connected(int drv); + bool is_floppy_disk_inserted(int drv) + { + return disk_inserted(drv); + } + void is_floppy_disk_protected(int drv, bool value); + bool is_floppy_disk_protected(int drv); + uint32 is_floppy_disk_accessed(); + uint32 floppy_disk_indicator_color(); void play_tape(_TCHAR* file_path); + void play_tape(int drv, const _TCHAR* file_path) + { + (void)drv; + play_tape(const_cast<_TCHAR*>(file_path)); + } void rec_tape(_TCHAR* file_path); + void rec_tape(int drv, const _TCHAR* file_path) + { + (void)drv; + rec_tape(const_cast<_TCHAR*>(file_path)); + } void close_tape(); + void close_tape(int drv) + { + (void)drv; + close_tape(); + } bool tape_inserted(); + bool is_tape_inserted(int drv) + { + (void)drv; + return tape_inserted(); + } + void open_compact_disc(int drv, const _TCHAR* file_path); + void close_compact_disc(int drv); + bool is_compact_disc_inserted(int drv); + uint32 is_compact_disc_accessed(); bool now_skip(); + bool is_frame_skippable() + { + return now_skip(); + } - void update_config(); - void save_state(FILEIO* state_fio); - bool load_state(FILEIO* state_fio); + void update_config(); + void save_state(FILEIO* state_fio); + bool load_state(FILEIO* state_fio); + bool process_state(FILEIO* state_fio, bool loading) + { + if(loading) { + return load_state(state_fio); + } + save_state(state_fio); + return true; + } // ---------------------------------------- // for each device diff --git a/Source/ePC-8801MA/vm/upd1990a.cpp b/Source/ePC-8801MA/vm/upd1990a.cpp index 84b2587..67edd07 100644 --- a/Source/ePC-8801MA/vm/upd1990a.cpp +++ b/Source/ePC-8801MA/vm/upd1990a.cpp @@ -12,20 +12,21 @@ #define EVENT_1SEC 0 #define EVENT_TP 1 -void UPD1990A::initialize() -{ - // initialize rtc - emu->get_host_time(&cur_time); - - // register events -#ifdef SDL - register_event(this, EVENT_1SEC, 100000.0, true, ®ister_id_1sec); - event_count = 0; -#else - register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); -#endif // SDL - register_id_tp = -1; -} +void UPD1990A::initialize() +{ + // initialize rtc + emu->get_host_time(&cur_time); + + // register events +#ifdef SDL + // Keep period under the SDL event manager's long-loop edge case at high CPU clocks. + register_event(this, EVENT_1SEC, 100000.0, true, ®ister_id_1sec); + event_count = 0; +#else + register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); +#endif // SDL + register_id_tp = -1; +} void UPD1990A::write_signal(int id, uint32 data, uint32 mask) { @@ -161,22 +162,23 @@ void UPD1990A::write_signal(int id, uint32 data, uint32 mask) } // reset counter hold switch(mode & 0x0f) { - case 0x00: - case 0x01: - case 0x03: - if(hold) { - // restart event - cancel_event(this, register_id_1sec); -#ifdef SDL - register_event(this, EVENT_1SEC, 100000.0, true, ®ister_id_1sec); -#else - register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); -#endif // SDL - hold = false; - } - break; - } - } + case 0x00: + case 0x01: + case 0x03: + if(hold) { + // restart event + cancel_event(this, register_id_1sec); +#ifdef SDL + register_event(this, EVENT_1SEC, 100000.0, true, ®ister_id_1sec); + event_count = 0; +#else + register_event(this, EVENT_1SEC, 1000000.0, true, ®ister_id_1sec); +#endif // SDL + hold = false; + } + break; + } + } stb = next; } else if(id == SIG_UPD1990A_CMD) { cmd = (cmd & ~mask) | (data & mask); @@ -195,21 +197,20 @@ void UPD1990A::write_signal(int id, uint32 data, uint32 mask) } } -void UPD1990A::event_callback(int event_id, int err) -{ - if(event_id == EVENT_1SEC) { -#ifdef SDL - event_count++; - if (event_count < 10) { - return; - } - event_count = 0; -#endif // SDL - - if(cur_time.initialized) { - if(!hold) { - cur_time.increment(); - } +void UPD1990A::event_callback(int event_id, int err) +{ + if(event_id == EVENT_1SEC) { +#ifdef SDL + event_count++; + if(event_count < 10) { + return; + } + event_count = 0; +#endif // SDL + if(cur_time.initialized) { + if(!hold) { + cur_time.increment(); + } if(dout_changed) { dout_changed = false; } else { @@ -276,13 +277,18 @@ bool UPD1990A::load_state(FILEIO* state_fio) dout = state_fio->FgetUint32(); dout_changed = state_fio->FgetBool(); register_id_tp = state_fio->FgetInt32(); -#ifdef HAS_UPD4990A - shift_cmd = state_fio->FgetUint8(); -#endif - - // version 1.60 - adjust_event(register_id_1sec, 100000.0); - - return true; -} +#ifdef HAS_UPD4990A + shift_cmd = state_fio->FgetUint8(); +#endif + + // version 1.60 +#ifdef SDL + adjust_event(register_id_1sec, 100000.0); + event_count = 0; +#else + adjust_event(register_id_1sec, 1000000.0); +#endif // SDL + + return true; +} diff --git a/Source/ePC-8801MA/vm/upd1990a.h b/Source/ePC-8801MA/vm/upd1990a.h index 1bba2b8..87728ca 100644 --- a/Source/ePC-8801MA/vm/upd1990a.h +++ b/Source/ePC-8801MA/vm/upd1990a.h @@ -83,11 +83,11 @@ class UPD1990A : public DEVICE { register_output_signal(&outputs_tp, device, id, mask); } -#ifdef SDL - void resync(void) { cur_time.initialized = false; } - uint32 event_count; -#endif // SDL -}; +#ifdef SDL + void resync(void) { cur_time.initialized = false; } + uint32 event_count; +#endif // SDL +}; #endif diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 2478815..0e08d4c 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -13,12 +13,13 @@ #include "noise.h" #define EVENT_PHASE 0 -#define EVENT_DRQ 1 -#define EVENT_LOST 2 +#define EVENT_DRQ 1 +#define EVENT_LOST 2 #define EVENT_RESULT7 3 #define EVENT_INDEX 4 -#define EVENT_SEEK 5 -#define EVENT_UNLOAD 9 +#define EVENT_SEEK_STEP 5 +#define EVENT_SEEK 9 +#define EVENT_UNLOAD 13 #define PHASE_IDLE 0 #define PHASE_CMD 1 @@ -140,6 +141,11 @@ cancel_event(this, seek_id[d]); \ seek_id[d] = -1; \ } \ + if(seek_step_id[d] != -1) { \ + cancel_event(this, seek_step_id[d]); \ + seek_step_id[d] = -1; \ + } \ + seek_step_remain[d] = 0; \ if(head_unload_id[d] != -1) { \ cancel_event(this, head_unload_id[d]); \ head_unload_id[d] = -1; \ @@ -177,15 +183,18 @@ void UPD765A::initialize() // initialize fdc memset(fdc, 0, sizeof(fdc)); + memset(cur_track, 0, sizeof(cur_track)); memset(head_load, 0, sizeof(head_load)); memset(buffer, 0, sizeof(buffer)); - phase = prevphase = PHASE_IDLE; - status = S_RQM; - seekstat = 0; + phase = prevphase = PHASE_IDLE; + status = S_RQM; + seekstat = 0; bufptr = buffer; // temporary phase_id = drq_id = lost_id = result7_id = -1; seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; + seek_step_id[0] = seek_step_id[1] = seek_step_id[2] = seek_step_id[3] = -1; + seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; head_unload_time = 0; no_dma_mode = false; @@ -225,8 +234,14 @@ void UPD765A::reset() // CANCEL_EVENT(); phase_id = drq_id = lost_id = result7_id = -1; seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; + seek_step_id[0] = seek_step_id[1] = seek_step_id[2] = seek_step_id[3] = -1; + seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; head_load[0] = head_load[1] = head_load[2] = head_load[3] = false; + cur_track[0] = fdc[0].track; + cur_track[1] = fdc[1].track; + cur_track[2] = fdc[2].track; + cur_track[3] = fdc[3].track; set_irq(false); set_drq(false); @@ -515,8 +530,31 @@ void UPD765A::event_callback(int event_id, int err) write_signals(&outputs_index, now_index ? 0xffffffff : 0); prev_index = now_index; } + } else if(event_id >= EVENT_SEEK_STEP && event_id < EVENT_SEEK_STEP + 4) { + int drv = event_id - EVENT_SEEK_STEP; + if(cur_track[drv] < fdc[drv].track) { + cur_track[drv]++; + } else if(cur_track[drv] > fdc[drv].track) { + cur_track[drv]--; + } + if(seek_step_remain[drv] > 0) { + seek_step_remain[drv]--; + if(d_noise_seek != NULL) { + d_noise_seek->play(); + } + } + if((cur_track[drv] == fdc[drv].track || seek_step_remain[drv] <= 0) && seek_step_id[drv] != -1) { + cancel_event(this, seek_step_id[drv]); + seek_step_id[drv] = -1; + } } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) { int drv = event_id - EVENT_SEEK; + if(seek_step_id[drv] != -1) { + cancel_event(this, seek_step_id[drv]); + seek_step_id[drv] = -1; + } + seek_step_remain[drv] = 0; + cur_track[drv] = fdc[drv].track; seek_id[drv] = -1; seek_event(drv); } else if(event_id >= EVENT_UNLOAD && event_id < EVENT_UNLOAD + 4) { @@ -689,20 +727,18 @@ void UPD765A::cmd_sence_intstat() // status &= ~S_CB; } -uint8 UPD765A::get_devstat(int drv) -{ - if(drv >= MAX_DRIVE) { - return 0x80 | drv; - } -#ifdef SDL - if(!disk[drv]->inserted && !force_ready) { -#else - if(!disk[drv]->inserted) { -#endif // SDL - return drv; - } - return 0x28 | drv | (fdc[drv].track ? 0 : 0x10) | ((fdc[drv].track & 1) ? 0x04 : 0) | (disk[drv]->write_protected ? 0x40 : 0); -} +uint8 UPD765A::get_devstat(int drv) +{ + if(drv >= MAX_DRIVE) { + return ST3_FT | drv; + } + return drv | + ((cur_track[drv] & 1) ? ST3_HD : 0) | + ST3_TS | + (cur_track[drv] ? 0 : ST3_T0) | + ((force_ready || disk[drv]->inserted) ? ST3_RY : 0) | + (disk[drv]->write_protected ? ST3_WP : 0); +} void UPD765A::cmd_seek() { @@ -733,38 +769,54 @@ void UPD765A::cmd_recalib() void UPD765A::seek(int drv, int trk) { // get distance - int prev_track = fdc[drv].track; - int seektime = 32 - 2 * step_rate_time; + int distance = abs(trk - cur_track[drv]); + int steptime = 32 - 2 * step_rate_time; if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { - seektime /= 2; + steptime /= 2; } - seektime = (trk == fdc[drv].track) ? 120 : seektime * abs(trk - fdc[drv].track) + 500; //usec - - if(drv >= MAX_DRIVE) { - // invalid drive number - fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; - set_irq(true); + if(steptime <= 0) { + steptime = 1; + } + int seektime = (distance == 0) ? 120 : steptime * distance + 500; // usec + + if(drv >= MAX_DRIVE) { + // invalid drive number + fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; + set_irq(true); } else { fdc[drv].track = trk; - if(prev_track != trk && d_noise_seek != NULL) { +#ifdef UPD765A_DONT_WAIT_SEEK + if(distance > 0 && d_noise_seek != NULL) { d_noise_seek->play(); } -#ifdef UPD765A_DONT_WAIT_SEEK + cur_track[drv] = fdc[drv].track; seek_event(drv); #else - if(seek_id[drv] != -1) { - cancel_event(this, seek_id[drv]); - } -#ifdef SDL - if (config.ignore_crc) { - seektime = 100; - } -#endif // SDL - register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]); - seekstat |= 1 << drv; -#endif - } -} + if(seek_step_id[drv] != -1) { + cancel_event(this, seek_step_id[drv]); + } + if(seek_id[drv] != -1) { + cancel_event(this, seek_id[drv]); + } + seek_step_id[drv] = -1; + seek_step_remain[drv] = 0; +#ifdef SDL + if (config.ignore_crc) { + seektime = 100; + distance = 0; + } +#endif // SDL + if(distance > 0) { + seek_step_remain[drv] = distance; + register_event(this, EVENT_SEEK_STEP + drv, steptime, true, &seek_step_id[drv]); + } else { + cur_track[drv] = fdc[drv].track; + } + register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]); + seekstat |= 1 << drv; +#endif + } +} void UPD765A::seek_event(int drv) { @@ -1757,7 +1809,7 @@ void UPD765A::set_drive_mfm(int drv, bool mfm) } } -#define STATE_VERSION 2 +#define STATE_VERSION 4 void UPD765A::save_state(FILEIO* state_fio) { @@ -1798,9 +1850,12 @@ void UPD765A::save_state(FILEIO* state_fio) state_fio->FputInt32(event_phase); state_fio->FputInt32(phase_id); state_fio->FputInt32(drq_id); - state_fio->FputInt32(lost_id); - state_fio->FputInt32(result7_id); - state_fio->Fwrite(seek_id, sizeof(seek_id), 1); + state_fio->FputInt32(lost_id); + state_fio->FputInt32(result7_id); + state_fio->Fwrite(seek_id, sizeof(seek_id), 1); + state_fio->Fwrite(seek_step_id, sizeof(seek_step_id), 1); + state_fio->Fwrite(seek_step_remain, sizeof(seek_step_remain), 1); + state_fio->Fwrite(cur_track, sizeof(cur_track), 1); state_fio->FputBool(force_ready); state_fio->FputBool(reset_signal); state_fio->FputBool(prev_index); @@ -1855,9 +1910,28 @@ bool UPD765A::load_state(FILEIO* state_fio) event_phase = state_fio->FgetInt32(); phase_id = state_fio->FgetInt32(); drq_id = state_fio->FgetInt32(); - lost_id = state_fio->FgetInt32(); - result7_id = state_fio->FgetInt32(); - state_fio->Fread(seek_id, sizeof(seek_id), 1); + lost_id = state_fio->FgetInt32(); + result7_id = state_fio->FgetInt32(); + state_fio->Fread(seek_id, sizeof(seek_id), 1); + if(state_version >= 3) { + state_fio->Fread(seek_step_id, sizeof(seek_step_id), 1); + state_fio->Fread(seek_step_remain, sizeof(seek_step_remain), 1); + if(state_version >= 4) { + state_fio->Fread(cur_track, sizeof(cur_track), 1); + } else { + cur_track[0] = fdc[0].track; + cur_track[1] = fdc[1].track; + cur_track[2] = fdc[2].track; + cur_track[3] = fdc[3].track; + } + } else { + seek_step_id[0] = seek_step_id[1] = seek_step_id[2] = seek_step_id[3] = -1; + seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; + cur_track[0] = fdc[0].track; + cur_track[1] = fdc[1].track; + cur_track[2] = fdc[2].track; + cur_track[3] = fdc[3].track; + } force_ready = state_fio->FgetBool(); reset_signal = state_fio->FgetBool(); prev_index = state_fio->FgetBool(); diff --git a/Source/ePC-8801MA/vm/upd765a.h b/Source/ePC-8801MA/vm/upd765a.h index c560152..de8e2f1 100644 --- a/Source/ePC-8801MA/vm/upd765a.h +++ b/Source/ePC-8801MA/vm/upd765a.h @@ -46,11 +46,12 @@ class UPD765A : public DEVICE uint8 track; uint8 result; bool access; - // timing - int cur_position; + // timing + int cur_position; int next_trans_position; uint32 prev_clock; } fdc[4]; + uint8 cur_track[4]; bool head_load[4]; DISK* disk[4]; @@ -71,7 +72,8 @@ class UPD765A : public DEVICE uint8 buffer[0x8000]; int count; int event_phase; - int phase_id, drq_id, lost_id, result7_id, seek_id[4], head_unload_id[4]; + int phase_id, drq_id, lost_id, result7_id, seek_id[4], seek_step_id[4], head_unload_id[4]; + int seek_step_remain[4]; bool force_ready; bool reset_signal; bool prev_index;