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
+
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/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..535a9f7 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,15 @@ class DISK
double get_usec_per_bytes(int bytes);
int get_bytes_per_usec(double usec);
bool check_media_type();
+ bool correct_timing()
+ {
+ // Keep current XM8 behavior: standard images use fixed timing path.
+ return !is_standard_image;
+ }
+ bool ignore_crc()
+ {
+ return config.ignore_crc;
+ }
bool inserted;
bool ejected;
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/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 6763b6b..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;
@@ -446,8 +468,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 +507,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
@@ -682,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]);
}
@@ -1024,42 +1055,51 @@ 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
- 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
+ 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;
+ }
+ 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);
} 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
- 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;
}
@@ -1085,19 +1125,25 @@ 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;
- }
- // 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;
+ 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;
+ }
+ 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) {
@@ -1124,21 +1170,30 @@ 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;
- }
- // 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;
+ 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;
+ }
+ 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;
}
@@ -1294,26 +1349,30 @@ 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;
-}
-
-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);
+ 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_MA;
+}
+
+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;
@@ -1464,13 +1523,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);
diff --git a/Source/ePC-8801MA/vm/upd765a.h b/Source/ePC-8801MA/vm/upd765a.h
index 265794d..c69299c 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
@@ -136,11 +146,12 @@ class UPD765A : public DEVICE
void reset();
void write_io8(uint32 addr, uint32 data);
uint32 read_io8(uint32 addr);
- void write_dma_io8(uint32 addr, uint32 data);
- uint32 read_dma_io8(uint32 addr);
- void write_signal(int id, uint32 data, uint32 mask);
- uint32 read_signal(int ch);
+ void write_dma_io8(uint32 addr, uint32 data);
+ 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 update_config();
void save_state(FILEIO* state_fio);
bool load_state(FILEIO* state_fio);
bool process_state(FILEIO* state_fio, bool loading);
@@ -154,14 +165,38 @@ class UPD765A : public DEVICE
{
register_output_signal(&outputs_drq, device, id, mask);
}
- void set_context_hdu(DEVICE* device, int id, uint32 mask)
- {
- 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_hdu(DEVICE* device, int id, uint32 mask)
+ {
+ 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_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) {
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_ */