summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/imagedev
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/imagedev')
-rw-r--r--src/devices/imagedev/avivideo.cpp58
-rw-r--r--src/devices/imagedev/avivideo.h45
-rw-r--r--src/devices/imagedev/bitbngr.cpp41
-rw-r--r--src/devices/imagedev/bitbngr.h41
-rw-r--r--src/devices/imagedev/cartrom.cpp30
-rw-r--r--src/devices/imagedev/cartrom.h55
-rw-r--r--src/devices/imagedev/cassette.cpp345
-rw-r--r--src/devices/imagedev/cassette.h99
-rw-r--r--src/devices/imagedev/cdromimg.cpp283
-rw-r--r--src/devices/imagedev/cdromimg.h117
-rw-r--r--src/devices/imagedev/chd_cd.cpp130
-rw-r--r--src/devices/imagedev/chd_cd.h70
-rw-r--r--src/devices/imagedev/diablo.cpp144
-rw-r--r--src/devices/imagedev/diablo.h59
-rw-r--r--src/devices/imagedev/flopdrv.cpp441
-rw-r--r--src/devices/imagedev/flopdrv.h115
-rw-r--r--src/devices/imagedev/floppy.cpp2274
-rw-r--r--src/devices/imagedev/floppy.h413
-rw-r--r--src/devices/imagedev/harddriv.cpp280
-rw-r--r--src/devices/imagedev/harddriv.h92
-rw-r--r--src/devices/imagedev/magtape.cpp35
-rw-r--r--src/devices/imagedev/magtape.h56
-rw-r--r--src/devices/imagedev/memcard.cpp18
-rw-r--r--src/devices/imagedev/memcard.h39
-rw-r--r--src/devices/imagedev/mfmhd.cpp464
-rw-r--r--src/devices/imagedev/mfmhd.h52
-rw-r--r--src/devices/imagedev/microdrv.cpp32
-rw-r--r--src/devices/imagedev/microdrv.h52
-rw-r--r--src/devices/imagedev/midiin.cpp567
-rw-r--r--src/devices/imagedev/midiin.h156
-rw-r--r--src/devices/imagedev/midiout.cpp40
-rw-r--r--src/devices/imagedev/midiout.h40
-rw-r--r--src/devices/imagedev/papertape.cpp38
-rw-r--r--src/devices/imagedev/papertape.h71
-rw-r--r--src/devices/imagedev/picture.cpp49
-rw-r--r--src/devices/imagedev/picture.h32
-rw-r--r--src/devices/imagedev/printer.cpp19
-rw-r--r--src/devices/imagedev/printer.h33
-rw-r--r--src/devices/imagedev/simh_tape_image.cpp85
-rw-r--r--src/devices/imagedev/simh_tape_image.h52
-rw-r--r--src/devices/imagedev/snapquik.cpp61
-rw-r--r--src/devices/imagedev/snapquik.h56
-rw-r--r--src/devices/imagedev/wafadrive.cpp11
-rw-r--r--src/devices/imagedev/wafadrive.h35
44 files changed, 4581 insertions, 2644 deletions
diff --git a/src/devices/imagedev/avivideo.cpp b/src/devices/imagedev/avivideo.cpp
index 0c3559a127a..bfa095fd331 100644
--- a/src/devices/imagedev/avivideo.cpp
+++ b/src/devices/imagedev/avivideo.cpp
@@ -26,8 +26,8 @@ DEFINE_DEVICE_TYPE(IMAGE_AVIVIDEO, avivideo_image_device, "avivideo_image", "AVI
avivideo_image_device::avivideo_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, IMAGE_AVIVIDEO, tag, owner, clock),
device_image_interface(mconfig, *this),
- m_frame(nullptr),
- m_avi(nullptr),
+ m_frame(),
+ m_avi(),
m_frame_timer(nullptr),
m_frame_count(0),
m_frame_num(0)
@@ -46,7 +46,7 @@ avivideo_image_device::~avivideo_image_device()
void avivideo_image_device::device_start()
{
- m_frame_timer = timer_alloc(TIMER_FRAME);
+ m_frame_timer = timer_alloc(FUNC(avivideo_image_device::frame_timer), this);
m_frame_timer->adjust(attotime::never);
save_item(NAME(m_frame_count));
@@ -58,40 +58,36 @@ void avivideo_image_device::device_reset()
m_frame_num = 0;
}
-void avivideo_image_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(avivideo_image_device::frame_timer)
{
- if (id == TIMER_FRAME)
+ if (m_avi)
{
- if (m_avi != nullptr)
+ avi_file::error avierr = m_avi->read_uncompressed_video_frame(m_frame_num, *m_frame);
+ if (avierr != avi_file::error::NONE)
{
- avi_file::error avierr = m_avi->read_uncompressed_video_frame(m_frame_num, *m_frame);
- if (avierr != avi_file::error::NONE)
- {
- m_frame_timer->adjust(attotime::never);
- return;
- }
- m_frame_num++;
- if (m_frame_num >= m_frame_count)
- {
- m_frame_num = 0;
- }
+ m_frame_timer->adjust(attotime::never);
+ return;
}
- else
+ m_frame_num++;
+ if (m_frame_num >= m_frame_count)
{
- m_frame_timer->adjust(attotime::never);
+ m_frame_num = 0;
}
}
+ else
+ {
+ m_frame_timer->adjust(attotime::never);
+ }
}
-image_init_result avivideo_image_device::call_load()
+std::pair<std::error_condition, std::string> avivideo_image_device::call_load()
{
- m_frame = new bitmap_argb32;
+ m_frame.reset(new bitmap_argb32);
avi_file::error avierr = avi_file::open(filename(), m_avi);
if (avierr != avi_file::error::NONE)
{
- delete m_frame;
- m_frame = nullptr;
- return image_init_result::FAIL;
+ m_frame.reset();
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
}
const avi_file::movie_info &aviinfo = m_avi->get_movie_info();
@@ -100,19 +96,11 @@ image_init_result avivideo_image_device::call_load()
m_frame_timer->adjust(frame_time, 0, frame_time);
m_frame_count = aviinfo.video_numsamples;
m_frame_num = 0;
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
void avivideo_image_device::call_unload()
{
- if (m_frame)
- {
- delete m_frame;
- m_frame = nullptr;
- }
- if (m_avi)
- {
- m_avi.release();
- m_avi = nullptr;
- }
+ m_frame.reset();
+ m_avi.reset();
}
diff --git a/src/devices/imagedev/avivideo.h b/src/devices/imagedev/avivideo.h
index 8feb78b262e..67d0f30d132 100644
--- a/src/devices/imagedev/avivideo.h
+++ b/src/devices/imagedev/avivideo.h
@@ -8,13 +8,19 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_AVIVIDEO_H
-#define MAME_DEVICES_IMAGEDEV_AVIVIDEO_H
+#ifndef MAME_IMAGEDEV_AVIVIDEO_H
+#define MAME_IMAGEDEV_AVIVIDEO_H
#pragma once
-#include "bitmap.h"
#include "aviio.h"
+#include "bitmap.h"
+
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
/***************************************************************************
TYPE DEFINITIONS
@@ -29,30 +35,29 @@ public:
avivideo_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual ~avivideo_image_device();
- // image-level overrides
- virtual image_init_result call_load() override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual void call_unload() override;
- virtual iodevice_t image_type() const override { return IO_VIDEO; }
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 0; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *file_extensions() const override { return "avi"; }
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return false; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *file_extensions() const noexcept override { return "avi"; }
+ virtual const char *image_type_name() const noexcept override { return "vidfile"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "vid"; }
bitmap_argb32 &get_frame() { return *m_frame; }
protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
-private:
- static constexpr device_timer_id TIMER_FRAME = 0;
+ TIMER_CALLBACK_MEMBER(frame_timer);
- bitmap_argb32 *m_frame;
+private:
+ std::unique_ptr<bitmap_argb32> m_frame;
avi_file::ptr m_avi;
emu_timer *m_frame_timer;
@@ -64,4 +69,4 @@ private:
// device type definition
DECLARE_DEVICE_TYPE(IMAGE_AVIVIDEO, avivideo_image_device)
-#endif // MAME_DEVICES_IMAGEDEV_AVIVIDEO_H
+#endif // MAME_IMAGEDEV_AVIVIDEO_H
diff --git a/src/devices/imagedev/bitbngr.cpp b/src/devices/imagedev/bitbngr.cpp
index 2a18395ad75..ae207c81498 100644
--- a/src/devices/imagedev/bitbngr.cpp
+++ b/src/devices/imagedev/bitbngr.cpp
@@ -9,6 +9,10 @@
#include "emu.h"
#include "bitbngr.h"
+#include "softlist_dev.h"
+
+#include <cstring>
+
/***************************************************************************
@@ -37,10 +41,8 @@ bitbanger_device::bitbanger_device(const machine_config &mconfig, const char *ta
void bitbanger_device::output(uint8_t data)
{
- if (exists())
- {
+ if (!loaded_through_softlist() && exists())
fwrite(&data, 1);
- }
}
@@ -51,10 +53,9 @@ void bitbanger_device::output(uint8_t data)
uint32_t bitbanger_device::input(void *buffer, uint32_t length)
{
if (exists())
- {
return fread(buffer, length);
- }
- return 0;
+ else
+ return 0;
}
@@ -63,8 +64,19 @@ uint32_t bitbanger_device::input(void *buffer, uint32_t length)
device_start
-------------------------------------------------*/
-void bitbanger_device::device_start(void)
+void bitbanger_device::device_start()
+{
+}
+
+
+
+/*-------------------------------------------------
+ get_software_list_loader
+-------------------------------------------------*/
+
+const software_list_loader &bitbanger_device::get_software_list_loader() const
{
+ return image_software_list_loader::instance();
}
@@ -73,22 +85,23 @@ void bitbanger_device::device_start(void)
call_load
-------------------------------------------------*/
-image_init_result bitbanger_device::call_load(void)
+std::pair<std::error_condition, std::string> bitbanger_device::call_load()
{
- /* we don't need to do anything special */
- return image_init_result::PASS;
+ // we don't need to do anything special
+ return std::make_pair(std::error_condition(), std::string());
}
-image_init_result bitbanger_device::call_create(int format_type, util::option_resolution *format_options)
+std::pair<std::error_condition, std::string> bitbanger_device::call_create(int format_type, util::option_resolution *format_options)
{
- /* we don't need to do anything special */
- return image_init_result::PASS;
+ // we don't need to do anything special
+ return std::make_pair(std::error_condition(), std::string());
}
/*-------------------------------------------------
call_unload
-------------------------------------------------*/
-void bitbanger_device::call_unload(void)
+void bitbanger_device::call_unload()
{
+ // we don't need to do anything special
}
diff --git a/src/devices/imagedev/bitbngr.h b/src/devices/imagedev/bitbngr.h
index 2a2a72dd9a6..a10cfc80bb1 100644
--- a/src/devices/imagedev/bitbngr.h
+++ b/src/devices/imagedev/bitbngr.h
@@ -6,8 +6,10 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_BITBNGR_H
-#define MAME_DEVICES_IMAGEDEV_BITBNGR_H
+#ifndef MAME_IMAGEDEV_BITBNGR_H
+#define MAME_IMAGEDEV_BITBNGR_H
+
+#pragma once
class bitbanger_device : public device_t,
public device_image_interface
@@ -19,29 +21,30 @@ public:
// construction/destruction
bitbanger_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- // image-level overrides
- virtual image_init_result call_load() override;
- virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
virtual void call_unload() override;
- // image device
- virtual iodevice_t image_type() const override { return IO_SERIAL; }
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return !m_is_readonly; }
- virtual bool is_creatable() const override { return !m_is_readonly; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override { return m_interface; }
- virtual const char *file_extensions() const override { return ""; }
- virtual const char *custom_instance_name() const override { return "bitbanger"; }
- virtual const char *custom_brief_instance_name() const override { return "bitb"; }
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return !m_is_readonly; }
+ virtual bool is_creatable() const noexcept override { return !m_is_readonly; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual bool support_command_line_image_creation() const noexcept override { return !m_is_readonly; }
+ virtual const char *image_interface() const noexcept override { return m_interface; }
+ virtual const char *file_extensions() const noexcept override { return ""; }
+ virtual const char *image_type_name() const noexcept override { return "bitbanger"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "bitb"; }
void output(uint8_t data);
uint32_t input(void *buffer, uint32_t length);
protected:
- // device-level overrides
- virtual void device_start() override;
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
+
+ // device_image_interface implementation
+ virtual software_list_loader const &get_software_list_loader() const override;
private:
char const *m_interface;
@@ -52,4 +55,4 @@ private:
// device type definition
DECLARE_DEVICE_TYPE(BITBANGER, bitbanger_device)
-#endif // MAME_DEVICES_IMAGEDEV_BITBNGR_H
+#endif // MAME_IMAGEDEV_BITBNGR_H
diff --git a/src/devices/imagedev/cartrom.cpp b/src/devices/imagedev/cartrom.cpp
new file mode 100644
index 00000000000..7b357817bbe
--- /dev/null
+++ b/src/devices/imagedev/cartrom.cpp
@@ -0,0 +1,30 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/*********************************************************************
+
+ cartrom.cpp
+
+ Base classes for ROM and cartridge ROM image devices.
+
+*********************************************************************/
+
+#include "emu.h"
+#include "cartrom.h"
+
+#include "softlist_dev.h"
+
+
+device_rom_image_interface::device_rom_image_interface(const machine_config &mconfig, device_t &device)
+ : device_image_interface(mconfig, device)
+{
+}
+
+device_cartrom_image_interface::device_cartrom_image_interface(const machine_config &mconfig, device_t &device)
+ : device_rom_image_interface(mconfig, device)
+{
+}
+
+const software_list_loader &device_rom_image_interface::get_software_list_loader() const
+{
+ return rom_software_list_loader::instance();
+}
diff --git a/src/devices/imagedev/cartrom.h b/src/devices/imagedev/cartrom.h
new file mode 100644
index 00000000000..07b58c786cb
--- /dev/null
+++ b/src/devices/imagedev/cartrom.h
@@ -0,0 +1,55 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/*********************************************************************
+
+ cartrom.h
+
+ Base classes for ROM and cartridge ROM image devices.
+
+*********************************************************************/
+
+#ifndef MAME_IMAGEDEV_CARTROM_H
+#define MAME_IMAGEDEV_CARTROM_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> device_rom_image_interface
+
+class device_rom_image_interface : public device_image_interface
+{
+public:
+ // image-level overrides
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return false; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual const char *image_type_name() const noexcept override { return "romimage"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "rom"; }
+
+protected:
+ // construction/destruction
+ device_rom_image_interface(const machine_config &mconfig, device_t &device);
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override;
+};
+
+// ======================> device_cartrom_image_interface
+
+class device_cartrom_image_interface : public device_rom_image_interface
+{
+public:
+ // image-level overrides
+ virtual const char *image_type_name() const noexcept override { return "cartridge"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "cart"; }
+
+protected:
+ // construction/destruction
+ device_cartrom_image_interface(const machine_config &mconfig, device_t &device);
+};
+
+#endif // MAME_IMAGEDEV_CARTROM_H
diff --git a/src/devices/imagedev/cassette.cpp b/src/devices/imagedev/cassette.cpp
index 3007ea752f5..cef022b57a5 100644
--- a/src/devices/imagedev/cassette.cpp
+++ b/src/devices/imagedev/cassette.cpp
@@ -9,16 +9,24 @@
*********************************************************************/
#include "emu.h"
-#include "formats/imageutl.h"
#include "cassette.h"
+#include "softlist_dev.h"
+
+#include "formats/imageutl.h"
+
+#include "util/ioprocs.h"
+#include "util/ioprocsfilter.h"
+
+#include <regex>
-#define LOG_WARN (1U<<1) // Warnings
-#define LOG_DETAIL (1U<<2) // Details
+#define LOG_WARN (1U << 1) // Warnings
+#define LOG_DETAIL (1U << 2) // Details
-#define VERBOSE ( LOG_WARN )
+#define VERBOSE (LOG_WARN)
#include "logmacro.h"
+
// device type definition
DEFINE_DEVICE_TYPE(CASSETTE, cassette_image_device, "cassette_image", "Cassette")
@@ -26,14 +34,14 @@ DEFINE_DEVICE_TYPE(CASSETTE, cassette_image_device, "cassette_image", "Cassette"
// cassette_image_device - constructor
//-------------------------------------------------
-cassette_image_device::cassette_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, CASSETTE, tag, owner, clock),
+cassette_image_device::cassette_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, CASSETTE, tag, owner, clock),
device_image_interface(mconfig, *this),
device_sound_interface(mconfig, *this),
m_cassette(nullptr),
m_state(CASSETTE_STOPPED),
- m_position(0),
- m_position_time(0),
+ m_position(0.0),
+ m_position_time(0.0),
m_value(0),
m_channel(0),
m_speed(0),
@@ -63,8 +71,8 @@ cassette_image_device::~cassette_image_device()
void cassette_image_device::device_config_complete()
{
m_extension_list[0] = '\0';
- for (int i = 0; m_formats[i]; i++ )
- image_specify_extension( m_extension_list, 256, m_formats[i]->extensions );
+ for (int i = 0; m_formats[i]; i++)
+ image_specify_extension(m_extension_list, 256, m_formats[i]->extensions);
}
@@ -72,50 +80,41 @@ void cassette_image_device::device_config_complete()
cassette IO
*********************************************************************/
-bool cassette_image_device::is_motor_on()
-{
- if ((m_state & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED)
- return false;
- if ((m_state & CASSETTE_MASK_MOTOR) != CASSETTE_MOTOR_ENABLED)
- return false;
- else
- return true;
-}
-
-
-
void cassette_image_device::update()
{
double cur_time = machine().time().as_double();
- if (is_motor_on())
+ if (!is_stopped() && motor_on())
{
- double new_position = m_position + (cur_time - m_position_time)*m_speed*m_direction;
+ double new_position = m_position + (cur_time - m_position_time) * m_speed * m_direction;
- switch(m_state & CASSETTE_MASK_UISTATE)
+ switch (m_state & CASSETTE_MASK_UISTATE)
{
case CASSETTE_RECORD:
- cassette_put_sample(m_cassette, m_channel, m_position, new_position - m_position, m_value);
+ m_cassette->put_sample(m_channel, m_position, new_position - m_position, m_value);
break;
case CASSETTE_PLAY:
- if ( m_cassette )
+ if (m_cassette)
{
- cassette_get_sample(m_cassette, m_channel, new_position, 0.0, &m_value);
- /* See if reached end of tape */
+ m_cassette->get_sample(m_channel, new_position, 0.0, &m_value);
+ // See if reached end of tape
double length = get_length();
if (new_position > length)
{
- m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED);
+ m_state = (m_state & ~CASSETTE_MASK_UISTATE) | CASSETTE_STOPPED;
new_position = length;
}
- else if (new_position < 0)
+ else if (new_position < 0.0)
{
- m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED);
- new_position = 0;
+ m_state = (m_state & ~CASSETTE_MASK_UISTATE) | CASSETTE_STOPPED;
+ new_position = 0.0;
}
}
break;
+
+ default:
+ break;
}
m_position = new_position;
}
@@ -124,12 +123,17 @@ void cassette_image_device::update()
void cassette_image_device::change_state(cassette_state state, cassette_state mask)
{
- cassette_state new_state = m_state;
- new_state = (cassette_state)(new_state & ~mask);
- new_state = (cassette_state)(new_state | (state & mask));
- if ((m_state ^ new_state) & (CASSETTE_MASK_UISTATE | CASSETTE_MASK_MOTOR))
- m_position_time = machine().time().as_double();
- m_state = new_state;
+ cassette_state new_state;
+
+ new_state = m_state;
+ new_state &= ~mask;
+ new_state |= (state & mask);
+
+ if (new_state != m_state)
+ {
+ update();
+ m_state = new_state;
+ }
}
@@ -137,12 +141,11 @@ void cassette_image_device::change_state(cassette_state state, cassette_state ma
double cassette_image_device::input()
{
update();
- int32_t sample = m_value;
- double double_value = sample / ((double) 0x7FFFFFFF);
+ double value = m_value / (double(0x7fffffff));
- LOGMASKED(LOG_DETAIL, "cassette_input(): time_index=%g value=%g\n", m_position, double_value);
+ LOGMASKED(LOG_DETAIL, "cassette_input(): time_index=%g value=%g\n", m_position, value);
- return double_value;
+ return value;
}
@@ -153,26 +156,26 @@ void cassette_image_device::output(double value)
{
update();
- value = std::min(value, 1.0);
- value = std::max(value, -1.0);
-
- m_value = (int32_t) (value * 0x7FFFFFFF);
+ value = std::clamp(value, -1.0, 1.0);
+ m_value = int32_t(value * 0x7fffffff);
}
}
double cassette_image_device::get_position()
{
- return m_position;
+ double position = m_position;
+
+ if (!is_stopped() && motor_on())
+ position += (machine().time().as_double() - m_position_time) * m_speed * m_direction;
+ return position;
}
double cassette_image_device::get_length()
{
- struct CassetteInfo info;
-
- cassette_get_info(m_cassette, &info);
+ cassette_image::Info info = m_cassette->get_info();
return ((double) info.sample_count) / info.sample_frequency;
}
@@ -199,9 +202,12 @@ void cassette_image_device::go_reverse()
void cassette_image_device::seek(double time, int origin)
{
+ update();
+
double length = get_length();
- switch(origin) {
+ switch (origin)
+ {
case SEEK_SET:
break;
@@ -214,14 +220,8 @@ void cassette_image_device::seek(double time, int origin)
break;
}
- /* clip position into legal bounds */
- if (time < 0)
- time = 0;
- else
- if (time > length)
- time = length;
-
- m_position = time;
+ // clip position into legal bounds
+ m_position = std::clamp(time, 0.0, length);
}
@@ -230,38 +230,76 @@ void cassette_image_device::seek(double time, int origin)
cassette device init/load/unload/specify
*********************************************************************/
+// allow save_item on a non-fundamental type
+ALLOW_SAVE_TYPE(cassette_state);
+
void cassette_image_device::device_start()
{
- /* set to default state */
+ // set to default state
m_cassette = nullptr;
m_state = m_default_state;
m_value = 0;
- machine().sound().stream_alloc(*this, 0, (m_stereo? 2:1), machine().sample_rate());
+ stream_alloc(0, m_stereo ? 2 : 1, machine().sample_rate());
+
+ save_item(NAME(m_state));
+ save_item(NAME(m_position));
+ save_item(NAME(m_position_time));
+ save_item(NAME(m_value));
+ save_item(NAME(m_channel));
+ save_item(NAME(m_speed));
+ save_item(NAME(m_direction));
+}
+
+const software_list_loader &cassette_image_device::get_software_list_loader() const
+{
+ return image_software_list_loader::instance();
}
-image_init_result cassette_image_device::call_create(int format_type, util::option_resolution *format_options)
+std::pair<std::error_condition, std::string> cassette_image_device::call_create(int format_type, util::option_resolution *format_options)
{
- return internal_load(true);
+ return std::make_pair(internal_load(true), std::string());
}
-image_init_result cassette_image_device::call_load()
+std::pair<std::error_condition, std::string> cassette_image_device::call_load()
{
- return internal_load(false);
+ return std::make_pair(internal_load(false), std::string());
+}
+
+bool cassette_image_device::has_any_extension(std::string_view candidate_extensions) const
+{
+ const char separator = ',';
+ std::istringstream extension_stream(std::string{candidate_extensions});
+ for (std::string extension; std::getline(extension_stream, extension, separator);)
+ if (is_filetype(extension))
+ return true;
+
+ return false;
}
-image_init_result cassette_image_device::internal_load(bool is_create)
+std::error_condition cassette_image_device::internal_load(bool is_create)
{
cassette_image::error err;
device_image_interface *image = nullptr;
interface(image);
- if (is_create || (length()==0)) // empty existing images are fine to write over.
+ check_for_file();
+ if (is_create || (length() == 0)) // empty existing images are fine to write over.
{
- // creating an image
- err = cassette_create((void *)image, &image_ioprocs, &wavfile_format, m_create_opts, CASSETTE_FLAG_READWRITE|CASSETTE_FLAG_SAVEONEXIT, &m_cassette);
- if (err != cassette_image::error::SUCCESS)
- goto error;
+ auto io = util::random_read_write_fill(image_core_file(), 0x00);
+ if (io)
+ {
+ err = cassette_image::create(
+ std::move(io),
+ has_any_extension(cassette_image::flacfile_format.extensions) ? &cassette_image::flacfile_format : &cassette_image::wavfile_format,
+ m_create_opts,
+ cassette_image::FLAG_READWRITE|cassette_image::FLAG_SAVEONEXIT,
+ m_cassette);
+ }
+ else
+ {
+ err = cassette_image::error::OUT_OF_MEMORY;
+ }
}
else
{
@@ -272,11 +310,24 @@ image_init_result cassette_image_device::internal_load(bool is_create)
// we probably don't want to retry...
retry = false;
- // try opening the cassette
- int cassette_flags = is_readonly()
- ? CASSETTE_FLAG_READONLY
- : (CASSETTE_FLAG_READWRITE | CASSETTE_FLAG_SAVEONEXIT);
- err = cassette_open_choices((void *)image, &image_ioprocs, filetype(), m_formats, cassette_flags, &m_cassette);
+ auto io = util::random_read_write_fill(image_core_file(), 0x00);
+ if (io)
+ {
+ // try opening the cassette
+ int const cassette_flags = is_readonly()
+ ? cassette_image::FLAG_READONLY
+ : (cassette_image::FLAG_READWRITE | cassette_image::FLAG_SAVEONEXIT);
+ err = cassette_image::open_choices(
+ std::move(io),
+ filetype(),
+ m_formats,
+ cassette_flags,
+ m_cassette);
+ }
+ else
+ {
+ err = cassette_image::error::OUT_OF_MEMORY;
+ }
// special case - if we failed due to readwrite not being supported, make the image be read only and retry
if (err == cassette_image::error::READ_WRITE_UNSUPPORTED)
@@ -285,64 +336,62 @@ image_init_result cassette_image_device::internal_load(bool is_create)
retry = true;
}
}
- while(retry);
-
- if (err != cassette_image::error::SUCCESS)
- goto error;
+ while (retry);
}
- /* set to default state, but only change the UI state */
- //change_state(m_default_state, CASSETTE_MASK_UISTATE);
- m_state = m_default_state;
-
- /* reset the position */
- m_position = 0.0;
- m_position_time = machine().time().as_double();
+ if (err == cassette_image::error::SUCCESS)
+ {
+ // set to default state, but only change the UI state
+ change_state(m_default_state, CASSETTE_MASK_UISTATE);
- /* default channel to 0, speed multiplier to 1 */
- m_channel = 0;
- m_speed = 1;
- m_direction = 1;
+ // reset the position
+ m_position = 0.0;
+ m_position_time = machine().time().as_double();
- return image_init_result::PASS;
+ // default channel to 0, speed multiplier to 1
+ m_channel = 0;
+ m_speed = 1;
+ m_direction = 1;
-error:
- image_error_t imgerr = IMAGE_ERROR_UNSPECIFIED;
- switch(err)
+ return std::error_condition();
+ }
+ else
{
- case cassette_image::error::INTERNAL:
- imgerr = IMAGE_ERROR_INTERNAL;
- break;
- case cassette_image::error::UNSUPPORTED:
- imgerr = IMAGE_ERROR_UNSUPPORTED;
- break;
- case cassette_image::error::OUT_OF_MEMORY:
- imgerr = IMAGE_ERROR_OUTOFMEMORY;
- break;
- case cassette_image::error::INVALID_IMAGE:
- imgerr = IMAGE_ERROR_INVALIDIMAGE;
- break;
- default:
- imgerr = IMAGE_ERROR_UNSPECIFIED;
- break;
+ std::error_condition imgerr = image_error::UNSPECIFIED;
+ switch(err)
+ {
+ case cassette_image::error::INTERNAL:
+ imgerr = image_error::INTERNAL;
+ break;
+ case cassette_image::error::UNSUPPORTED:
+ imgerr = image_error::UNSUPPORTED;
+ break;
+ case cassette_image::error::OUT_OF_MEMORY:
+ imgerr = std::errc::not_enough_memory;
+ break;
+ case cassette_image::error::INVALID_IMAGE:
+ imgerr = image_error::INVALIDIMAGE;
+ break;
+ default:
+ imgerr = image_error::UNSPECIFIED;
+ break;
+ }
+ return imgerr;
}
- image->seterror(imgerr, "" );
- return image_init_result::FAIL;
}
void cassette_image_device::call_unload()
{
- /* if we are recording, write the value to the image */
+ // if we are recording, write the value to the image
if ((m_state & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD)
update();
- /* close out the cassette */
- cassette_close(m_cassette);
- m_cassette = nullptr;
+ // close out the cassette
+ m_cassette.reset();
- /* set to default state, but only change the UI state */
+ // set to default state, but only change the UI state
change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE);
}
@@ -359,24 +408,24 @@ std::string cassette_image_device::call_display()
std::string result;
// only show the image when a cassette is loaded and the motor is on
- if (exists() && is_motor_on())
+ if (exists() && !is_stopped() && motor_on())
{
static char const *const shapes[] = { u8"\u2500", u8"\u2572", u8"\u2502", u8"\u2571" };
// figure out where we are in the cassette
double position = get_position();
double length = get_length();
- cassette_state uistate = cassette_state(get_state() & CASSETTE_MASK_UISTATE);
+ cassette_state uistate = get_state() & CASSETTE_MASK_UISTATE;
// choose which frame of the animation we are at
- int n = (int(position) / ANIMATION_FPS) % ARRAY_LENGTH(shapes);
+ int n = (int(position) / ANIMATION_FPS) % std::size(shapes);
// play or record
const char *status_icon = (uistate == CASSETTE_PLAY)
- ? u8"\u25BA"
- : u8"\u25CF";
+ ? u8"\u25ba"
+ : u8"\u25cf";
- // Since you can have anything in a BDF file, we will use crude ascii characters instead
+ // create information string
result = string_format("%s %s %02d:%02d (%04d) [%02d:%02d (%04d)]",
shapes[n], // animation
status_icon, // play or record
@@ -386,6 +435,18 @@ std::string cassette_image_device::call_display()
((int)length / 60),
((int)length % 60),
(int)length);
+
+ // make sure tape stops at end when playing
+ if ((m_state & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY)
+ {
+ if (m_cassette)
+ {
+ if (get_position() > get_length())
+ {
+ m_state = ((m_state & ~CASSETTE_MASK_UISTATE) | CASSETTE_STOPPED);
+ }
+ }
+ }
}
return result;
}
@@ -394,37 +455,29 @@ std::string cassette_image_device::call_display()
// Cassette sound
//-------------------------------------------------
-void cassette_image_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void cassette_image_device::sound_stream_update(sound_stream &stream)
{
- stream_sample_t *left_buffer = outputs[0];
- stream_sample_t *right_buffer = nullptr;
-
- if (m_stereo)
- right_buffer = outputs[1];
-
- cassette_state state = get_state();
+ cassette_state state = get_state() & (CASSETTE_MASK_UISTATE | CASSETTE_MASK_MOTOR | CASSETTE_MASK_SPEAKER);
if (exists() && (state == (CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED)))
{
+ int samples = stream.samples();
cassette_image *cassette = get_image();
double time_index = get_position();
- double duration = ((double) samples) / machine().sample_rate();
+ double duration = ((double) samples) / stream.sample_rate();
- cassette_get_samples(cassette, 0, time_index, duration, samples, 2, left_buffer, CASSETTE_WAVEFORM_16BIT);
- if (m_stereo)
- cassette_get_samples(cassette, 1, time_index, duration, samples, 2, right_buffer, CASSETTE_WAVEFORM_16BIT);
+ if (m_samples.size() < samples)
+ m_samples.resize(samples);
- for (int i = samples - 1; i >= 0; i--)
+ const cassette_image::Info info = cassette->get_info();
+ for (int ch = 0; ch < stream.output_count(); ch++)
{
- left_buffer[i] = ((int16_t *) left_buffer)[i];
- if (m_stereo)
- right_buffer[i] = ((int16_t *) right_buffer)[i];
+ if (ch < info.channels)
+ cassette->get_samples(ch, time_index, duration, samples, 2, &m_samples[0], cassette_image::WAVEFORM_16BIT);
+ else
+ cassette->get_samples(0, time_index, duration, samples, 2, &m_samples[0], cassette_image::WAVEFORM_16BIT);
+ for (int sampindex = 0; sampindex < samples; sampindex++)
+ stream.put_int(ch, sampindex, m_samples[sampindex], 32768);
}
}
- else
- {
- memset(left_buffer, 0, sizeof(*left_buffer) * samples);
- if (m_stereo)
- memset(right_buffer, 0, sizeof(*right_buffer) * samples);
- }
}
diff --git a/src/devices/imagedev/cassette.h b/src/devices/imagedev/cassette.h
index aac43869d2a..88b63caf38b 100644
--- a/src/devices/imagedev/cassette.h
+++ b/src/devices/imagedev/cassette.h
@@ -8,33 +8,36 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_CASSETTE_H
-#define MAME_DEVICES_IMAGEDEV_CASSETTE_H
+#ifndef MAME_IMAGEDEV_CASSETTE_H
+#define MAME_IMAGEDEV_CASSETTE_H
+
+#pragma once
#include "formats/cassimg.h"
-#include "softlist_dev.h"
-enum cassette_state
+enum cassette_state : uint8_t
{
- /* this part of the state is controlled by the UI */
+ // this part of the state is controlled by the UI
CASSETTE_STOPPED = 0,
CASSETTE_PLAY = 1,
CASSETTE_RECORD = 2,
- /* this part of the state is controlled by drivers */
+ // this part of the state is controlled by drivers
CASSETTE_MOTOR_ENABLED = 0,
CASSETTE_MOTOR_DISABLED = 4,
CASSETTE_SPEAKER_ENABLED = 0,
CASSETTE_SPEAKER_MUTED = 8,
- /* masks */
+ // masks
CASSETTE_MASK_UISTATE = 3,
CASSETTE_MASK_MOTOR = 4,
CASSETTE_MASK_SPEAKER = 8,
CASSETTE_MASK_DRVSTATE = 12
};
+DECLARE_ENUM_BITWISE_OPERATORS(cassette_state)
+
/***************************************************************************
TYPE DEFINITIONS
@@ -51,38 +54,46 @@ public:
cassette_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual ~cassette_image_device();
- void set_formats(const struct CassetteFormat* const *formats) { m_formats = formats; }
- void set_create_opts(const struct CassetteOptions *create_opts) { m_create_opts = create_opts; }
+ void set_formats(const cassette_image::Format* const *formats) { m_formats = formats; }
+ void set_create_opts(const cassette_image::Options *create_opts) { m_create_opts = create_opts; }
void set_default_state(cassette_state default_state) { m_default_state = default_state; }
- void set_default_state(int default_state) { m_default_state = (cassette_state)default_state; }
void set_interface(const char *interface) { m_interface = interface; }
- // image-level overrides
- virtual image_init_result call_load() override;
- virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
virtual void call_unload() override;
virtual std::string call_display() override;
- virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); }
- virtual iodevice_t image_type() const override { return IO_CASSETTE; }
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return true; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual bool support_command_line_image_creation() const noexcept override { return true; }
+ virtual const char *image_interface() const noexcept override { return m_interface; }
+ virtual const char *file_extensions() const noexcept override { return m_extension_list; }
+ virtual const char *image_type_name() const noexcept override { return "cassette"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "cass"; }
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 1; }
- virtual bool is_creatable() const override { return 1; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override { return m_interface; }
- virtual const char *file_extensions() const override { return m_extension_list; }
+ double input();
+ void output(double value);
// specific implementation
cassette_state get_state() { return m_state; }
- void set_state(cassette_state state) { change_state(state, (cassette_state)(~0)); }
+ void set_state(cassette_state state) { change_state(state, cassette_state(~0)); }
void change_state(cassette_state state, cassette_state mask);
- double input();
- void output(double value);
+ // state getters/setters
+ bool is_stopped() { return (m_state & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED; }
+ bool is_playing() { return (m_state & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY; }
+ bool is_recording() { return (m_state & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD; }
- cassette_image *get_image() { return m_cassette; }
+ void set_motor(bool state) { change_state(state ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); } // aka remote control
+ bool motor_on() { return (m_state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_ENABLED; }
+ void set_speaker(bool state) { change_state(state ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER); }
+ bool speaker_on() { return (m_state & CASSETTE_MASK_SPEAKER) == CASSETTE_SPEAKER_ENABLED; }
+
+ cassette_image *get_image() { return m_cassette.get(); }
double get_position();
double get_length();
void set_speed(double speed);
@@ -92,41 +103,45 @@ public:
void seek(double time, int origin);
// sound stream update overrides
- void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream) override;
device_sound_interface& set_stereo() { m_stereo = true; return *this; }
protected:
- bool is_motor_on();
- void update();
-
- // device-level overrides
+ // device_t implementation
virtual void device_config_complete() override;
- virtual void device_start() override;
- virtual const bool use_software_list_file_extension_for_filetype() const override { return true; }
+ virtual void device_start() override ATTR_COLD;
+ virtual bool use_software_list_file_extension_for_filetype() const noexcept override { return true; }
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override;
+
+ void update();
private:
- cassette_image *m_cassette;
+ cassette_image::ptr m_cassette;
cassette_state m_state;
double m_position;
double m_position_time;
- int32_t m_value;
+ int32_t m_value;
int m_channel;
double m_speed; // speed multiplier for tape speeds other than standard 1.875ips (used in adam driver)
int m_direction; // direction select
char m_extension_list[256];
- const struct CassetteFormat* const *m_formats;
- const struct CassetteOptions *m_create_opts;
- cassette_state m_default_state;
- const char * m_interface;
+ const cassette_image::Format* const *m_formats;
+ const cassette_image::Options *m_create_opts;
+ cassette_state m_default_state;
+ const char * m_interface;
- image_init_result internal_load(bool is_create);
+ std::error_condition internal_load(bool is_create);
+ bool has_any_extension(std::string_view candidate_extensions) const;
bool m_stereo;
+ std::vector<s16> m_samples;
};
// device type definition
DECLARE_DEVICE_TYPE(CASSETTE, cassette_image_device)
// device iterator
-typedef device_type_iterator<cassette_image_device> cassette_device_iterator;
+typedef device_type_enumerator<cassette_image_device> cassette_device_enumerator;
-#endif // MAME_DEVICES_IMAGEDEV_CASSETTE_H
+#endif // MAME_IMAGEDEV_CASSETTE_H
diff --git a/src/devices/imagedev/cdromimg.cpp b/src/devices/imagedev/cdromimg.cpp
new file mode 100644
index 00000000000..b4deb9fc4ad
--- /dev/null
+++ b/src/devices/imagedev/cdromimg.cpp
@@ -0,0 +1,283 @@
+// license:BSD-3-Clause
+// copyright-holders:Nathan Woods, R. Belmont, Miodrag Milanovic
+/*********************************************************************
+
+ CD/DVD reader
+
+*********************************************************************/
+
+#include "emu.h"
+#include "cdromimg.h"
+
+#include "romload.h"
+
+// device type definition
+DEFINE_DEVICE_TYPE(CDROM, cdrom_image_device, "cdrom_image", "CD-ROM Image")
+DEFINE_DEVICE_TYPE(GDROM, gdrom_image_device, "gdrom_image", "CD/GD-ROM Image")
+DEFINE_DEVICE_TYPE(DVDROM, dvdrom_image_device, "dvdrom_image", "CD/DVD-ROM Image")
+
+//-------------------------------------------------
+// cdrom_image_device - constructor
+//-------------------------------------------------
+
+cdrom_image_device::cdrom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : cdrom_image_device(mconfig, CDROM, tag, owner, clock)
+{
+}
+
+cdrom_image_device::cdrom_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool dvd_compat, bool gd_compat)
+ : device_t(mconfig, type, tag, owner, clock),
+ device_image_interface(mconfig, *this),
+ m_gd_compat(gd_compat),
+ m_dvd_compat(dvd_compat),
+ m_cdrom_handle(nullptr),
+ m_dvdrom_handle(nullptr),
+ m_extension_list(nullptr),
+ m_interface(nullptr)
+{
+}
+
+//-------------------------------------------------
+// cdrom_image_device - destructor
+//-------------------------------------------------
+
+cdrom_image_device::~cdrom_image_device()
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cdrom_image_device::device_config_complete()
+{
+ m_extension_list = "chd,cue,toc,nrg,gdi,iso,cdr";
+
+ add_format("chdcd", m_dvd_compat ? "CD/DVD-ROM drive" : "CD-ROM drive", m_extension_list, "");
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cdrom_image_device::device_start()
+{
+ if (has_preset_images())
+ setup_current_preset_image();
+ else
+ {
+ m_cdrom_handle.reset();
+ m_dvdrom_handle.reset();
+ }
+}
+
+void cdrom_image_device::setup_current_preset_image()
+{
+ m_cdrom_handle.reset();
+ m_dvdrom_handle.reset();
+
+ chd_file *chd = current_preset_image_chd();
+ if (!chd->check_is_cd() || (m_gd_compat && !chd->check_is_gd()))
+ m_cdrom_handle = std::make_unique<cdrom_file>(chd);
+ else if(m_dvd_compat && !chd->check_is_dvd())
+ m_dvdrom_handle = std::make_unique<dvdrom_file>(chd);
+ else
+ fatalerror("chd for region %s is not compatible with the cdrom image device\n", preset_images_list()[current_preset_image_id()]);
+}
+
+void cdrom_image_device::device_stop()
+{
+ m_cdrom_handle.reset();
+ m_dvdrom_handle.reset();
+ if (m_self_chd.opened())
+ m_self_chd.close();
+}
+
+std::pair<std::error_condition, std::string> cdrom_image_device::call_load()
+{
+ if (has_preset_images())
+ {
+ setup_current_preset_image();
+ return std::make_pair(image_error(0), std::string());
+ }
+
+ std::error_condition err;
+ chd_file *chd = nullptr;
+
+ m_cdrom_handle.reset();
+ m_dvdrom_handle.reset();
+
+ if (!loaded_through_softlist())
+ {
+ if (is_filetype("chd") && is_loaded())
+ {
+ util::core_file::ptr proxy;
+ err = util::core_file::open_proxy(image_core_file(), proxy);
+ if (!err)
+ err = m_self_chd.open(std::move(proxy)); // CDs are never writeable
+ if (err)
+ goto error;
+ chd = &m_self_chd;
+ }
+ }
+ else
+ {
+ chd = device().machine().rom_load().get_disk_handle(device().subtag("cdrom"));
+ }
+
+ // open the CHD file
+ if (chd)
+ {
+ err = chd->check_is_cd();
+ if (err == chd_file::error::METADATA_NOT_FOUND && m_gd_compat)
+ err = chd->check_is_gd();
+ if (!err)
+ {
+ m_cdrom_handle.reset(new cdrom_file(chd));
+ return std::make_pair(std::error_condition(), std::string());
+ }
+ if (err != chd_file::error::METADATA_NOT_FOUND)
+ goto error;
+
+ if (m_dvd_compat)
+ {
+ err = chd->check_is_dvd();
+ if (!err)
+ {
+ m_dvdrom_handle.reset(new dvdrom_file(chd));
+ return std::make_pair(std::error_condition(), std::string());
+ }
+ if (err != chd_file::error::METADATA_NOT_FOUND)
+ goto error;
+ }
+
+ err = image_error::INVALIDIMAGE;
+ goto error;
+ }
+ else
+ {
+ try
+ {
+ m_cdrom_handle.reset(new cdrom_file(filename()));
+ }
+ catch (...)
+ {
+ try
+ {
+ m_dvdrom_handle.reset(new dvdrom_file(filename()));
+ }
+ catch (...)
+ {
+ err = image_error::INVALIDIMAGE;
+ goto error;
+ }
+ }
+ }
+
+ return std::make_pair(std::error_condition(), std::string());
+
+error:
+ if (chd && chd == &m_self_chd)
+ m_self_chd.close();
+ return std::make_pair(err ? err : image_error::UNSPECIFIED, std::string());
+}
+
+void cdrom_image_device::call_unload()
+{
+ assert(m_cdrom_handle || m_dvdrom_handle);
+ m_cdrom_handle.reset();
+ m_dvdrom_handle.reset();
+ if (m_self_chd.opened())
+ m_self_chd.close();
+}
+
+int cdrom_image_device::get_last_track() const
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->get_last_track();
+ return 0;
+}
+
+int cdrom_image_device::get_last_session() const
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->get_last_session();
+ return 0;
+}
+
+uint32_t cdrom_image_device::get_track(uint32_t frame) const
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->get_track(frame);
+ return 0;
+}
+
+uint32_t cdrom_image_device::get_track_index(uint32_t frame) const
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->get_track_index(frame);
+ return 0;
+}
+
+uint32_t cdrom_image_device::get_track_start(uint32_t track) const
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->get_track_start(track);
+ return 0;
+}
+
+bool cdrom_image_device::read_data(uint32_t lbasector, void *buffer, uint32_t datatype, bool phys)
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->read_data(lbasector, buffer, datatype, phys);
+ if (m_dvdrom_handle)
+ return !m_dvdrom_handle->read_data(lbasector, buffer);
+ return 0;
+}
+
+bool cdrom_image_device::read_subcode(uint32_t lbasector, void *buffer, bool phys)
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->read_subcode(lbasector, buffer, phys);
+ return 0;
+}
+
+int cdrom_image_device::get_adr_control(int track) const
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->get_adr_control(track);
+ return 0;
+}
+
+const cdrom_file::toc &cdrom_image_device::get_toc() const
+{
+ static cdrom_file::toc notoc;
+ if (m_cdrom_handle)
+ return m_cdrom_handle->get_toc();
+ return notoc;
+}
+
+int cdrom_image_device::get_track_type(int track) const
+{
+ if (m_cdrom_handle)
+ return m_cdrom_handle->get_track_type(track);
+ return 0;
+}
+
+bool cdrom_image_device::is_cd() const
+{
+ return m_cdrom_handle != nullptr;
+}
+
+bool cdrom_image_device::is_gd() const
+{
+ return m_cdrom_handle && m_cdrom_handle->is_gdrom();
+}
+
+bool cdrom_image_device::is_dvd() const
+{
+ return m_dvdrom_handle != nullptr;
+}
+
diff --git a/src/devices/imagedev/cdromimg.h b/src/devices/imagedev/cdromimg.h
new file mode 100644
index 00000000000..e7d9feaa62d
--- /dev/null
+++ b/src/devices/imagedev/cdromimg.h
@@ -0,0 +1,117 @@
+// license:BSD-3-Clause
+// copyright-holders:Nathan Woods, R. Belmont, Miodrag Milanovic
+/*********************************************************************
+
+ cdromimg.h
+
+ CD/DVD reader
+
+*********************************************************************/
+
+#ifndef MAME_IMAGEDEV_CDROMIMG_H
+#define MAME_IMAGEDEV_CDROMIMG_H
+
+#pragma once
+
+#include "softlist_dev.h"
+
+#include "cdrom.h"
+#include "dvdrom.h"
+
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+// device type definition
+DECLARE_DEVICE_TYPE(CDROM, cdrom_image_device)
+DECLARE_DEVICE_TYPE(GDROM, gdrom_image_device) // Includes CDROM compatibility (but not DVDROM)
+DECLARE_DEVICE_TYPE(DVDROM, dvdrom_image_device) // Includes CDROM compatibility (but not GDROM)
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> cdrom_image_device
+
+class cdrom_image_device : public device_t,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ cdrom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ virtual ~cdrom_image_device();
+
+ void set_interface(const char *interface) { m_interface = interface; }
+
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual void call_unload() override;
+
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return false; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *image_interface() const noexcept override { return m_interface; }
+ virtual const char *file_extensions() const noexcept override { return m_extension_list; }
+ virtual const char *image_type_name() const noexcept override { return "cdrom"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "cdrm"; }
+
+ int get_last_track() const;
+ int get_last_session() const;
+ uint32_t get_track(uint32_t frame) const;
+ uint32_t get_track_index(uint32_t frame) const;
+ uint32_t get_track_start(uint32_t track) const;
+ bool read_data(uint32_t lbasector, void *buffer, uint32_t datatype, bool phys=false);
+ bool read_subcode(uint32_t lbasector, void *buffer, bool phys=false);
+ int get_adr_control(int track) const;
+ const cdrom_file::toc &get_toc() const;
+ int get_track_type(int track) const;
+
+ bool is_cd() const;
+ bool is_gd() const;
+ bool is_dvd() const;
+
+protected:
+ cdrom_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool dvd_compat = false, bool gd_compat = false);
+
+ // device_t implementation
+ virtual void device_config_complete() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_stop() override ATTR_COLD;
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
+
+ void setup_current_preset_image();
+
+ bool m_gd_compat;
+ bool m_dvd_compat;
+ chd_file m_self_chd;
+ std::unique_ptr<cdrom_file> m_cdrom_handle;
+ std::unique_ptr<dvdrom_file> m_dvdrom_handle;
+ const char *m_extension_list;
+ const char *m_interface;
+};
+
+class gdrom_image_device : public cdrom_image_device
+{
+public:
+ // construction/destruction
+ gdrom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) :
+ cdrom_image_device(mconfig, GDROM, tag, owner, clock, false, true) {}
+ virtual ~gdrom_image_device() = default;
+};
+
+class dvdrom_image_device : public cdrom_image_device
+{
+public:
+ // construction/destruction
+ dvdrom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) :
+ cdrom_image_device(mconfig, DVDROM, tag, owner, clock, true, false) {}
+ virtual ~dvdrom_image_device() = default;
+};
+
+
+#endif // MAME_IMAGEDEV_CDROMIMG_H
diff --git a/src/devices/imagedev/chd_cd.cpp b/src/devices/imagedev/chd_cd.cpp
deleted file mode 100644
index 5daaba2ed45..00000000000
--- a/src/devices/imagedev/chd_cd.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Nathan Woods, R. Belmont, Miodrag Milanovic
-/*********************************************************************
-
- Code to interface the image code with CHD-CD core.
-
- Based on harddriv.c by Raphael Nabet 2003
-
-*********************************************************************/
-
-#include "emu.h"
-#include "chd_cd.h"
-
-#include "cdrom.h"
-#include "romload.h"
-
-// device type definition
-DEFINE_DEVICE_TYPE(CDROM, cdrom_image_device, "cdrom_image", "CD-ROM Image")
-
-//-------------------------------------------------
-// cdrom_image_device - constructor
-//-------------------------------------------------
-
-cdrom_image_device::cdrom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : cdrom_image_device(mconfig, CDROM, tag, owner, clock)
-{
-}
-
-cdrom_image_device::cdrom_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- device_image_interface(mconfig, *this),
- m_cdrom_handle(nullptr),
- m_extension_list(nullptr),
- m_interface(nullptr)
-{
-}
-//-------------------------------------------------
-// cdrom_image_device - destructor
-//-------------------------------------------------
-
-cdrom_image_device::~cdrom_image_device()
-{
-}
-
-//-------------------------------------------------
-// device_config_complete - perform any
-// operations now that the configuration is
-// complete
-//-------------------------------------------------
-
-void cdrom_image_device::device_config_complete()
-{
- m_extension_list = "chd,cue,toc,nrg,gdi,iso,cdr";
-
- add_format("chdcd", "CD-ROM drive", m_extension_list, "");
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void cdrom_image_device::device_start()
-{
- // try to locate the CHD from a DISK_REGION
- chd_file *chd = machine().rom_load().get_disk_handle(owner()->tag() );
- if( chd != nullptr )
- {
- m_cdrom_handle = cdrom_open( chd );
- }
- else
- {
- m_cdrom_handle = nullptr;
- }
-}
-
-void cdrom_image_device::device_stop()
-{
- if (m_cdrom_handle)
- cdrom_close(m_cdrom_handle);
- if( m_self_chd.opened() )
- m_self_chd.close();
-}
-
-image_init_result cdrom_image_device::call_load()
-{
- chd_error err = (chd_error)0;
- chd_file *chd = nullptr;
-
- if (m_cdrom_handle)
- cdrom_close(m_cdrom_handle);
-
- if (!loaded_through_softlist())
- {
- if (is_filetype("chd") && is_loaded()) {
- err = m_self_chd.open( image_core_file() ); /* CDs are never writeable */
- if ( err )
- goto error;
- chd = &m_self_chd;
- }
- } else {
- chd = device().machine().rom_load().get_disk_handle(device().subtag("cdrom").c_str());
- }
-
- /* open the CHD file */
- if (chd) {
- m_cdrom_handle = cdrom_open( chd );
- } else {
- m_cdrom_handle = cdrom_open(filename());
- }
- if ( ! m_cdrom_handle )
- goto error;
-
- return image_init_result::PASS;
-
-error:
- if ( chd && chd == &m_self_chd )
- m_self_chd.close( );
- if ( err )
- seterror( IMAGE_ERROR_UNSPECIFIED, chd_file::error_string( err ) );
- return image_init_result::FAIL;
-}
-
-void cdrom_image_device::call_unload()
-{
- assert(m_cdrom_handle);
- cdrom_close(m_cdrom_handle);
- m_cdrom_handle = nullptr;
- if( m_self_chd.opened() )
- m_self_chd.close();
-}
diff --git a/src/devices/imagedev/chd_cd.h b/src/devices/imagedev/chd_cd.h
deleted file mode 100644
index e3e980d9ea9..00000000000
--- a/src/devices/imagedev/chd_cd.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Nathan Woods, R. Belmont, Miodrag Milanovic
-/*********************************************************************
-
- chd_cd.h
-
- Interface to the CHD CDROM code
-
-*********************************************************************/
-
-#ifndef MAME_DEVICES_IMAGEDEV_CHD_CD_H
-#define MAME_DEVICES_IMAGEDEV_CHD_CD_H
-
-#pragma once
-
-#include "cdrom.h"
-#include "softlist_dev.h"
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-// ======================> cdrom_image_device
-
-class cdrom_image_device : public device_t,
- public device_image_interface
-{
-public:
- // construction/destruction
- cdrom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- virtual ~cdrom_image_device();
-
- void set_interface(const char *interface) { m_interface = interface; }
-
- // image-level overrides
- virtual image_init_result call_load() override;
- virtual void call_unload() override;
- virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
-
- virtual iodevice_t image_type() const override { return IO_CDROM; }
-
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 0; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override { return m_interface; }
- virtual const char *file_extensions() const override { return m_extension_list; }
-
- // specific implementation
- cdrom_file *get_cdrom_file() { return m_cdrom_handle; }
-
-protected:
- cdrom_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
-
- // device-level overrides
- virtual void device_config_complete() override;
- virtual void device_start() override;
- virtual void device_stop() override;
-
- chd_file m_self_chd;
- cdrom_file *m_cdrom_handle;
- const char *m_extension_list;
- const char *m_interface;
-};
-
-// device type definition
-DECLARE_DEVICE_TYPE(CDROM, cdrom_image_device)
-
-#endif // MAME_DEVICES_IMAGEDEV_CHD_CD_H
diff --git a/src/devices/imagedev/diablo.cpp b/src/devices/imagedev/diablo.cpp
index f7da6fa26cb..46f60fe70d2 100644
--- a/src/devices/imagedev/diablo.cpp
+++ b/src/devices/imagedev/diablo.cpp
@@ -8,9 +8,12 @@
#include "diablo.h"
#include "emuopts.h"
+#include "fileio.h"
#include "harddisk.h"
#include "romload.h"
+#include "opresolv.h"
+
OPTION_GUIDE_START(dsk_option_guide)
OPTION_INT('C', "cylinders", "Cylinders")
@@ -32,13 +35,12 @@ DEFINE_DEVICE_TYPE(DIABLO, diablo_image_device, "diablo_image", "Diablo")
//-------------------------------------------------
diablo_image_device::diablo_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, DIABLO, tag, owner, clock),
- device_image_interface(mconfig, *this),
- m_chd(nullptr),
- m_hard_disk_handle(nullptr),
- m_device_image_load(load_delegate()),
- m_device_image_unload(unload_delegate()),
- m_interface(nullptr)
+ : harddisk_image_base_device(mconfig, DIABLO, tag, owner, clock)
+ , m_chd(nullptr)
+ , m_hard_disk_handle()
+ , m_device_image_load(*this)
+ , m_device_image_unload(*this)
+ , m_interface(nullptr)
{
}
@@ -72,29 +74,27 @@ const util::option_guide &diablo_image_device::create_option_guide() const
void diablo_image_device::device_start()
{
+ m_device_image_load.resolve();
+ m_device_image_unload.resolve();
+
m_chd = nullptr;
// try to locate the CHD from a DISK_REGION
chd_file *handle = machine().rom_load().get_disk_handle(tag());
- if (handle != nullptr)
- {
- m_hard_disk_handle = hard_disk_open(handle);
- }
+ if (handle)
+ m_hard_disk_handle.reset(new hard_disk_file(handle));
else
- {
- m_hard_disk_handle = nullptr;
- }
+ m_hard_disk_handle.reset();
}
void diablo_image_device::device_stop()
{
- if (m_hard_disk_handle)
- hard_disk_close(m_hard_disk_handle);
+ m_hard_disk_handle.reset();
}
-image_init_result diablo_image_device::call_load()
+std::pair<std::error_condition, std::string> diablo_image_device::call_load()
{
- image_init_result our_result;
+ std::error_condition our_result;
our_result = internal_load_dsk();
/* Check if there is an image_load callback defined */
@@ -103,14 +103,12 @@ image_init_result diablo_image_device::call_load()
/* Let the override do some additional work/checks */
our_result = m_device_image_load(*this);
}
- return our_result;
+ return std::make_pair(our_result, std::string());
}
-image_init_result diablo_image_device::call_create(int create_format, util::option_resolution *create_args)
+std::pair<std::error_condition, std::string> diablo_image_device::call_create(int create_format, util::option_resolution *create_args)
{
- int err;
-
if (!create_args)
throw emu_fatalerror("diablo_image_device::call_create: Expected create_args to not be nullptr");
@@ -124,33 +122,30 @@ image_init_result diablo_image_device::call_create(int create_format, util::opti
/* create the CHD file */
chd_codec_type compression[4] = { CHD_CODEC_NONE };
- err = m_origchd.create(image_core_file(), (uint64_t)totalsectors * (uint64_t)sectorsize, hunksize, sectorsize, compression);
- if (err != CHDERR_NONE)
- return image_init_result::FAIL;
+ util::core_file::ptr proxy;
+ std::error_condition err = util::core_file::open_proxy(image_core_file(), proxy);
+ if (!err)
+ m_origchd.create(std::move(proxy), uint64_t(totalsectors) * uint64_t(sectorsize), hunksize, sectorsize, compression);
+ if (err)
+ return std::make_pair(err, std::string());
/* if we created the image and hence, have metadata to set, set the metadata */
err = m_origchd.write_metadata(HARD_DISK_METADATA_TAG, 0, string_format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize));
m_origchd.close();
- if (err != CHDERR_NONE)
- return image_init_result::FAIL;
+ if (err)
+ return std::make_pair(err, std::string());
- return internal_load_dsk();
+ return std::make_pair(internal_load_dsk(), std::string());
}
void diablo_image_device::call_unload()
{
- /* Check if there is an image_unload callback defined */
- if ( !m_device_image_unload.isnull() )
- {
+ // Check if there is an image_unload callback defined
+ if (!m_device_image_unload.isnull())
m_device_image_unload(*this);
- }
- if (m_hard_disk_handle != nullptr)
- {
- hard_disk_close(m_hard_disk_handle);
- m_hard_disk_handle = nullptr;
- }
+ m_hard_disk_handle.reset();
m_origchd.close();
m_diffchd.close();
@@ -161,28 +156,28 @@ void diablo_image_device::call_unload()
open_disk_diff - open a DISK diff file
-------------------------------------------------*/
-static chd_error open_disk_diff(emu_options &options, const char *name, chd_file &source, chd_file &diff_chd)
+static std::error_condition open_disk_diff(emu_options &options, const char *name, chd_file &source, chd_file &diff_chd)
{
std::string fname = std::string(name).append(".dif");
/* try to open the diff */
//printf("Opening differencing image file: %s\n", fname.c_str());
emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE);
- osd_file::error filerr = diff_file.open(fname.c_str());
- if (filerr == osd_file::error::NONE)
+ std::error_condition filerr = diff_file.open(fname);
+ if (!filerr)
{
std::string fullpath(diff_file.fullpath());
diff_file.close();
//printf("Opening differencing image file: %s\n", fullpath.c_str());
- return diff_chd.open(fullpath.c_str(), true, &source);
+ return diff_chd.open(fullpath, true, &source);
}
/* didn't work; try creating it instead */
//printf("Creating differencing image: %s\n", fname.c_str());
diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- filerr = diff_file.open(fname.c_str());
- if (filerr == osd_file::error::NONE)
+ filerr = diff_file.open(fname);
+ if (!filerr)
{
std::string fullpath(diff_file.fullpath());
diff_file.close();
@@ -190,44 +185,48 @@ static chd_error open_disk_diff(emu_options &options, const char *name, chd_file
/* create the CHD */
//printf("Creating differencing image file: %s\n", fullpath.c_str());
chd_codec_type compression[4] = { CHD_CODEC_NONE };
- chd_error err = diff_chd.create(fullpath.c_str(), source.logical_bytes(), source.hunk_bytes(), compression, source);
- if (err != CHDERR_NONE)
+ std::error_condition err = diff_chd.create(fullpath, source.logical_bytes(), source.hunk_bytes(), compression, source);
+ if (err)
return err;
return diff_chd.clone_all_metadata(source);
}
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
-image_init_result diablo_image_device::internal_load_dsk()
+std::error_condition diablo_image_device::internal_load_dsk()
{
- chd_error err = CHDERR_NONE;
+ std::error_condition err;
m_chd = nullptr;
- if (m_hard_disk_handle)
- hard_disk_close(m_hard_disk_handle);
+ m_hard_disk_handle.reset();
- /* open the CHD file */
+ // open the CHD file
if (loaded_through_softlist())
{
m_chd = device().machine().rom_load().get_disk_handle(device().subtag("harddriv").c_str());
}
else
{
- err = m_origchd.open(image_core_file(), true);
- if (err == CHDERR_NONE)
+ util::core_file::ptr proxy;
+ err = util::core_file::open_proxy(image_core_file(), proxy);
+ if (!err)
+ err = m_origchd.open(std::move(proxy), true);
+ if (!err)
{
m_chd = &m_origchd;
}
- else if (err == CHDERR_FILE_NOT_WRITEABLE)
+ else if (err == chd_file::error::FILE_NOT_WRITEABLE)
{
- err = m_origchd.open(image_core_file(), false);
- if (err == CHDERR_NONE)
+ err = util::core_file::open_proxy(image_core_file(), proxy);
+ if (!err)
+ err = m_origchd.open(std::move(proxy), false);
+ if (!err)
{
err = open_disk_diff(device().machine().options(), basename_noext(), m_origchd, m_diffchd);
- if (err == CHDERR_NONE)
+ if (!err)
{
m_chd = &m_diffchd;
}
@@ -235,35 +234,18 @@ image_init_result diablo_image_device::internal_load_dsk()
}
}
- if (m_chd != nullptr)
+ if (m_chd)
{
- /* open the hard disk file */
- m_hard_disk_handle = hard_disk_open(m_chd);
- if (m_hard_disk_handle != nullptr)
- return image_init_result::PASS;
+ // open the hard disk file
+ m_hard_disk_handle.reset(new hard_disk_file(m_chd));
+ if (m_hard_disk_handle)
+ return std::error_condition();
}
- /* if we had an error, close out the CHD */
+ // if we had an error, close out the CHD
m_origchd.close();
m_diffchd.close();
m_chd = nullptr;
- seterror(IMAGE_ERROR_UNSPECIFIED, chd_file::error_string(err));
- return image_init_result::FAIL;
-}
-
-/*************************************
- *
- * Get the CHD file (from the src/chd.c core)
- * after an image has been opened with the hd core
- *
- *************************************/
-
-chd_file *diablo_image_device::get_chd_file()
-{
- chd_file *result = nullptr;
- hard_disk_file *hd_file = get_hard_disk_file();
- if (hd_file)
- result = hard_disk_get_chd(hd_file);
- return result;
+ return err ? err : image_error::UNSPECIFIED;
}
diff --git a/src/devices/imagedev/diablo.h b/src/devices/imagedev/diablo.h
index a83d8bc30b7..c4b6e9408cf 100644
--- a/src/devices/imagedev/diablo.h
+++ b/src/devices/imagedev/diablo.h
@@ -4,14 +4,21 @@
* DIABLO drive image to hard disk interface
**********************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_DIABLO_H
-#define MAME_DEVICES_IMAGEDEV_DIABLO_H
+#ifndef MAME_IMAGEDEV_DIABLO_H
+#define MAME_IMAGEDEV_DIABLO_H
#pragma once
-#include "harddisk.h"
#include "softlist_dev.h"
+#include "harddriv.h"
+
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+
#define DIABLO_TAG(id) "diablo"#id
/***************************************************************************
@@ -20,9 +27,12 @@
// ======================> diablo_image_device
-class diablo_image_device : public device_t, public device_image_interface
+class diablo_image_device : public harddisk_image_base_device
{
public:
+ typedef device_delegate<std::error_condition (device_image_interface &)> load_delegate;
+ typedef device_delegate<void (device_image_interface &)> unload_delegate;
+
// construction/destruction
diablo_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual ~diablo_image_device();
@@ -31,39 +41,34 @@ public:
template <typename Object> void set_device_unload(Object &&cb) { m_device_image_unload = std::forward<Object>(cb); }
void set_interface(const char *interface) { m_interface = interface; }
- // image-level overrides
- virtual image_init_result call_load() override;
- virtual image_init_result call_create(int create_format, util::option_resolution *create_args) override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int create_format, util::option_resolution *create_args) override;
virtual void call_unload() override;
- virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
-
- virtual iodevice_t image_type() const override { return IO_HARDDISK; }
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 1; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override { return m_interface; }
- virtual const char *file_extensions() const override { return "chd,dsk"; }
+ virtual bool image_is_chd_type() const noexcept override { return true; }
+ virtual const char *image_interface() const noexcept override { return m_interface; }
+ virtual const char *file_extensions() const noexcept override { return "chd,dsk"; }
virtual const util::option_guide &create_option_guide() const override;
// specific implementation
- hard_disk_file *get_hard_disk_file() { return m_hard_disk_handle; }
- chd_file *get_chd_file();
+ hard_disk_file *get_hard_disk_file() { return m_hard_disk_handle.get(); }
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_config_complete() override;
- virtual void device_start() override;
- virtual void device_stop() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_stop() override ATTR_COLD;
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
- image_init_result internal_load_dsk();
+ std::error_condition internal_load_dsk();
chd_file *m_chd;
- chd_file m_origchd; /* handle to the original CHD */
- chd_file m_diffchd; /* handle to the diff CHD */
- hard_disk_file *m_hard_disk_handle;
+ chd_file m_origchd; // handle to the original CHD
+ chd_file m_diffchd; // handle to the diff CHD
+ std::unique_ptr<hard_disk_file> m_hard_disk_handle;
load_delegate m_device_image_load;
unload_delegate m_device_image_unload;
@@ -73,4 +78,4 @@ protected:
// device type definition
DECLARE_DEVICE_TYPE(DIABLO, diablo_image_device)
-#endif // MAME_DEVICES_IMAGEDEV_DIABLO_H
+#endif // MAME_IMAGEDEV_DIABLO_H
diff --git a/src/devices/imagedev/flopdrv.cpp b/src/devices/imagedev/flopdrv.cpp
index bf42b1070ea..9f1e2ff0c96 100644
--- a/src/devices/imagedev/flopdrv.cpp
+++ b/src/devices/imagedev/flopdrv.cpp
@@ -14,17 +14,23 @@
*/
#include "emu.h"
-#include "formats/imageutl.h"
#include "flopdrv.h"
-#define VERBOSE 0
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+#include "softlist_dev.h"
+
+#include "formats/imageutl.h"
+
+#include "util/ioprocs.h"
+#include "util/ioprocsfilter.h"
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
/***************************************************************************
CONSTANTS
***************************************************************************/
-#define FLOPDRVTAG "flopdrv"
#define LOG_FLOPPY 0
/***************************************************************************
@@ -34,8 +40,7 @@
struct floppy_error_map
{
floperr_t ferr;
- image_error_t ierr;
- const char *message;
+ std::error_condition ierr;
};
@@ -46,64 +51,23 @@ struct floppy_error_map
static const floppy_error_map errmap[] =
{
- { FLOPPY_ERROR_SUCCESS, IMAGE_ERROR_SUCCESS },
- { FLOPPY_ERROR_INTERNAL, IMAGE_ERROR_INTERNAL },
- { FLOPPY_ERROR_UNSUPPORTED, IMAGE_ERROR_UNSUPPORTED },
- { FLOPPY_ERROR_OUTOFMEMORY, IMAGE_ERROR_OUTOFMEMORY },
- { FLOPPY_ERROR_INVALIDIMAGE, IMAGE_ERROR_INVALIDIMAGE }
+ { FLOPPY_ERROR_SUCCESS, { } },
+ { FLOPPY_ERROR_INTERNAL, { image_error::INTERNAL } },
+ { FLOPPY_ERROR_UNSUPPORTED, { image_error::UNSUPPORTED } },
+ { FLOPPY_ERROR_OUTOFMEMORY, { std::errc::not_enough_memory } },
+ { FLOPPY_ERROR_INVALIDIMAGE, { image_error::INVALIDIMAGE } }
};
/***************************************************************************
IMPLEMENTATION
***************************************************************************/
-
-floppy_image_legacy *legacy_floppy_image_device::flopimg_get_image()
-{
- return m_floppy;
-}
-
-int legacy_floppy_image_device::flopimg_get_sectors_per_track(int side)
-{
- floperr_t err;
- int sector_count;
-
- if (!m_floppy)
- return 0;
-
- err = floppy_get_sector_count(m_floppy, side, m_track, &sector_count);
- if (err)
- return 0;
- return sector_count;
-}
-
-void legacy_floppy_image_device::flopimg_get_id_callback(chrn_id *id, int id_index, int side)
-{
- int cylinder, sector, N;
- unsigned long flags;
- uint32_t sector_length;
-
- if (!m_floppy)
- return;
-
- floppy_get_indexed_sector_info(m_floppy, side, m_track, id_index, &cylinder, &side, &sector, &sector_length, &flags);
-
- N = compute_log2(sector_length);
-
- id->C = cylinder;
- id->H = side;
- id->R = sector;
- id->data_id = id_index;
- id->flags = flags;
- id->N = ((N >= 7) && (N <= 10)) ? N - 7 : 0;
-}
-
void legacy_floppy_image_device::log_readwrite(const char *name, int head, int track, int sector, const char *buf, int length)
{
char membuf[1024];
int i;
for (i = 0; i < length; i++)
- sprintf(membuf + i*2, "%02x", (int) (uint8_t) buf[i]);
+ snprintf(membuf + i*2, 1024 - (i*2), "%02x", (int) (uint8_t) buf[i]);
logerror("%s: head=%i track=%i sector=%i buffer='%s'\n", name, head, track, sector, membuf);
}
@@ -124,13 +88,11 @@ void legacy_floppy_image_device::floppy_drive_init()
/* initialise flags */
m_flags = 0;
m_index_pulse_callback = nullptr;
- m_index_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(legacy_floppy_image_device::floppy_drive_index_callback),this));
+ m_index_timer = timer_alloc(FUNC(legacy_floppy_image_device::floppy_drive_index_callback), this);
m_idx = 0;
floppy_drive_set_geometry(m_config->floppy_type);
- /* initialise id index - not so important */
- m_id_index = 0;
/* initialise track */
m_current_track = 0;
@@ -138,8 +100,6 @@ void legacy_floppy_image_device::floppy_drive_init()
m_rpm = 300;
m_controller = nullptr;
-
- m_floppy_drive_type = FLOPPY_TYPE_REGULAR;
}
/* index pulses at rpm/60 Hz, and stays high 1/20th of time */
@@ -251,7 +211,7 @@ int legacy_floppy_image_device::floppy_drive_get_flag_state(int flag)
void legacy_floppy_image_device::floppy_drive_seek(signed int signed_tracks)
{
- LOG(("seek from: %d delta: %d\n",m_current_track, signed_tracks));
+ LOG("seek from: %d delta: %d\n", m_current_track, signed_tracks);
/* update position */
m_current_track+=signed_tracks;
@@ -267,83 +227,16 @@ void legacy_floppy_image_device::floppy_drive_seek(signed int signed_tracks)
}
/* set track 0 flag */
- m_tk00 = (m_current_track == 0) ? CLEAR_LINE : ASSERT_LINE;
+ m_tk00 = (m_current_track == 0) ? 0 : 1;
//m_out_tk00_func(m_tk00);
/* clear disk changed flag */
- m_dskchg = ASSERT_LINE;
+ m_dskchg = 1;
//m_out_dskchg_func(m_dskchg);
/* inform disk image of step operation so it can cache information */
if (exists())
m_track = m_current_track;
-
- m_id_index = 0;
-}
-
-
-/* this is not accurate. But it will do for now */
-int legacy_floppy_image_device::floppy_drive_get_next_id(int side, chrn_id *id)
-{
- int spt;
-
- /* get sectors per track */
- spt = flopimg_get_sectors_per_track(side);
-
- /* set index */
- if ((m_id_index==(spt-1)) || (spt==0))
- {
- floppy_drive_set_flag_state(FLOPPY_DRIVE_INDEX, 1);
- }
- else
- {
- floppy_drive_set_flag_state(FLOPPY_DRIVE_INDEX, 0);
- }
-
- /* get id */
- if (spt!=0)
- {
- flopimg_get_id_callback(id, m_id_index, side);
- }
-
- m_id_index++;
- if (spt!=0)
- m_id_index %= spt;
- else
- m_id_index = 0;
-
- return (spt == 0) ? 0 : 1;
-}
-
-void legacy_floppy_image_device::floppy_drive_read_track_data_info_buffer(int side, void *ptr, int *length )
-{
- if (exists())
- {
- if (!m_floppy)
- return;
-
- floppy_read_track_data(m_floppy, side, m_track, ptr, *length);
- }
-}
-
-void legacy_floppy_image_device::floppy_drive_write_track_data_info_buffer(int side, const void *ptr, int *length )
-{
- if (exists())
- {
- if (!m_floppy)
- return;
-
- floppy_write_track_data(m_floppy, side, m_track, ptr, *length);
- }
-}
-
-void legacy_floppy_image_device::floppy_drive_format_sector(int side, int sector_index,int c,int h, int r, int n, int filler)
-{
- if (exists())
- {
-/* if (m_interface_.format_sector)
- m_interface_.format_sector(img, side, sector_index,c, h, r, n, filler);*/
- }
}
void legacy_floppy_image_device::floppy_drive_read_sector_data(int side, int index1, void *ptr, int length)
@@ -385,28 +278,11 @@ void legacy_floppy_image_device::floppy_install_unload_proc(void (*proc)(device_
m_unload_proc = proc;
}
-/* set the callback for the index pulse */
-void legacy_floppy_image_device::floppy_drive_set_index_pulse_callback(void (*callback)(device_t *controller, device_t *img, int state))
-{
- m_index_pulse_callback = callback;
-}
-
int legacy_floppy_image_device::floppy_drive_get_current_track()
{
return m_current_track;
}
-uint64_t legacy_floppy_image_device::floppy_drive_get_current_track_size(int head)
-{
- int size = 0;
- if (exists())
- {
- size = floppy_get_track_size(m_floppy, head, m_current_track);
- }
-
- return size;
-}
-
void legacy_floppy_image_device::floppy_drive_set_rpm(float rpm)
{
m_rpm = rpm;
@@ -417,52 +293,54 @@ void legacy_floppy_image_device::floppy_drive_set_controller(device_t *controlle
m_controller = controller;
}
-image_init_result legacy_floppy_image_device::internal_floppy_device_load(bool is_create, int create_format, util::option_resolution *create_args)
+std::error_condition legacy_floppy_image_device::internal_floppy_device_load(bool is_create, int create_format, util::option_resolution *create_args)
{
- floperr_t err;
- const struct FloppyFormat *floppy_options;
- int floppy_flags, i;
+ const struct FloppyFormat *floppy_options = m_config->formats;
- device_image_interface *image = nullptr;
- interface(image); /* figure out the floppy options */
- floppy_options = m_config->formats;
-
- if (is_create)
+ floperr_t err;
+ check_for_file();
+ auto io = util::random_read_write_fill(image_core_file(), 0xff);
+ if (!io)
+ {
+ err = FLOPPY_ERROR_OUTOFMEMORY;
+ }
+ else if (is_create)
{
/* creating an image */
assert(create_format >= 0);
- err = floppy_create((void *) image, &image_ioprocs, &floppy_options[create_format], create_args, &m_floppy);
- if (err)
- goto error;
+ err = floppy_create(std::move(io), &floppy_options[create_format], create_args, &m_floppy);
}
else
{
/* opening an image */
- floppy_flags = !is_readonly() ? FLOPPY_FLAGS_READWRITE : FLOPPY_FLAGS_READONLY;
- err = floppy_open_choices((void *) image, &image_ioprocs, filetype(), floppy_options, floppy_flags, &m_floppy);
- if (err)
- goto error;
- }
- if (floppy_callbacks(m_floppy)->get_heads_per_disk && floppy_callbacks(m_floppy)->get_tracks_per_disk)
- {
- floppy_drive_set_geometry_absolute(floppy_get_tracks_per_disk(m_floppy),floppy_get_heads_per_disk(m_floppy));
+ int const floppy_flags = !is_readonly() ? FLOPPY_FLAGS_READWRITE : FLOPPY_FLAGS_READONLY;
+ err = floppy_open_choices(std::move(io), filetype(), floppy_options, floppy_flags, &m_floppy);
}
- /* disk changed */
- m_dskchg = CLEAR_LINE;
- // If we have one of our hacky load procs, call it
- if (m_load_proc)
- m_load_proc(*this, is_create);
+ if (!err)
+ {
+ if (floppy_callbacks(m_floppy)->get_heads_per_disk && floppy_callbacks(m_floppy)->get_tracks_per_disk)
+ {
+ floppy_drive_set_geometry_absolute(floppy_get_tracks_per_disk(m_floppy),floppy_get_heads_per_disk(m_floppy));
+ }
+ /* disk changed */
+ m_dskchg = CLEAR_LINE;
- return image_init_result::PASS;
+ // If we have one of our hacky load procs, call it
+ if (m_load_proc)
+ m_load_proc(*this, is_create);
-error:
- for (i = 0; i < ARRAY_LENGTH(errmap); i++)
+ return std::error_condition();
+ }
+ else
{
- if (err == errmap[i].ferr)
- seterror(errmap[i].ierr, errmap[i].message);
+ for (int i = 0; i < std::size(errmap); i++)
+ {
+ if (err == errmap[i].ferr)
+ return errmap[i].ierr;
+ }
+ return image_error::UNSPECIFIED;
}
- return image_init_result::FAIL;
}
TIMER_CALLBACK_MEMBER( legacy_floppy_image_device::set_wpt )
@@ -471,115 +349,21 @@ TIMER_CALLBACK_MEMBER( legacy_floppy_image_device::set_wpt )
//m_out_wpt_func(param);
}
-legacy_floppy_image_device *floppy_get_device(running_machine &machine,int drive)
-{
- switch(drive) {
- case 0 : return machine.device<legacy_floppy_image_device>(FLOPPY_0);
- case 1 : return machine.device<legacy_floppy_image_device>(FLOPPY_1);
- case 2 : return machine.device<legacy_floppy_image_device>(FLOPPY_2);
- case 3 : return machine.device<legacy_floppy_image_device>(FLOPPY_3);
- }
- return nullptr;
-}
-
-int legacy_floppy_image_device::floppy_get_drive_type()
-{
- return m_floppy_drive_type;
-}
-
-void legacy_floppy_image_device::floppy_set_type(int ftype)
-{
- m_floppy_drive_type = ftype;
-}
-
-legacy_floppy_image_device *floppy_get_device_by_type(running_machine &machine,int ftype,int drive)
-{
- int i;
- int cnt = 0;
- for (i=0;i<4;i++) {
- legacy_floppy_image_device *disk = floppy_get_device(machine,i);
- if (disk && disk->floppy_get_drive_type()==ftype) {
- if (cnt==drive) {
- return disk;
- }
- cnt++;
- }
- }
- return nullptr;
-}
-
-static int floppy_get_drive(device_t *image)
-{
- int drive = -1;
- if (strcmp(image->tag(), ":" FLOPPY_0) == 0) drive = 0;
- if (strcmp(image->tag(), ":" FLOPPY_1) == 0) drive = 1;
- if (strcmp(image->tag(), ":" FLOPPY_2) == 0) drive = 2;
- if (strcmp(image->tag(), ":" FLOPPY_3) == 0) drive = 3;
- return drive;
-}
-
-int floppy_get_drive_by_type(legacy_floppy_image_device *image,int ftype)
-{
- int i,drive =0;
- for (i=0;i<4;i++) {
- legacy_floppy_image_device *disk = floppy_get_device(image->machine(),i);
- if (disk && disk->floppy_get_drive_type()==ftype) {
- if (image==disk) {
- return drive;
- }
- drive++;
- }
- }
- return -1;
-}
-
-
-/* drive select 0 */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds0_w )
-{
- if (state == CLEAR_LINE)
- m_active = (m_drive_id == 0);
-}
-
-/* drive select 1 */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds1_w )
-{
- if (state == CLEAR_LINE)
- m_active = (m_drive_id == 1);
-}
-
-/* drive select 2 */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds2_w )
+/* drive select */
+void legacy_floppy_image_device::floppy_ds_w(int state)
{
- if (state == CLEAR_LINE)
- m_active = (m_drive_id == 2);
-}
-
-/* drive select 3 */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds3_w )
-{
- if (state == CLEAR_LINE)
- m_active = (m_drive_id == 3);
-}
-
-/* shortcut to write all four ds lines */
-WRITE8_MEMBER( legacy_floppy_image_device::floppy_ds_w )
-{
- floppy_ds0_w(BIT(data, 0));
- floppy_ds1_w(BIT(data, 1));
- floppy_ds2_w(BIT(data, 2));
- floppy_ds3_w(BIT(data, 3));
+ m_active = (state == 0);
}
/* motor on, active low */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_mon_w )
+void legacy_floppy_image_device::floppy_mon_w(int state)
{
/* force off if there is no attached image */
if (!exists())
- state = ASSERT_LINE;
+ state = 1;
/* off -> on */
- if (m_mon && state == CLEAR_LINE)
+ if (m_mon && state == 0)
{
m_idx = 0;
floppy_drive_index_func();
@@ -593,18 +377,13 @@ WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_mon_w )
}
/* direction */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_drtn_w )
+void legacy_floppy_image_device::floppy_drtn_w(int state)
{
m_drtn = state;
}
-/* write data */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_wtd_w )
-{
-}
-
/* step */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_stp_w )
+void legacy_floppy_image_device::floppy_stp_w(int state)
{
/* move head one track when going from high to low and write gate is high */
if (m_active && m_stp && state == CLEAR_LINE && m_wtg)
@@ -617,7 +396,7 @@ WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_stp_w )
m_current_track--;
/* are we at track 0 now? */
- m_tk00 = (m_current_track == 0) ? CLEAR_LINE : ASSERT_LINE;
+ m_tk00 = (m_current_track == 0) ? 0 : 1;
}
else
{
@@ -626,7 +405,7 @@ WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_stp_w )
m_current_track++;
/* we can't be at track 0 here, so reset the line */
- m_tk00 = ASSERT_LINE;
+ m_tk00 = 1;
}
/* update track 0 line with new status */
@@ -641,44 +420,23 @@ WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_stp_w )
}
/* write gate */
-WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_wtg_w )
+void legacy_floppy_image_device::floppy_wtg_w(int state)
{
m_wtg = state;
}
-/* write protect signal, active low */
-READ_LINE_MEMBER( legacy_floppy_image_device::floppy_wpt_r )
-{
- return m_wpt;
-}
-
/* track 0 detect */
-READ_LINE_MEMBER( legacy_floppy_image_device::floppy_tk00_r )
+int legacy_floppy_image_device::floppy_tk00_r()
{
return m_tk00;
}
-/* disk changed */
-READ_LINE_MEMBER( legacy_floppy_image_device::floppy_dskchg_r )
-{
- return m_dskchg;
-}
-
-/* 2-sided disk */
-READ_LINE_MEMBER( legacy_floppy_image_device::floppy_twosid_r )
-{
- if (m_floppy == nullptr)
- return ASSERT_LINE;
- else
- return !floppy_get_heads_per_disk(m_floppy);
-}
-
-READ_LINE_MEMBER( legacy_floppy_image_device::floppy_index_r )
+int legacy_floppy_image_device::floppy_index_r()
{
return m_idx;
}
-READ_LINE_MEMBER( legacy_floppy_image_device::floppy_ready_r )
+int legacy_floppy_image_device::floppy_ready_r()
{
return !(floppy_drive_get_flag_state(FLOPPY_DRIVE_READY) == FLOPPY_DRIVE_READY);
}
@@ -706,9 +464,7 @@ legacy_floppy_image_device::legacy_floppy_image_device(const machine_config &mco
m_idx(0),
m_tk00(0),
m_wpt(0),
- m_rdy(0),
m_dskchg(0),
- m_drive_id(-1),
m_active(0),
m_config(nullptr),
m_flags(0),
@@ -718,13 +474,11 @@ legacy_floppy_image_device::legacy_floppy_image_device(const machine_config &mco
m_index_timer(nullptr),
m_index_pulse_callback(nullptr),
m_rpm(0.0f),
- m_id_index(0),
m_controller(nullptr),
m_floppy(nullptr),
m_track(0),
m_load_proc(nullptr),
- m_unload_proc(nullptr),
- m_floppy_drive_type(0)
+ m_unload_proc(nullptr)
{
memset(&m_extension_list,0,sizeof(m_extension_list));
}
@@ -745,11 +499,9 @@ void legacy_floppy_image_device::device_start()
{
floppy_drive_init();
- m_drive_id = floppy_get_drive(this);
m_active = false;
/* resolve callbacks */
- m_out_idx_func.resolve_safe();
//m_in_mon_func.resolve(m_config->in_mon_func, *this);
//m_out_tk00_func.resolve(m_config->out_tk00_func, *this);
//m_out_wpt_func.resolve(m_config->out_wpt_func, *this);
@@ -757,19 +509,22 @@ void legacy_floppy_image_device::device_start()
// m_out_dskchg_func.resolve(m_config->out_dskchg_func, *this);
/* by default we are not write-protected */
- m_wpt = ASSERT_LINE;
+ m_wpt = 1;
//m_out_wpt_func(m_wpt);
/* not at track 0 */
- m_tk00 = ASSERT_LINE;
+ m_tk00 = 1;
//m_out_tk00_func(m_tk00);
/* motor off */
- m_mon = ASSERT_LINE;
+ m_mon = 1;
/* disk changed */
m_dskchg = CLEAR_LINE;
// m_out_dskchg_func(m_dskchg);
+
+ /* write-protect callback */
+ m_wpt_timer = timer_alloc(FUNC(legacy_floppy_image_device::set_wpt), this);
}
@@ -788,7 +543,8 @@ void legacy_floppy_image_device::device_config_complete()
for (int i = 0; floppy_options && floppy_options[i].construct; i++)
{
// only add if creatable
- if (floppy_options[i].param_guidelines) {
+ if (floppy_options[i].param_guidelines)
+ {
// allocate a new format and append it to the list
add_format(floppy_options[i].name, floppy_options[i].description, floppy_options[i].extensions, floppy_options[i].param_guidelines);
}
@@ -797,14 +553,19 @@ void legacy_floppy_image_device::device_config_complete()
}
}
-image_init_result legacy_floppy_image_device::call_create(int format_type, util::option_resolution *format_options)
+const software_list_loader &legacy_floppy_image_device::get_software_list_loader() const
+{
+ return image_software_list_loader::instance();
+}
+
+std::pair<std::error_condition, std::string> legacy_floppy_image_device::call_create(int format_type, util::option_resolution *format_options)
{
- return internal_floppy_device_load(true, format_type, format_options);
+ return std::make_pair(internal_floppy_device_load(true, format_type, format_options), std::string());
}
-image_init_result legacy_floppy_image_device::call_load()
+std::pair<std::error_condition, std::string> legacy_floppy_image_device::call_load()
{
- image_init_result retVal = internal_floppy_device_load(false, -1, nullptr);
+ std::error_condition retVal = internal_floppy_device_load(false, -1, nullptr);
/* push disk halfway into drive */
m_wpt = CLEAR_LINE;
@@ -814,13 +575,13 @@ image_init_result legacy_floppy_image_device::call_load()
int next_wpt;
if (!is_readonly())
- next_wpt = ASSERT_LINE;
+ next_wpt = 1;
else
- next_wpt = CLEAR_LINE;
+ next_wpt = 0;
- machine().scheduler().timer_set(attotime::from_msec(250), timer_expired_delegate(FUNC(legacy_floppy_image_device::set_wpt),this), next_wpt);
+ m_wpt_timer->adjust(attotime::from_msec(250), next_wpt);
- return retVal;
+ return std::make_pair(retVal, std::string());
}
void legacy_floppy_image_device::call_unload()
@@ -832,32 +593,32 @@ void legacy_floppy_image_device::call_unload()
m_floppy = nullptr;
/* disk changed */
- m_dskchg = CLEAR_LINE;
+ m_dskchg = 0;
//m_out_dskchg_func(m_dskchg);
/* pull disk halfway out of drive */
- m_wpt = CLEAR_LINE;
+ m_wpt = 0;
//m_out_wpt_func(m_wpt);
/* set timer for disk eject */
- machine().scheduler().timer_set(attotime::from_msec(250), timer_expired_delegate(FUNC(legacy_floppy_image_device::set_wpt),this), ASSERT_LINE);
+ m_wpt_timer->adjust(attotime::from_msec(250), 1);
}
-bool legacy_floppy_image_device::is_creatable() const
+bool legacy_floppy_image_device::is_creatable() const noexcept
{
- int cnt = 0;
- if (m_config != nullptr)
+ if (m_config)
{
const struct FloppyFormat *floppy_options = m_config->formats;
- int i;
- for ( i = 0; floppy_options[i].construct; i++ ) {
- if(floppy_options[i].param_guidelines) cnt++;
+ for (int i = 0; floppy_options[i].construct; i++)
+ {
+ if (floppy_options[i].param_guidelines)
+ return true;
}
}
- return (cnt>0) ? 1 : 0;
+ return false;
}
-const char *legacy_floppy_image_device::image_interface() const
+const char *legacy_floppy_image_device::image_interface() const noexcept
{
return m_config->interface;
}
diff --git a/src/devices/imagedev/flopdrv.h b/src/devices/imagedev/flopdrv.h
index 97ae6a77859..24ab79ef7c1 100644
--- a/src/devices/imagedev/flopdrv.h
+++ b/src/devices/imagedev/flopdrv.h
@@ -2,22 +2,12 @@
// copyright-holders:Nathan Woods, Miodrag Milanovic
/* flopdrv provides simple emulation of a disc drive */
-#ifndef MAME_DEVICES_IMAGEDV_FLOPDRV_H
-#define MAME_DEVICES_IMAGEDV_FLOPDRV_H
+#ifndef MAME_IMAGEDEV_FLOPDRV_H
+#define MAME_IMAGEDEV_FLOPDRV_H
#pragma once
-#include "formats/flopimg.h"
-#include "softlist_dev.h"
-
-#define FLOPPY_0 "floppy0"
-#define FLOPPY_1 "floppy1"
-#define FLOPPY_2 "floppy2"
-#define FLOPPY_3 "floppy3"
-
-#define FLOPPY_TYPE_REGULAR 0
-#define FLOPPY_TYPE_APPLE 1
-#define FLOPPY_TYPE_SONY 2
+#include "formats/flopimg_legacy.h"
#define FLOPPY_DRIVE_2_8_INCH 1
#define FLOPPY_DRIVE_3_INCH 2
@@ -108,92 +98,60 @@ public:
void set_floppy_config(const floppy_interface *config) { m_config = config; }
auto out_idx_cb() { return m_out_idx_func.bind(); }
- static void add_4drives(machine_config &mconfig, const floppy_interface *config)
- {
- LEGACY_FLOPPY(mconfig, FLOPPY_0, 0, config);
- LEGACY_FLOPPY(mconfig, FLOPPY_1, 0, config);
- LEGACY_FLOPPY(mconfig, FLOPPY_2, 0, config);
- LEGACY_FLOPPY(mconfig, FLOPPY_3, 0, config);
- }
-
- static void add_2drives(machine_config &mconfig, const floppy_interface *config)
- {
- LEGACY_FLOPPY(mconfig, FLOPPY_0, 0, config);
- LEGACY_FLOPPY(mconfig, FLOPPY_1, 0, config);
- }
-
- virtual image_init_result call_load() override;
- virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); }
- virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
virtual void call_unload() override;
- virtual iodevice_t image_type() const override { return IO_FLOPPY; }
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override;
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *image_interface() const noexcept override;
+ virtual const char *file_extensions() const noexcept override { return m_extension_list; }
+ virtual const char *image_type_name() const noexcept override { return "floppydisk"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "flop"; }
+ virtual const util::option_guide &create_option_guide() const override { return floppy_option_guide(); }
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 1; }
- virtual bool is_creatable() const override;
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override;
- virtual const char *file_extensions() const override { return m_extension_list; }
- virtual const util::option_guide &create_option_guide() const override { return floppy_option_guide; }
-
- floppy_image_legacy *flopimg_get_image();
- void floppy_drive_set_geometry(floppy_type_t type);
- void floppy_drive_set_flag_state(int flag, int state);
void floppy_drive_set_ready_state(int state, int flag);
int floppy_drive_get_flag_state(int flag);
void floppy_drive_seek(signed int signed_tracks);
- int floppy_drive_get_next_id(int side, chrn_id *id);
- void floppy_drive_read_track_data_info_buffer(int side, void *ptr, int *length );
- void floppy_drive_write_track_data_info_buffer(int side, const void *ptr, int *length );
- void floppy_drive_format_sector(int side, int sector_index,int c,int h, int r, int n, int filler);
void floppy_drive_read_sector_data(int side, int index1, void *ptr, int length);
void floppy_drive_write_sector_data(int side, int index1, const void *ptr,int length, int ddam);
void floppy_install_load_proc(void (*proc)(device_image_interface &image, bool is_created));
void floppy_install_unload_proc(void (*proc)(device_image_interface &image));
- void floppy_drive_set_index_pulse_callback(void (*callback)(device_t *controller,device_t *image, int state));
int floppy_drive_get_current_track();
- uint64_t floppy_drive_get_current_track_size(int head);
void floppy_drive_set_rpm(float rpm);
void floppy_drive_set_controller(device_t *controller);
- int floppy_get_drive_type();
- void floppy_set_type(int ftype);
- WRITE_LINE_MEMBER( floppy_ds0_w );
- WRITE_LINE_MEMBER( floppy_ds1_w );
- WRITE_LINE_MEMBER( floppy_ds2_w );
- WRITE_LINE_MEMBER( floppy_ds3_w );
- WRITE8_MEMBER( floppy_ds_w );
- WRITE_LINE_MEMBER( floppy_mon_w );
- WRITE_LINE_MEMBER( floppy_drtn_w );
- WRITE_LINE_MEMBER( floppy_wtd_w );
- WRITE_LINE_MEMBER( floppy_stp_w );
- WRITE_LINE_MEMBER( floppy_wtg_w );
- READ_LINE_MEMBER( floppy_wpt_r );
- READ_LINE_MEMBER( floppy_tk00_r );
- READ_LINE_MEMBER( floppy_dskchg_r );
- READ_LINE_MEMBER( floppy_twosid_r );
- READ_LINE_MEMBER( floppy_index_r );
- READ_LINE_MEMBER( floppy_ready_r );
+ void floppy_ds_w(int state);
+ void floppy_mon_w(int state);
+ void floppy_drtn_w(int state);
+ void floppy_stp_w(int state);
+ void floppy_wtg_w(int state);
+ int floppy_tk00_r();
+ int floppy_index_r();
+ int floppy_ready_r();
private:
- int flopimg_get_sectors_per_track(int side);
- void flopimg_get_id_callback(chrn_id *id, int id_index, int side);
void log_readwrite(const char *name, int head, int track, int sector, const char *buf, int length);
+ void floppy_drive_set_flag_state(int flag, int state);
void floppy_drive_set_geometry_absolute(int tracks, int sides);
+ void floppy_drive_set_geometry(floppy_type_t type);
TIMER_CALLBACK_MEMBER(floppy_drive_index_callback);
void floppy_drive_init();
void floppy_drive_index_func();
- image_init_result internal_floppy_device_load(bool is_create, int create_format, util::option_resolution *create_args);
+ std::error_condition internal_floppy_device_load(bool is_create, int create_format, util::option_resolution *create_args);
TIMER_CALLBACK_MEMBER( set_wpt );
protected:
legacy_floppy_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device overrides
+ // device_t implementation
virtual void device_config_complete() override;
- virtual void device_start() override;
+ virtual void device_start() override ATTR_COLD;
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override;
/* callbacks */
devcb_write_line m_out_idx_func;
@@ -208,12 +166,10 @@ protected:
int m_idx; /* index pulse */
int m_tk00; /* track 00 */
int m_wpt; /* write protect */
- int m_rdy; /* ready */
int m_dskchg; /* disk changed */
/* drive select logic */
- int m_drive_id;
- int m_active;
+ bool m_active;
const floppy_interface *m_config;
@@ -234,7 +190,7 @@ protected:
/* rotation per minute => gives index pulse frequency */
float m_rpm;
- int m_id_index;
+ emu_timer *m_wpt_timer;
device_t *m_controller;
@@ -242,13 +198,8 @@ protected:
int m_track;
void (*m_load_proc)(device_image_interface &image, bool is_created);
void (*m_unload_proc)(device_image_interface &image);
- int m_floppy_drive_type;
char m_extension_list[256];
};
-legacy_floppy_image_device *floppy_get_device(running_machine &machine,int drive);
-legacy_floppy_image_device *floppy_get_device_by_type(running_machine &machine,int ftype,int drive);
-int floppy_get_drive_by_type(legacy_floppy_image_device *image,int ftype);
-
-#endif // MAME_DEVICES_IMAGEDV_FLOPDRV_H
+#endif // MAME_IMAGEDEV_FLOPDRV_H
diff --git a/src/devices/imagedev/floppy.cpp b/src/devices/imagedev/floppy.cpp
index 60058681549..b6f3e2b69b5 100644
--- a/src/devices/imagedev/floppy.cpp
+++ b/src/devices/imagedev/floppy.cpp
@@ -9,9 +9,32 @@
#include "emu.h"
#include "floppy.h"
+#include "formats/d88_dsk.h"
+#include "formats/dfi_dsk.h"
+#include "formats/hxchfe_dsk.h"
+#include "formats/hxcmfm_dsk.h"
+#include "formats/imd_dsk.h"
+#include "formats/mfi_dsk.h"
+#include "formats/td0_dsk.h"
+#include "formats/cqm_dsk.h"
+#include "formats/dsk_dsk.h"
+#include "formats/pc_dsk.h"
+#include "formats/ipf_dsk.h"
+#include "formats/86f_dsk.h"
+
+#include "formats/fs_unformatted.h"
+#include "formats/fsblk_vec.h"
+
+#include "softlist_dev.h"
#include "speaker.h"
+
#include "formats/imageutl.h"
-#include "zippath.h"
+
+#include "util/ioprocs.h"
+#include "util/ioprocsfilter.h"
+#include "util/zippath.h"
+
+#include <algorithm>
/*
Debugging flags. Set to 0 or 1.
@@ -29,8 +52,11 @@
DEFINE_DEVICE_TYPE(FLOPPY_CONNECTOR, floppy_connector, "floppy_connector", "Floppy drive connector abstraction")
// generic 3" drives
-DEFINE_DEVICE_TYPE(FLOPPY_3_SSDD, floppy_3_ssdd, "floppy_3_ssdd", "3\" single-sided floppy drive")
-DEFINE_DEVICE_TYPE(FLOPPY_3_DSDD, floppy_3_dsdd, "floppy_3_dsdd", "3\" double-sided floppy drive")
+DEFINE_DEVICE_TYPE(FLOPPY_3_SSSD, floppy_3_sssd, "floppy_3_sssd", "3\" single-sided single density floppy drive")
+DEFINE_DEVICE_TYPE(FLOPPY_3_DSSD, floppy_3_dssd, "floppy_3_dssd", "3\" double-sided single density floppy drive")
+DEFINE_DEVICE_TYPE(FLOPPY_3_SSDD, floppy_3_ssdd, "floppy_3_ssdd", "3\" single-sided double density floppy drive")
+DEFINE_DEVICE_TYPE(FLOPPY_3_DSDD, floppy_3_dsdd, "floppy_3_dsdd", "3\" double-sided double density floppy drive")
+DEFINE_DEVICE_TYPE(FLOPPY_3_DSQD, floppy_3_dsqd, "floppy_3_dsqd", "3\" double-sided quad density floppy drive")
// generic 3.5" drives
DEFINE_DEVICE_TYPE(FLOPPY_35_SSDD, floppy_35_ssdd, "floppy_35_ssdd", "3.5\" single-sided double density floppy drive")
@@ -41,6 +67,7 @@ DEFINE_DEVICE_TYPE(FLOPPY_35_ED, floppy_35_ed, "floppy_35_ed", "3.5\" exte
// generic 5.25" drives
DEFINE_DEVICE_TYPE(FLOPPY_525_SSSD_35T, floppy_525_sssd_35t, "floppy_525_sssd_35t", "5.25\" single-sided single density 35-track floppy drive")
DEFINE_DEVICE_TYPE(FLOPPY_525_SD_35T, floppy_525_sd_35t, "floppy_525_sd_35t", "5.25\" double-sided single density 35-track floppy drive")
+DEFINE_DEVICE_TYPE(FLOPPY_525_VTECH, floppy_525_vtech, "floppy_525_vtech", "5.25\" single-sided single density VTECH floppy drive")
DEFINE_DEVICE_TYPE(FLOPPY_525_SSSD, floppy_525_sssd, "floppy_525_sssd", "5.25\" single-sided single density floppy drive")
DEFINE_DEVICE_TYPE(FLOPPY_525_SD, floppy_525_sd, "floppy_525_sd", "5.25\" single density floppy drive")
DEFINE_DEVICE_TYPE(FLOPPY_525_SSDD, floppy_525_ssdd, "floppy_525_ssdd", "5.25\" single-sided double density floppy drive")
@@ -95,6 +122,9 @@ DEFINE_DEVICE_TYPE(EPSON_SD_621L, epson_sd_621l, "epson_sd_621l", "EPSON SD-621L
DEFINE_DEVICE_TYPE(EPSON_SD_680L, epson_sd_680l, "epson_sd_680l", "EPSON SD-680L Mini-Floppy Disk Drive")
#endif
+// Panasonic 3.5" drive
+DEFINE_DEVICE_TYPE(PANA_JU_363, pana_ju_363, "pana_ju_363", "Panasonic JU-363 Flexible Disk Drive")
+
// Sony 3.5" drives
DEFINE_DEVICE_TYPE(SONY_OA_D31V, sony_oa_d31v, "sony_oa_d31v", "Sony OA-D31V Micro Floppydisk Drive")
DEFINE_DEVICE_TYPE(SONY_OA_D32W, sony_oa_d32w, "sony_oa_d32w", "Sony OA-D32W Micro Floppydisk Drive")
@@ -104,10 +134,8 @@ DEFINE_DEVICE_TYPE(SONY_OA_D32V, sony_oa_d32v, "sony_oa_d32v", "Sony OA-D32V Mic
DEFINE_DEVICE_TYPE(TEAC_FD_30A, teac_fd_30a, "teac_fd_30a", "TEAC FD-30A FDD")
// TEAC 5.25" drives
-#if 0
DEFINE_DEVICE_TYPE(TEAC_FD_55A, teac_fd_55a, "teac_fd_55a", "TEAC FD-55A FDD")
DEFINE_DEVICE_TYPE(TEAC_FD_55B, teac_fd_55b, "teac_fd_55b", "TEAC FD-55B FDD")
-#endif
DEFINE_DEVICE_TYPE(TEAC_FD_55E, teac_fd_55e, "teac_fd_55e", "TEAC FD-55E FDD")
DEFINE_DEVICE_TYPE(TEAC_FD_55F, teac_fd_55f, "teac_fd_55f", "TEAC FD-55F FDD")
DEFINE_DEVICE_TYPE(TEAC_FD_55G, teac_fd_55g, "teac_fd_55g", "TEAC FD-55G FDD")
@@ -118,26 +146,76 @@ DEFINE_DEVICE_TYPE(ALPS_3255190X, alps_3255190x, "alps_3255190x", "ALPS 32551901
// IBM 8" drives
DEFINE_DEVICE_TYPE(IBM_6360, ibm_6360, "ibm_6360", "IBM 6360 8\" single-sided single density floppy drive")
+// Mac 3.5" drives
+DEFINE_DEVICE_TYPE(OAD34V, oa_d34v_device, "oa_d34v", "Apple/Sony 3.5 SD (400K GCR)")
+DEFINE_DEVICE_TYPE(MFD51W, mfd51w_device, "mfd51w", "Apple/Sony 3.5 DD (400/800K GCR)")
+DEFINE_DEVICE_TYPE(MFD75W, mfd75w_device, "mfd75w", "Apple/Sony 3.5 HD (Superdrive)")
-const floppy_format_type floppy_image_device::default_floppy_formats[] = {
- FLOPPY_D88_FORMAT,
- FLOPPY_DFI_FORMAT,
- FLOPPY_HFE_FORMAT,
- FLOPPY_IMD_FORMAT,
- FLOPPY_IPF_FORMAT,
- FLOPPY_MFI_FORMAT,
- FLOPPY_MFM_FORMAT,
- FLOPPY_TD0_FORMAT,
- FLOPPY_CQM_FORMAT,
- FLOPPY_DSK_FORMAT,
- nullptr
-};
+
+format_registration::format_registration()
+{
+ add(FLOPPY_MFI_FORMAT); // Our generic format
+ add(FLOPPY_DFI_FORMAT); // Flux format, dying
+
+ add(fs::UNFORMATTED);
+}
+
+void format_registration::add_fm_containers()
+{
+ add(FLOPPY_MFM_FORMAT);
+ add(FLOPPY_TD0_FORMAT);
+ add(FLOPPY_IMD_FORMAT);
+ add(FLOPPY_86F_FORMAT);
+}
+
+void format_registration::add_mfm_containers()
+{
+ add_fm_containers();
+
+ add(FLOPPY_D88_FORMAT);
+ add(FLOPPY_CQM_FORMAT);
+ add(FLOPPY_DSK_FORMAT);
+}
+
+void format_registration::add_pc_formats()
+{
+ add_mfm_containers();
+
+ add(FLOPPY_PC_FORMAT);
+ add(FLOPPY_IPF_FORMAT);
+}
+
+void format_registration::add(const floppy_image_format_t &format)
+{
+ m_formats.push_back(&format);
+}
+
+void format_registration::add(const fs::manager_t &fs)
+{
+ m_fs.push_back(&fs);
+}
+
+void floppy_image_device::default_fm_floppy_formats(format_registration &fr)
+{
+ fr.add_fm_containers();
+}
+
+void floppy_image_device::default_mfm_floppy_formats(format_registration &fr)
+{
+ fr.add_mfm_containers();
+}
+
+void floppy_image_device::default_pc_floppy_formats(format_registration &fr)
+{
+ fr.add_pc_formats();
+}
floppy_connector::floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, FLOPPY_CONNECTOR, tag, owner, clock),
device_slot_interface(mconfig, *this),
formats(nullptr),
- m_enable_sound(false)
+ m_enable_sound(false),
+ m_sectoring_type(floppy_image::SOFT)
{
}
@@ -145,11 +223,6 @@ floppy_connector::~floppy_connector()
{
}
-void floppy_connector::set_formats(const floppy_format_type _formats[])
-{
- formats = _formats;
-}
-
void floppy_connector::device_start()
{
}
@@ -161,6 +234,7 @@ void floppy_connector::device_config_complete()
{
dev->set_formats(formats);
dev->enable_sound(m_enable_sound);
+ dev->set_sectoring_type(m_sectoring_type);
}
}
@@ -176,32 +250,32 @@ floppy_image_device *floppy_connector::get_device()
floppy_image_device::floppy_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock),
device_image_interface(mconfig, *this),
- device_slot_card_interface(mconfig, *this),
- input_format(nullptr),
- output_format(nullptr),
- image(nullptr),
- fif_list(nullptr),
- index_timer(nullptr),
- tracks(0),
- sides(0),
- form_factor(0),
- motor_always_on(false),
- dskchg_writable(false),
- has_trk00_sensor(true),
- dir(0), stp(0), wtg(0), mon(0), ss(0), ds(-1), idx(0), wpt(0), rdy(0), dskchg(0),
- ready(false),
- rpm(0),
- floppy_ratio_1(0),
- revolution_count(0),
- cyl(0),
- subcyl(0),
- image_dirty(false),
- ready_counter(0),
+ m_input_format(nullptr),
+ m_output_format(nullptr),
+ m_image(),
+ m_index_timer(nullptr),
+ m_tracks(0),
+ m_sides(0),
+ m_form_factor(0),
+ m_sectoring_type(floppy_image::SOFT),
+ m_motor_always_on(false),
+ m_dskchg_writable(false),
+ m_has_trk00_sensor(true),
+ m_dir(0), m_stp(0), m_wtg(0), m_mon(0), m_ss(0), m_ds(-1), m_idx(0), m_wpt(0), m_rdy(0), m_dskchg(0),
+ m_ready(false),
+ m_rpm(0),
+ m_angular_speed(0),
+ m_revolution_count(0),
+ m_cyl(0),
+ m_subcyl(0),
+ m_amplifier_freakout_time(attotime::from_usec(16)),
+ m_image_dirty(false),
+ m_track_dirty(false),
+ m_ready_counter(0),
m_make_sound(false),
m_sound_out(nullptr)
{
- extension_list[0] = '\0';
- m_err = IMAGE_ERROR_INVALIDIMAGE;
+ m_extension_list[0] = '\0';
}
//-------------------------------------------------
@@ -210,167 +284,291 @@ floppy_image_device::floppy_image_device(const machine_config &mconfig, device_t
floppy_image_device::~floppy_image_device()
{
- for(floppy_image_format_t *format = fif_list; format; ) {
- floppy_image_format_t* tmp_format = format;
- format = format->next;
- delete tmp_format;
- }
- fif_list = nullptr;
}
void floppy_image_device::setup_load_cb(load_cb cb)
{
- cur_load_cb = cb;
+ m_cur_load_cb = cb;
}
void floppy_image_device::setup_unload_cb(unload_cb cb)
{
- cur_unload_cb = cb;
+ m_cur_unload_cb = cb;
}
void floppy_image_device::setup_index_pulse_cb(index_pulse_cb cb)
{
- cur_index_pulse_cb = cb;
+ m_cur_index_pulse_cb = cb;
}
void floppy_image_device::setup_ready_cb(ready_cb cb)
{
- cur_ready_cb = cb;
+ m_cur_ready_cb = cb;
}
void floppy_image_device::setup_wpt_cb(wpt_cb cb)
{
- cur_wpt_cb = cb;
+ m_cur_wpt_cb = cb;
}
void floppy_image_device::setup_led_cb(led_cb cb)
{
- cur_led_cb = cb;
+ m_cur_led_cb = cb;
+}
+
+struct floppy_image_device::fs_enum : public fs::manager_t::floppy_enumerator {
+ floppy_image_device *m_fid;
+ const fs::manager_t *m_manager;
+
+ fs_enum(floppy_image_device *fid);
+
+ virtual void add_raw(const char *name, u32 key, const char *description) override;
+protected:
+ virtual void add_format(const floppy_image_format_t &type, u32 image_size, const char *name, const char *description) override;
+};
+
+floppy_image_device::fs_enum::fs_enum(floppy_image_device *fid)
+ : fs::manager_t::floppy_enumerator(fid->m_form_factor, fid->m_variants)
+ , m_fid(fid)
+{
}
-void floppy_image_device::set_formats(const floppy_format_type *formats)
+void floppy_image_device::fs_enum::add_format(const floppy_image_format_t &type, u32 image_size, const char *name, const char *description)
{
- extension_list[0] = '\0';
- fif_list = nullptr;
- for(int cnt=0; formats[cnt]; cnt++)
- {
- // allocate a new format
- floppy_image_format_t *fif = formats[cnt]();
- if(!fif_list)
- fif_list = fif;
- else
- fif_list->append(fif);
+ m_fid->m_fs.emplace_back(fs_info(m_manager, &type, image_size, name, description));
+}
+void floppy_image_device::fs_enum::add_raw(const char *name, u32 key, const char *description)
+{
+ m_fid->m_fs.emplace_back(fs_info(name, key, description));
+}
+
+void floppy_image_device::register_formats()
+{
+ format_registration fr;
+ if(m_format_registration_cb)
+ m_format_registration_cb(fr);
+
+ m_extension_list[0] = '\0';
+ m_fif_list = std::move(fr.m_formats);
+ for(const floppy_image_format_t *fif : m_fif_list)
+ {
add_format(fif->name(), fif->description(), fif->extensions(), "");
+ image_specify_extension( m_extension_list, 256, fif->extensions() );
+ }
+
+ fs_enum fse(this);
+ for(const fs::manager_t *fmt : fr.m_fs)
+ {
+ fse.m_manager = fmt;
+ fmt->enumerate_f(fse);
+ m_fs_managers.push_back(fmt);
+ }
+}
+
+void floppy_image_device::add_variant(uint32_t variant)
+{
+ uint32_t actual_variant = variant;
- image_specify_extension( extension_list, 256, fif->extensions() );
+ if (m_sectoring_type == floppy_image::H10) {
+ switch (variant) {
+ case floppy_image::SSSD:
+ actual_variant = floppy_image::SSSD10;
+ break;
+ case floppy_image::SSDD:
+ actual_variant = floppy_image::SSDD10;
+ break;
+ case floppy_image::SSQD:
+ actual_variant = floppy_image::SSQD10;
+ break;
+ case floppy_image::DSSD:
+ actual_variant = floppy_image::DSSD10;
+ break;
+ case floppy_image::DSDD:
+ actual_variant = floppy_image::DSDD10;
+ break;
+ case floppy_image::DSQD:
+ actual_variant = floppy_image::DSQD10;
+ break;
+ }
+ } else if (m_sectoring_type == floppy_image::H16) {
+ switch (variant) {
+ case floppy_image::SSSD:
+ actual_variant = floppy_image::SSDD16;
+ break;
+ case floppy_image::SSDD:
+ actual_variant = floppy_image::SSSD16;
+ break;
+ case floppy_image::SSQD:
+ actual_variant = floppy_image::SSQD16;
+ break;
+ case floppy_image::DSSD:
+ actual_variant = floppy_image::DSSD16;
+ break;
+ case floppy_image::DSDD:
+ actual_variant = floppy_image::DSDD16;
+ break;
+ case floppy_image::DSQD:
+ actual_variant = floppy_image::DSQD16;
+ break;
+ }
+ } else if (m_sectoring_type == floppy_image::H32) {
+ switch (variant) {
+ case floppy_image::SSSD:
+ actual_variant = floppy_image::SSSD32;
+ break;
+ case floppy_image::SSDD:
+ actual_variant = floppy_image::SSDD32;
+ break;
+ case floppy_image::DSSD:
+ actual_variant = floppy_image::DSSD32;
+ break;
+ case floppy_image::DSDD:
+ actual_variant = floppy_image::DSDD32;
+ break;
+ }
}
+
+ m_variants.push_back(actual_variant);
}
-floppy_image_format_t *floppy_image_device::get_formats() const
+void floppy_image_device::set_formats(std::function<void (format_registration &fr)> formats)
{
- return fif_list;
+ m_format_registration_cb = formats;
}
-floppy_image_format_t *floppy_image_device::get_load_format() const
+const std::vector<const floppy_image_format_t *> &floppy_image_device::get_formats() const
{
- return input_format;
+ return m_fif_list;
+}
+
+const floppy_image_format_t *floppy_image_device::get_load_format() const
+{
+ return m_input_format;
}
void floppy_image_device::set_rpm(float _rpm)
{
- if(rpm == _rpm)
+ if(m_rpm == _rpm)
return;
- rpm = _rpm;
- rev_time = attotime::from_double(60/rpm);
- floppy_ratio_1 = int(1000.0f*rpm/300.0f+0.5f);
+ m_rpm = _rpm;
+ m_rev_time = attotime::from_double(60/m_rpm);
+ m_angular_speed = m_rpm/60.0*2e8;
}
-void floppy_image_device::setup_write(floppy_image_format_t *_output_format)
+void floppy_image_device::set_sectoring_type(uint32_t sectoring_type)
{
- output_format = _output_format;
- commit_image();
+ m_sectoring_type = sectoring_type;
+}
+
+uint32_t floppy_image_device::get_sectoring_type()
+{
+ return m_sectoring_type;
+}
+
+void floppy_image_device::setup_write(const floppy_image_format_t *_output_format)
+{
+ m_output_format = _output_format;
+ if(m_image)
+ commit_image();
}
void floppy_image_device::commit_image()
{
- image_dirty = false;
- if(!output_format || !output_format->supports_save())
+ m_image_dirty = false;
+ if(!m_output_format || !m_output_format->supports_save())
+ return;
+
+ check_for_file();
+ auto io = util::random_read_write_fill(image_core_file(), 0xff);
+ if(!io) {
+ popmessage("Error, out of memory");
return;
- io_generic io;
- // Do _not_ remove this cast otherwise the pointer will be incorrect when used by the ioprocs.
- io.file = (device_image_interface *)this;
- io.procs = &image_ioprocs;
- io.filler = 0xff;
+ }
- osd_file::error err = image_core_file().truncate(0);
- if (err != osd_file::error::NONE)
- popmessage("Error, unable to truncate image: %d", int(err));
+ std::error_condition const err = image_core_file().truncate(0);
+ if (err)
+ popmessage("Error, unable to truncate image: %s", err.message());
- output_format->save(&io, image);
+ m_output_format->save(*io, m_variants, *m_image);
}
+void floppy_image_device::device_config_complete()
+{
+ m_rpm = 0;
+ m_motor_always_on = false;
+ m_dskchg_writable = false;
+ m_has_trk00_sensor = true;
+
+ setup_characteristics();
+ register_formats();
+}
+
+const software_list_loader &floppy_image_device::get_software_list_loader() const
+{
+ return image_software_list_loader::instance();
+}
+
+
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void floppy_image_device::device_start()
{
- rpm = 0;
- motor_always_on = false;
- dskchg_writable = false;
- has_trk00_sensor = true;
-
// better would be an extra parameter in the MCFG macro
- drive_index = atoi(owner()->basetag());
+ m_drive_index = atoi(owner()->basetag());
- idx = 0;
+ m_idx = 0;
/* motor off */
- mon = 1;
-
- cyl = 0;
- subcyl = 0;
- ss = 0;
- ds = -1;
- stp = 1;
- wpt = 0;
- dskchg = exists() ? 1 : 0;
- index_timer = timer_alloc(0);
- image_dirty = false;
- ready = true;
- ready_counter = 0;
+ m_mon = 1;
+
+ m_cyl = 0;
+ m_subcyl = 0;
+ m_ss = 0;
+ m_actual_ss = 0;
+ m_ds = -1;
+ m_stp = 1;
+ m_wpt = 0;
+ m_dskchg = exists() ? 1 : 0;
+ m_index_timer = timer_alloc(FUNC(floppy_image_device::index_resync), this);
+ m_image_dirty = false;
+ m_ready = true;
+ m_ready_counter = 0;
+ m_phases = 0;
- setup_characteristics();
if (m_make_sound) m_sound_out = subdevice<floppy_sound_device>(FLOPSND_TAG);
- save_item(NAME(dir));
- save_item(NAME(stp));
- save_item(NAME(wtg));
- save_item(NAME(mon));
- save_item(NAME(ss));
- save_item(NAME(ds));
- save_item(NAME(idx));
- save_item(NAME(wpt));
- save_item(NAME(rdy));
- save_item(NAME(dskchg));
- save_item(NAME(ready));
- save_item(NAME(rpm));
- save_item(NAME(floppy_ratio_1));
- save_item(NAME(revolution_start_time));
- save_item(NAME(rev_time));
- save_item(NAME(revolution_count));
- save_item(NAME(cyl));
- save_item(NAME(subcyl));
- save_item(NAME(cache_start_time));
- save_item(NAME(cache_end_time));
- save_item(NAME(cache_index));
- save_item(NAME(cache_entry));
- save_item(NAME(cache_weak));
- save_item(NAME(image_dirty));
- save_item(NAME(ready_counter));
+ save_item(NAME(m_dir));
+ save_item(NAME(m_stp));
+ save_item(NAME(m_wtg));
+ save_item(NAME(m_mon));
+ save_item(NAME(m_ss));
+ save_item(NAME(m_actual_ss));
+ save_item(NAME(m_ds));
+ save_item(NAME(m_idx));
+ save_item(NAME(m_wpt));
+ save_item(NAME(m_rdy));
+ save_item(NAME(m_dskchg));
+ save_item(NAME(m_ready));
+ save_item(NAME(m_rpm));
+ save_item(NAME(m_angular_speed));
+ save_item(NAME(m_revolution_start_time));
+ save_item(NAME(m_rev_time));
+ save_item(NAME(m_revolution_count));
+ save_item(NAME(m_cyl));
+ save_item(NAME(m_subcyl));
+ save_item(NAME(m_cache_start_time));
+ save_item(NAME(m_cache_end_time));
+ save_item(NAME(m_cache_index));
+ save_item(NAME(m_cache_entry));
+ save_item(NAME(m_cache_weak));
+ save_item(NAME(m_image_dirty));
+ save_item(NAME(m_ready_counter));
+ save_item(NAME(m_phases));
}
void floppy_image_device::device_reset()
@@ -381,143 +579,133 @@ void floppy_image_device::device_reset()
m_make_sound = m_sound_out->samples_loaded();
}
- revolution_start_time = attotime::never;
- revolution_count = 0;
- mon = 1;
+ m_revolution_start_time = attotime::never;
+ m_revolution_count = 0;
+ m_mon = 1;
set_ready(true);
- if(motor_always_on && image)
+ if(m_motor_always_on && m_image)
mon_w(0);
cache_clear();
}
-void floppy_image_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- index_resync();
-}
-
-floppy_image_format_t *floppy_image_device::identify(std::string filename)
+std::pair<std::error_condition, const floppy_image_format_t *> floppy_image_device::identify(std::string_view filename)
{
util::core_file::ptr fd;
std::string revised_path;
+ std::error_condition err = util::zippath_fopen(filename, OPEN_FLAG_READ, fd, revised_path);
+ if(err)
+ return{ err, nullptr };
- osd_file::error err = util::zippath_fopen(filename, OPEN_FLAG_READ, fd, revised_path);
- if(err != osd_file::error::NONE) {
- seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to open the image file");
- return nullptr;
- }
+ auto io = util::random_read_fill(std::move(fd), 0xff);
+ if(!io)
+ return{ std::errc::not_enough_memory, nullptr };
- io_generic io;
- io.file = fd.get();
- io.procs = &corefile_ioprocs_noclose;
- io.filler = 0xff;
int best = 0;
- floppy_image_format_t *best_format = nullptr;
- for (floppy_image_format_t *format = fif_list; format; format = format->next)
- {
- int score = format->identify(&io, form_factor);
+ const floppy_image_format_t *best_format = nullptr;
+ for(const floppy_image_format_t *format : m_fif_list) {
+ int score = format->identify(*io, m_form_factor, m_variants);
if(score > best) {
best = score;
best_format = format;
}
}
- fd.reset();
- return best_format;
+
+ if(best_format)
+ return{ std::error_condition(), best_format };
+ else
+ return{ image_error::INVALIDIMAGE, nullptr };
}
void floppy_image_device::init_floppy_load(bool write_supported)
{
cache_clear();
- revolution_start_time = mon ? attotime::never : machine().time();
- revolution_count = 0;
+ m_revolution_start_time = m_mon ? attotime::never : machine().time();
+ m_revolution_count = 0;
- index_resync();
+ index_resync(0);
- wpt = 1; // disk sleeve is covering the sensor
- if (!cur_wpt_cb.isnull())
- cur_wpt_cb(this, wpt);
+ m_wpt = 1; // disk sleeve is covering the sensor
+ if (!m_cur_wpt_cb.isnull())
+ m_cur_wpt_cb(this, m_wpt);
- wpt = is_readonly() || (!write_supported);
- if (!cur_wpt_cb.isnull())
- cur_wpt_cb(this, wpt);
+ m_wpt = is_readonly() || (!write_supported);
+ if (!m_cur_wpt_cb.isnull())
+ m_cur_wpt_cb(this, m_wpt);
- if (motor_always_on) {
+ if (m_motor_always_on) {
// When disk is inserted, start motor
mon_w(0);
- } else if(!mon)
- ready_counter = 2;
+ m_ready_counter = 2;
+
+ } else if(!m_mon)
+ m_ready_counter = 2;
- if (dskchg_writable)
- dskchg = 1;
+ if (m_dskchg_writable)
+ m_dskchg = 1;
}
-image_init_result floppy_image_device::call_load()
+std::pair<std::error_condition, std::string> floppy_image_device::call_load()
{
- io_generic io;
+ check_for_file();
+ auto io = util::random_read_fill(image_core_file(), 0xff);
+ if(!io)
+ return std::make_pair(std::errc::not_enough_memory, std::string());
- // Do _not_ remove this cast otherwise the pointer will be incorrect when used by the ioprocs.
- io.file = (device_image_interface *)this;
- io.procs = &image_ioprocs;
- io.filler = 0xff;
int best = 0;
- floppy_image_format_t *best_format = nullptr;
- for(floppy_image_format_t *format = fif_list; format; format = format->next) {
- int score = format->identify(&io, form_factor);
+ const floppy_image_format_t *best_format = nullptr;
+ for (const floppy_image_format_t *format : m_fif_list) {
+ int score = format->identify(*io, m_form_factor, m_variants);
+ if(score && format->extension_matches(filename()))
+ score |= floppy_image_format_t::FIFID_EXT;
if(score > best) {
best = score;
best_format = format;
}
}
- if(!best_format)
- {
- seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to identify the image format");
- return image_init_result::FAIL;
- }
+ if (!best_format)
+ return std::make_pair(image_error::INVALIDIMAGE, "Unable to identify image file format");
- image = global_alloc(floppy_image(tracks, sides, form_factor));
- if (!best_format->load(&io, form_factor, image))
- {
- seterror(IMAGE_ERROR_UNSUPPORTED, "Incompatible image format or corrupted data");
- global_free(image);
- image = nullptr;
- return image_init_result::FAIL;
+ m_image = std::make_unique<floppy_image>(m_tracks, m_sides, m_form_factor);
+ if (!best_format->load(*io, m_form_factor, m_variants, *m_image)) {
+ m_image.reset();
+ return std::make_pair(image_error::INVALIDIMAGE, "Incompatible image file format or corrupted data");
}
- output_format = is_readonly() ? nullptr : best_format;
+ m_output_format = is_readonly() ? nullptr : best_format;
- image_dirty = false;
+ m_image_dirty = false;
- init_floppy_load(output_format != nullptr);
+ init_floppy_load(m_output_format != nullptr);
- if (!cur_load_cb.isnull())
- return cur_load_cb(this);
+ if (!m_cur_load_cb.isnull())
+ m_cur_load_cb(this);
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
void floppy_image_device::call_unload()
{
cache_clear();
- dskchg = 0;
+ m_dskchg = 0;
- if (image) {
- if(image_dirty)
+ if (m_image) {
+ if(m_image_dirty)
commit_image();
- global_free(image);
- image = nullptr;
+ m_image.reset();
}
- wpt = 1; // disk sleeve is covering the sensor
- if (!cur_wpt_cb.isnull())
- cur_wpt_cb(this, wpt);
+ m_wpt = 1; // disk sleeve is covering the sensor
+ if (!m_cur_wpt_cb.isnull())
+ m_cur_wpt_cb(this, m_wpt);
- wpt = 0; // sensor is uncovered
- if (!cur_wpt_cb.isnull())
- cur_wpt_cb(this, wpt);
+ m_wpt = 0; // sensor is uncovered
+ if (!m_cur_wpt_cb.isnull())
+ m_cur_wpt_cb(this, m_wpt);
- if (!cur_unload_cb.isnull())
- cur_unload_cb(this);
+ if (!m_cur_unload_cb.isnull())
+ m_cur_unload_cb(this);
- if (motor_always_on) {
+ if (m_motor_always_on) {
// When disk is removed, stop motor
mon_w(1);
}
@@ -525,13 +713,13 @@ void floppy_image_device::call_unload()
set_ready(true);
}
-image_init_result floppy_image_device::call_create(int format_type, util::option_resolution *format_options)
+std::pair<std::error_condition, std::string> floppy_image_device::call_create(int format_type, util::option_resolution *format_options)
{
- image = global_alloc(floppy_image(tracks, sides, form_factor));
- output_format = nullptr;
+ m_image = std::make_unique<floppy_image>(m_tracks, m_sides, m_form_factor);
+ m_output_format = nullptr;
// search for a suitable format based on the extension
- for(floppy_image_format_t *i = fif_list; i; i = i->next)
+ for(const floppy_image_format_t *i : m_fif_list)
{
// only consider formats that actually support saving
if(!i->supports_save())
@@ -539,53 +727,78 @@ image_init_result floppy_image_device::call_create(int format_type, util::option
if (i->extension_matches(basename()))
{
- output_format = i;
+ m_output_format = i;
break;
}
+
+ // Use MFI as a default.
+ if (!strcmp(i->name(), "mfi"))
+ m_output_format = i;
}
- // did we find a suitable format?
- if (output_format == nullptr)
- {
- seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to identify the image format");
- return image_init_result::FAIL;
+ init_floppy_load(true);
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+void floppy_image_device::init_fs(const fs_info *fs, const fs::meta_data &meta)
+{
+ assert(m_image);
+ if (fs->m_type) {
+ std::vector<u8> img(fs->m_image_size);
+ fs::fsblk_vec_t blockdev(img);
+ auto cfs = fs->m_manager->mount(blockdev);
+ cfs->format(meta);
+
+ auto io = util::ram_read(img.data(), img.size(), 0xff);
+ fs->m_type->load(*io, floppy_image::FF_UNKNOWN, m_variants, *m_image);
+ } else {
+ fs::unformatted_image::format(fs->m_key, m_image.get());
}
- init_floppy_load(output_format != nullptr);
+ // intializing a file system makes the floppy dirty
+ m_image_dirty = true;
+}
- return image_init_result::PASS;
+/* write protect, active high
+ phase 1 can force it to 1 for drive detection
+ on the rare drives that actually use m_phases.
+ */
+bool floppy_image_device::wpt_r()
+{
+ return m_wpt || (m_phases & 2);
}
/* motor on, active low */
void floppy_image_device::mon_w(int state)
{
- if(mon == state)
+ if(m_mon == state)
return;
- mon = state;
+ m_mon = state;
/* off -> on */
- if (!mon && image)
+ if (!m_mon && m_image)
{
- revolution_start_time = machine().time();
+ m_revolution_start_time = machine().time();
cache_clear();
- if (motor_always_on) {
+ if (m_motor_always_on) {
// Drives with motor that is always spinning are immediately ready when a disk is loaded
// because there is no spin-up time
set_ready(false);
} else {
- ready_counter = 2;
+ m_ready_counter = 2;
}
- index_resync();
+ index_resync(0);
}
/* on -> off */
else {
- if(image_dirty)
+ if(m_image_dirty)
commit_image();
cache_clear();
- revolution_start_time = attotime::never;
- index_timer->adjust(attotime::zero);
+ m_revolution_start_time = attotime::never;
+ m_index_timer->adjust(attotime::zero);
set_ready(true);
}
@@ -595,128 +808,153 @@ void floppy_image_device::mon_w(int state)
attotime floppy_image_device::time_next_index()
{
- if(revolution_start_time.is_never())
+ if(m_revolution_start_time.is_never())
return attotime::never;
- return revolution_start_time + rev_time;
+ return m_revolution_start_time + m_rev_time;
}
-/* index pulses at rpm/60 Hz, and stays high for ~2ms at 300rpm */
-void floppy_image_device::index_resync()
+/* index pulses at m_rpm/60 Hz, and stays high for ~2ms at 300rpm */
+TIMER_CALLBACK_MEMBER(floppy_image_device::index_resync)
{
- if(revolution_start_time.is_never()) {
- if(idx) {
- idx = 0;
- if (!cur_index_pulse_cb.isnull())
- cur_index_pulse_cb(this, idx);
+ if(m_revolution_start_time.is_never()) {
+ if(m_idx) {
+ m_idx = 0;
+ if (!m_cur_index_pulse_cb.isnull())
+ m_cur_index_pulse_cb(this, m_idx);
}
return;
}
- attotime delta = machine().time() - revolution_start_time;
- while(delta >= rev_time) {
- delta -= rev_time;
- revolution_start_time += rev_time;
- revolution_count++;
+ attotime delta = machine().time() - m_revolution_start_time;
+ while(delta >= m_rev_time) {
+ delta -= m_rev_time;
+ m_revolution_start_time += m_rev_time;
+ m_revolution_count++;
}
- int position = (delta*floppy_ratio_1).as_ticks(1000000000/1000);
+ int position = int(delta.as_double()*m_angular_speed + 0.5);
- int new_idx = position < 20000;
+ uint32_t last_index = 0, next_index = 200000000;
+ // if hard-sectored floppy, has extra IDX pulses
+ if(m_image)
+ m_image->find_index_hole(position, last_index, next_index);
+ int new_idx = position - last_index < 2000000;
if(new_idx) {
- attotime index_up_time = attotime::from_nsec((2000000*1000)/floppy_ratio_1);
- index_timer->adjust(index_up_time - delta);
- } else
- index_timer->adjust(rev_time - delta);
-
- if(new_idx != idx) {
- idx = new_idx;
- if(idx && ready) {
- ready_counter--;
- if(!ready_counter) {
+ uint32_t index_up = last_index + 2000000;
+ attotime index_up_time = attotime::from_double(index_up/m_angular_speed);
+ m_index_timer->adjust(index_up_time - delta);
+ } else {
+ attotime next_index_time = next_index >= 200000000 ? m_rev_time : attotime::from_double(next_index/m_angular_speed);
+ m_index_timer->adjust(next_index_time - delta);
+ }
+
+ if(new_idx != m_idx) {
+ m_idx = new_idx;
+ if(m_idx && m_ready) {
+ m_ready_counter--;
+ if(!m_ready_counter) {
// logerror("Drive spun up\n");
set_ready(false);
}
}
- if (!cur_index_pulse_cb.isnull())
- cur_index_pulse_cb(this, idx);
+ if (!m_cur_index_pulse_cb.isnull())
+ m_cur_index_pulse_cb(this, m_idx);
}
}
bool floppy_image_device::ready_r()
{
- return ready;
+ return m_ready;
}
void floppy_image_device::set_ready(bool state)
{
- if (state != ready)
+ if (state != m_ready)
{
- ready = state;
+ m_ready = state;
check_led();
- if (!cur_ready_cb.isnull())
- cur_ready_cb(this, ready);
+ if (!m_cur_ready_cb.isnull())
+ m_cur_ready_cb(this, m_ready);
}
}
void floppy_image_device::check_led()
{
- if(!cur_led_cb.isnull())
- cur_led_cb(this, (ds == drive_index) && !ready ? 1 : 0);
-}
-
-double floppy_image_device::get_pos()
-{
- return index_timer->elapsed().as_double();
+ if(!m_cur_led_cb.isnull())
+ m_cur_led_cb(this, (m_ds == m_drive_index) && !m_ready ? 1 : 0);
}
bool floppy_image_device::twosid_r()
{
int tracks = 0, heads = 0;
- if (image) image->get_actual_geometry(tracks, heads);
+ if (m_image) m_image->get_actual_geometry(tracks, heads);
return heads == 1;
}
+bool floppy_image_device::floppy_is_hd()
+{
+ if (!m_image)
+ return false;
+ u32 const variant = m_image->get_variant();
+ return variant == floppy_image::DSHD;
+}
+
+bool floppy_image_device::floppy_is_ed()
+{
+ if (!m_image)
+ return false;
+ u32 const variant = m_image->get_variant();
+ return variant == floppy_image::DSED;
+}
+
+void floppy_image_device::track_changed()
+{
+}
+
void floppy_image_device::stp_w(int state)
{
// Before spin-up is done, ignore step pulses
// TODO: There are reports about drives supporting step operation with
// stopped spindle. Need to check that on real drives.
- // if (ready_counter > 0) return;
+ // if (m_ready_counter > 0) return;
- if ( stp != state ) {
+ if ( m_stp != state ) {
cache_clear();
- stp = state;
- if ( stp == 0 ) {
- int ocyl = cyl;
- if ( dir ) {
- if ( cyl ) cyl--;
+ m_stp = state;
+ if ( m_stp == 0 ) {
+ int ocyl = m_cyl;
+ if ( m_dir ) {
+ if ( m_cyl ) m_cyl--;
} else {
- if ( cyl < tracks-1 ) cyl++;
+ if ( m_cyl < m_tracks-1 ) m_cyl++;
}
- if(ocyl != cyl)
+ if(ocyl != m_cyl)
{
- if (TRACE_STEP) logerror("track %d\n", cyl);
+ if (TRACE_STEP) logerror("track %d\n", m_cyl);
// Do we want a stepper sound?
// We plan for 5 zones with possibly specific sounds
- if (m_make_sound) m_sound_out->step(cyl*5/tracks);
+ if (m_make_sound) m_sound_out->step(m_cyl*5/m_tracks);
+ track_changed();
}
/* Update disk detection if applicable */
- if (exists() && !dskchg_writable)
+ if (exists() && !m_dskchg_writable)
{
- if (dskchg==0) dskchg = 1;
+ if (m_dskchg==0) m_dskchg = 1;
}
}
- subcyl = 0;
+ m_subcyl = 0;
}
}
-void floppy_image_device::seek_phase_w(int phases)
+void floppy_image_device::seek_phase_w(int _phases)
{
- int cur_pos = (cyl << 2) | subcyl;
+ m_phases = _phases;
+
+ int cur_pos = (m_cyl << 2) | m_subcyl;
int req_pos;
- switch(phases) {
+ switch(m_phases) {
case 0x1: req_pos = 0; break;
case 0x3: req_pos = 1; break;
case 0x2: req_pos = 2; break;
@@ -739,20 +977,23 @@ void floppy_image_device::seek_phase_w(int phases)
next_pos -= 8;
if(next_pos < 0)
next_pos = 0;
- else if(next_pos > (tracks-1)*4)
- next_pos = (tracks-1)*4;
- cyl = next_pos >> 2;
- subcyl = next_pos & 3;
+ else if(next_pos > (m_tracks-1)*4)
+ next_pos = (m_tracks-1)*4;
+
+ m_cyl = next_pos >> 2;
+ m_subcyl = next_pos & 3;
cache_clear();
- if(TRACE_STEP && (next_pos != cur_pos))
- logerror("track %d.%d\n", cyl, subcyl);
+ if(next_pos != cur_pos) {
+ if (TRACE_STEP) logerror("track %d.%d\n", m_cyl, m_subcyl);
+ if (m_make_sound) m_sound_out->step(m_subcyl);
+ }
/* Update disk detection if applicable */
- if (exists() && !dskchg_writable)
- if (dskchg==0)
- dskchg = 1;
+ if (exists() && !m_dskchg_writable)
+ if (m_dskchg==0)
+ m_dskchg = 1;
}
// From http://burtleburtle.net/bob/hash/integer.html
@@ -767,99 +1008,69 @@ uint32_t floppy_image_device::hash32(uint32_t a) const
return a;
}
-int floppy_image_device::find_index(uint32_t position, const std::vector<uint32_t> &buf)const
-{
- int spos = (buf.size() >> 1)-1;
- int step;
- for(step=1; step<buf.size()+1; step<<=1) { }
- step >>= 1;
-
- for(;;) {
- if(spos >= int(buf.size()) || (spos > 0 && (buf[spos] & floppy_image::TIME_MASK) > position)) {
- spos -= step;
- step >>= 1;
- } else if(spos < 0 || (spos < int(buf.size())-1 && (buf[spos+1] & floppy_image::TIME_MASK) <= position)) {
- spos += step;
- step >>= 1;
- } else
- return spos;
- }
-}
-
uint32_t floppy_image_device::find_position(attotime &base, const attotime &when)
{
- base = revolution_start_time;
+ base = m_revolution_start_time;
attotime delta = when - base;
- while(delta >= rev_time) {
- delta -= rev_time;
- base += rev_time;
+ while(delta >= m_rev_time) {
+ delta -= m_rev_time;
+ base += m_rev_time;
}
while(delta < attotime::zero) {
- delta += rev_time;
- base -= rev_time;
+ delta += m_rev_time;
+ base -= m_rev_time;
}
- uint32_t res = (delta*floppy_ratio_1).as_ticks(1000000000/1000);
+ uint32_t res = uint32_t(delta.as_double()*m_angular_speed+0.5);
if (res >= 200000000) {
// Due to rounding errors in the previous operation,
// 'res' sometimes overflows 2E+8
res -= 200000000;
- base += rev_time;
+ base += m_rev_time;
}
return res;
}
-bool floppy_image_device::test_track_last_entry_warps(const std::vector<uint32_t> &buf) const
-{
- return !((buf[buf.size() - 1]^buf[0]) & floppy_image::MG_MASK);
-}
-
attotime floppy_image_device::position_to_time(const attotime &base, int position) const
{
- return base + attotime::from_nsec((int64_t(position)*2000/floppy_ratio_1+1)/2);
+ return base + attotime::from_double(position/m_angular_speed);
}
void floppy_image_device::cache_fill_index(const std::vector<uint32_t> &buf, int &index, attotime &base)
{
int cells = buf.size();
- if(index != 0 || !test_track_last_entry_warps(buf)) {
- cache_index = index;
- cache_start_time = position_to_time(base, buf[index] & floppy_image::TIME_MASK);
- } else {
- cache_index = cells - 1;
- cache_start_time = position_to_time(base - rev_time, buf[cache_index] & floppy_image::TIME_MASK);
- }
-
- cache_entry = buf[cache_index];
+ m_cache_index = index;
+ m_cache_start_time = position_to_time(base, buf[index] & floppy_image::TIME_MASK);
+ m_cache_entry = buf[m_cache_index];
index ++;
if(index >= cells) {
- index = test_track_last_entry_warps(buf) ? 1 : 0;
- base += rev_time;
+ index = 0;
+ base += m_rev_time;
}
- cache_end_time = position_to_time(base, buf[index] & floppy_image::TIME_MASK);
+ m_cache_end_time = position_to_time(base, buf[index] & floppy_image::TIME_MASK);
}
void floppy_image_device::cache_clear()
{
- cache_start_time = cache_end_time = cache_weak_start = attotime::zero;
- cache_index = 0;
- cache_entry = 0;
- cache_weak = false;
+ m_cache_start_time = m_cache_end_time = m_cache_weak_start = attotime::zero;
+ m_cache_index = 0;
+ m_cache_entry = 0;
+ m_cache_weak = false;
}
void floppy_image_device::cache_fill(const attotime &when)
{
- std::vector<uint32_t> &buf = image->get_buffer(cyl, ss, subcyl);
- uint32_t cells = buf.size();
+ std::vector<uint32_t> &buf = m_image->get_buffer(m_cyl, m_ss, m_subcyl);
+ uint32_t const cells = buf.size();
if(cells <= 1) {
- cache_start_time = attotime::zero;
- cache_end_time = attotime::never;
- cache_index = 0;
- cache_entry = cells == 1 ? buf[0] : floppy_image::MG_N;
+ m_cache_start_time = attotime::zero;
+ m_cache_end_time = attotime::never;
+ m_cache_index = 0;
+ m_cache_entry = (cells == 1) ? buf[0] : floppy_image::MG_N;
cache_weakness_setup();
return;
}
@@ -867,65 +1078,63 @@ void floppy_image_device::cache_fill(const attotime &when)
attotime base;
uint32_t position = find_position(base, when);
- int index = find_index(position, buf);
+ auto const it = std::upper_bound(
+ buf.begin(), buf.end(), position,
+ [] (uint32_t a, uint32_t b) { return a < (b & floppy_image::TIME_MASK); });
- if(index == -1) {
- // I suspect this should be an abort(), to check...
- cache_start_time = attotime::zero;
- cache_end_time = attotime::never;
- cache_index = 0;
- cache_entry = buf[0];
- cache_weakness_setup();
- return;
+ int index;
+ if(buf.begin() == it) {
+ base -= m_rev_time;
+ index = buf.size() - 1;
+ } else {
+ index = int(it - buf.begin()) - 1;
}
for(;;) {
cache_fill_index(buf, index, base);
- if(cache_end_time > when) {
+ if(m_cache_end_time > when) {
cache_weakness_setup();
- return;
+ break;
}
}
}
void floppy_image_device::cache_weakness_setup()
{
- u32 type = cache_entry & floppy_image::MG_MASK;
+ u32 type = m_cache_entry & floppy_image::MG_MASK;
if(type == floppy_image::MG_N || type == floppy_image::MG_D) {
- cache_weak = true;
- cache_weak_start = cache_start_time;
+ m_cache_weak = true;
+ m_cache_weak_start = m_cache_start_time;
return;
}
- cache_weak = cache_end_time.is_never() || (cache_end_time - cache_start_time >= attotime::from_usec(16));
- if(!cache_weak) {
- cache_weak_start = attotime::never;
+ m_cache_weak = m_cache_end_time.is_never() || (m_cache_end_time - m_cache_start_time >= m_amplifier_freakout_time);
+ if(!m_cache_weak) {
+ m_cache_weak_start = attotime::never;
return;
}
- cache_weak_start = cache_start_time + attotime::from_usec(16);
+ m_cache_weak_start = m_cache_start_time + attotime::from_usec(16);
}
attotime floppy_image_device::get_next_transition(const attotime &from_when)
{
- if(!image || mon)
+ if(!m_image || m_mon)
return attotime::never;
- if(from_when < cache_start_time || (!cache_end_time.is_never() && from_when >= cache_end_time))
+ if(from_when < m_cache_start_time || m_cache_start_time.is_zero() || (!m_cache_end_time.is_never() && from_when >= m_cache_end_time))
cache_fill(from_when);
- if(!cache_weak)
- return cache_end_time;
+ if(!m_cache_weak)
+ return m_cache_end_time;
// Put a flux transition in the middle of a 4us interval with a 50% probability
- int interval_index = (from_when - cache_weak_start).as_ticks(250000);
- if(interval_index < 0)
- interval_index = 0;
- attotime weak_time = cache_weak_start + attotime::from_ticks(interval_index*2+1, 500000);
+ uint64_t interval_index = (from_when < m_cache_weak_start) ? 0 : (from_when - m_cache_weak_start).as_ticks(250000);
+ attotime weak_time = m_cache_weak_start + attotime::from_ticks(interval_index*2+1, 500000);
for(;;) {
- if(weak_time >= cache_end_time)
- return cache_end_time;
+ if(weak_time >= m_cache_end_time)
+ return m_cache_end_time;
if(weak_time > from_when) {
- u32 test = hash32(hash32(hash32(hash32(revolution_count) ^ 0x4242) + cache_index) + interval_index);
+ u32 test = hash32(hash32(hash32(hash32(m_revolution_count) ^ 0x4242) + m_cache_index) + interval_index);
if(test & 1)
return weak_time;
}
@@ -934,180 +1143,187 @@ attotime floppy_image_device::get_next_transition(const attotime &from_when)
}
}
+bool floppy_image_device::writing_disabled() const
+{
+ // Disable writing when write protect is on or when, in the diskii
+ // case, phase 1 is 1
+ return m_wpt || (m_phases & 2);
+}
+
void floppy_image_device::write_flux(const attotime &start, const attotime &end, int transition_count, const attotime *transitions)
{
- if(!image || mon)
+ if(!m_image || m_mon)
return;
- image_dirty = true;
- attotime base;
- int start_pos = find_position(base, start);
- int end_pos = find_position(base, end);
+ if(writing_disabled())
+ return;
- std::vector<int> trans_pos(transition_count);
- for(int i=0; i != transition_count; i++)
- trans_pos[i] = find_position(base, transitions[i]);
+ m_image_dirty = true;
+ m_track_dirty = true;
+ cache_clear();
- std::vector<uint32_t> &buf = image->get_buffer(cyl, ss, subcyl);
+ std::vector<wspan> wspans(1);
- int index;
- if(!buf.empty())
- index = find_index(start_pos, buf);
- else {
- index = 0;
- buf.push_back(floppy_image::MG_N);
- }
+ attotime base;
+ wspans[0].start = find_position(base, start);
+ wspans[0].end = find_position(base, end);
- if(index && (buf[index] & floppy_image::TIME_MASK) == start_pos)
- index--;
+ for(int i=0; i != transition_count; i++)
+ wspans[0].flux_change_positions.push_back(find_position(base, transitions[i]));
- uint32_t cur_mg = buf[index] & floppy_image::MG_MASK;
- if(cur_mg == floppy_image::MG_N || cur_mg == floppy_image::MG_D)
- cur_mg = floppy_image::MG_A;
+ wspan_split_on_wrap(wspans);
- uint32_t pos = start_pos;
- int ti = 0;
- int cells = buf.size();
- while(pos != end_pos) {
- if(buf.size() < cells+10)
- buf.resize(cells+200);
- uint32_t next_pos;
- if(ti != transition_count)
- next_pos = trans_pos[ti++];
- else
- next_pos = end_pos;
- if(next_pos > pos)
- write_zone(&buf[0], cells, index, pos, next_pos, cur_mg);
- else {
- write_zone(&buf[0], cells, index, pos, 200000000, cur_mg);
- index = 0;
- write_zone(&buf[0], cells, index, 0, next_pos, cur_mg);
- }
- pos = next_pos;
- cur_mg = cur_mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A;
+ std::vector<uint32_t> &buf = m_image->get_buffer(m_cyl, m_ss, m_subcyl);
+
+ if(buf.empty()) {
+ buf.push_back(floppy_image::MG_N);
+ buf.push_back(floppy_image::MG_E | 199999999);
}
- buf.resize(cells);
-}
+ wspan_remove_damaged(wspans, buf);
+ wspan_write(wspans, buf);
-void floppy_image_device::write_zone(uint32_t *buf, int &cells, int &index, uint32_t spos, uint32_t epos, uint32_t mg)
-{
cache_clear();
- while(spos < epos) {
- while(index != cells-1 && (buf[index+1] & floppy_image::TIME_MASK) <= spos)
- index++;
-
- uint32_t ref_start = buf[index] & floppy_image::TIME_MASK;
- uint32_t ref_end = index == cells-1 ? 200000000 : buf[index+1] & floppy_image::TIME_MASK;
- uint32_t ref_mg = buf[index] & floppy_image::MG_MASK;
+}
- // Can't overwrite a damaged zone
- if(ref_mg == floppy_image::MG_D) {
- spos = ref_end;
- continue;
- }
+void floppy_image_device::wspan_split_on_wrap(std::vector<wspan> &wspans)
+{
+ int ne = wspans.size();
+ for(int i=0; i != ne; i++)
+ if(wspans[i].end < wspans[i].start) {
+ wspans.resize(wspans.size()+1);
+ auto &ws = wspans[i];
+ auto &we = wspans.back();
+ we.start = 0;
+ we.end = ws.end;
+ ws.end = 200000000;
+ int start = ws.start;
+ int split_index;
+ for(split_index = 0; split_index != ws.flux_change_positions.size(); split_index++)
+ if(ws.flux_change_positions[split_index] < start)
+ break;
+ if(split_index == 0)
+ std::swap(ws.flux_change_positions, we.flux_change_positions);
- // If the zone is of the type we want, we don't need to touch it
- if(ref_mg == mg) {
- spos = ref_end;
- continue;
+ else {
+ we.flux_change_positions.resize(ws.flux_change_positions.size() - split_index);
+ std::copy(ws.flux_change_positions.begin() + split_index, ws.flux_change_positions.end(), we.flux_change_positions.begin());
+ ws.flux_change_positions.erase(ws.flux_change_positions.begin() + split_index, ws.flux_change_positions.end());
+ }
}
+}
- // Check the overlaps, act accordingly
- if(spos == ref_start) {
- if(epos >= ref_end) {
- // Full overlap, that cell is dead, we need to see which ones we can extend
- uint32_t prev_mg = index != 0 ? buf[index-1] & floppy_image::MG_MASK : ~0;
- uint32_t next_mg = index != cells-1 ? buf[index+1] & floppy_image::MG_MASK : ~0;
- if(prev_mg == mg) {
- if(next_mg == mg) {
- // Both match, merge all three in one
- memmove(buf+index, buf+index+2, (cells-index-2)*sizeof(uint32_t));
- cells -= 2;
- index--;
-
- } else {
- // Previous matches, drop the current cell
- memmove(buf+index, buf+index+1, (cells-index-1)*sizeof(uint32_t));
- cells --;
- }
-
- } else {
- if(next_mg == mg) {
- // Following matches, extend it
- memmove(buf+index, buf+index+1, (cells-index-1)*sizeof(uint32_t));
- cells --;
- buf[index] = mg | spos;
- } else {
- // None match, convert the current cell
- buf[index] = mg | spos;
- index++;
- }
+void floppy_image_device::wspan_remove_damaged(std::vector<wspan> &wspans, const std::vector<uint32_t> &track)
+{
+ for(size_t pos = 0; pos != track.size(); pos++)
+ if((track[pos] & floppy_image::MG_MASK) == floppy_image::MG_D) {
+ int start = track[pos] & floppy_image::TIME_MASK;
+ int end = track[pos+1] & floppy_image::TIME_MASK;
+ int ne = wspans.size();
+ for(int i=0; i != ne; i++) {
+ // D range outside of span range
+ if(wspans[i].start > end || wspans[i].end <= start)
+ continue;
+
+ // D range covers span range
+ if(wspans[i].start >= start && wspans[i].end-1 <= end) {
+ wspans.erase(wspans.begin() + i);
+ i --;
+ ne --;
+ continue;
}
- spos = ref_end;
- } else {
- // Overlap at the start only
- // Check if we can just extend the previous cell
- if(index != 0 && (buf[index-1] & floppy_image::MG_MASK) == mg)
- buf[index] = ref_mg | epos;
- else {
- // Otherwise we need to insert a new cell
- if(index != cells-1)
- memmove(buf+index+1, buf+index, (cells-index)*sizeof(uint32_t));
- cells++;
- buf[index] = mg | spos;
- buf[index+1] = ref_mg | epos;
+ // D range covers the start of the span range
+ if(wspans[i].start >= start && wspans[i].end-1 > end) {
+ wspans[i].start = end+1;
+ while(!wspans[i].flux_change_positions.empty() && wspans[i].flux_change_positions[0] <= end)
+ wspans[i].flux_change_positions.erase(wspans[i].flux_change_positions.begin());
+ continue;
}
- spos = epos;
- }
- } else {
- if(epos >= ref_end) {
- // Overlap at the end only
- // If we can't just extend the following cell, we need to insert a new one
- if(index == cells-1 || (buf[index+1] & floppy_image::MG_MASK) != mg) {
- if(index != cells-1)
- memmove(buf+index+2, buf+index+1, (cells-index-1)*sizeof(uint32_t));
- cells++;
+ // D range covers the end of the span range
+ if(wspans[i].start < start && wspans[i].end-1 <= end) {
+ wspans[i].end = start;
+ while(!wspans[i].flux_change_positions.empty() && wspans[i].flux_change_positions[wspans[i].flux_change_positions.size()-1] >= start)
+ wspans[i].flux_change_positions.erase(wspans[i].flux_change_positions.end()-1);
+ continue;
}
- buf[index+1] = mg | spos;
- index++;
- spos = ref_end;
+ // D range is inside the span range, need to split
+ int id = wspans.size();
+ wspans.resize(id+1);
+ wspans[id].start = end+1;
+ wspans[id].end = wspans[i].end;
+ wspans[id].flux_change_positions = wspans[i].flux_change_positions;
+ wspans[i].end = start;
+ while(!wspans[i].flux_change_positions.empty() && wspans[i].flux_change_positions[wspans[i].flux_change_positions.size()-1] >= start)
+ wspans[i].flux_change_positions.erase(wspans[i].flux_change_positions.end()-1);
+ while(!wspans[id].flux_change_positions.empty() && wspans[id].flux_change_positions[0] <= end)
+ wspans[id].flux_change_positions.erase(wspans[id].flux_change_positions.begin());
+ }
+ }
+}
+
+void floppy_image_device::wspan_write(const std::vector<wspan> &wspans, std::vector<uint32_t> &track)
+{
+ for(const auto &ws : wspans) {
+ unsigned si, ei;
+ for(si = 0; si != track.size(); si++)
+ if((track[si] & floppy_image::TIME_MASK) >= ws.start)
+ break;
+ for(ei = si; ei != track.size(); ei++)
+ if((track[ei] & floppy_image::TIME_MASK) >= ws.end)
+ break;
+
+ // Reduce neutral zone at the start, if there's one
+ if(si != track.size() && (track[si] & floppy_image::MG_MASK) == floppy_image::MG_E) {
+ // Neutral zone is over the whole range, split it and adapt si/ei
+ if(si == ei) {
+ track.insert(track.begin() + si, floppy_image::MG_E | (ws.start-1));
+ track.insert(track.begin() + si + 1, (track[si-1] & floppy_image::MG_MASK) | ws.end);
+ si = ei = si+1;
} else {
- // Full inclusion
- // We need to split the zone in 3
- if(index != cells-1)
- memmove(buf+index+3, buf+index+1, (cells-index-1)*sizeof(uint32_t));
- cells += 2;
- buf[index+1] = mg | spos;
- buf[index+2] = ref_mg | epos;
- spos = epos;
+ // Reduce the zone size
+ track[si] = floppy_image::MG_E | (ws.start-1);
+ si ++;
}
}
+ // Check for a neutral zone at the end and reduce it if needed
+ if(ei != track.size() && (track[ei] & floppy_image::MG_MASK) == floppy_image::MG_E) {
+ track[ei-1] = floppy_image::MG_N | ws.end;
+ ei --;
+ }
+
+ // Clear the covered zone
+ track.erase(track.begin() + si, track.begin() + ei);
+
+ // Insert the flux changes
+ for(auto f : ws.flux_change_positions) {
+ track.insert(track.begin() + si, floppy_image::MG_F | f);
+ si ++;
+ }
}
}
void floppy_image_device::set_write_splice(const attotime &when)
{
- if(image) {
- image_dirty = true;
+ if(m_image && !m_mon) {
+ m_image_dirty = true;
attotime base;
int splice_pos = find_position(base, when);
- image->set_write_splice_position(cyl, ss, splice_pos, subcyl);
+ m_image->set_write_splice_position(m_cyl, m_ss, splice_pos, m_subcyl);
}
}
uint32_t floppy_image_device::get_form_factor() const
{
- return form_factor;
+ return m_form_factor;
}
uint32_t floppy_image_device::get_variant() const
{
- return image ? image->get_variant() : 0;
+ return m_image ? m_image->get_variant() : 0;
}
//===================================================================
@@ -1230,7 +1446,7 @@ void floppy_sound_device::device_start()
{
// What kind of drive do we have?
bool is525 = strstr(tag(), "525") != nullptr;
- set_samples_names(is525? floppy525_sample_names : floppy35_sample_names);
+ set_samples_names(is525 ? floppy525_sample_names : floppy35_sample_names);
m_motor_on = false;
@@ -1249,7 +1465,7 @@ void floppy_sound_device::device_start()
// If we don't have all samples, don't allocate a stream or access sample data.
if (m_loaded)
{
- m_sound = machine().sound().stream_alloc(*this, 0, 1, clock()); // per-floppy stream
+ m_sound = stream_alloc(0, 1, clock()); // per-floppy stream
}
register_for_save_states();
}
@@ -1268,13 +1484,16 @@ void floppy_sound_device::motor(bool running, bool withdisk)
if ((m_spin_playback_sample==QUIET || m_spin_playback_sample==SPIN_END) && running) // motor was either off or already spinning down
{
m_spin_samplepos = 0;
- m_spin_playback_sample = withdisk? SPIN_START_LOADED : SPIN_START_EMPTY; // (re)start the motor sound
+ m_spin_playback_sample = withdisk ? SPIN_START_LOADED : SPIN_START_EMPTY; // (re)start the motor sound
}
else
{
// Motor has been running and is turned off now
if ((m_spin_playback_sample == SPIN_EMPTY || m_spin_playback_sample == SPIN_LOADED) && !running)
+ {
+ m_spin_samplepos = 0;
m_spin_playback_sample = SPIN_END; // go to spin down sound when loop is finished
+ }
}
}
m_motor_on = running;
@@ -1343,6 +1562,9 @@ void floppy_sound_device::step(int zone)
}
}
}
+
+ // Start the new seek sound from the beginning.
+ m_seek_samplepos = 0;
}
// Changing the pitch does not always sound convincing
@@ -1373,27 +1595,26 @@ void floppy_sound_device::step(int zone)
// sound_stream_update - update the sound stream
//-------------------------------------------------
-void floppy_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void floppy_sound_device::sound_stream_update(sound_stream &stream)
{
// We are using only one stream, unlike the parent class
// Also, there is no need for interpolation, as we only expect
// one sample rate of 44100 for all samples
int16_t out;
- stream_sample_t *samplebuffer = outputs[0];
- int idx = 0;
+ int m_idx = 0;
int sampleend = 0;
- while (samples-- > 0)
+ for (int sampindex = 0; sampindex < stream.samples(); sampindex++)
{
out = 0;
// Motor sound
if (m_spin_playback_sample != QUIET)
{
- idx = m_spin_playback_sample;
- sampleend = m_sample[idx].data.size();
- out = m_sample[idx].data[m_spin_samplepos++];
+ m_idx = m_spin_playback_sample;
+ sampleend = m_sample[m_idx].data.size();
+ out = m_sample[m_idx].data[m_spin_samplepos++];
if (m_spin_samplepos >= sampleend)
{
@@ -1420,7 +1641,7 @@ void floppy_sound_device::sound_stream_update(sound_stream &stream, stream_sampl
// Spindown sample over, be quiet or restart if the
// motor has been restarted
if (m_motor_on)
- m_spin_playback_sample = m_with_disk? SPIN_START_LOADED : SPIN_START_EMPTY;
+ m_spin_playback_sample = m_with_disk ? SPIN_START_LOADED : SPIN_START_EMPTY;
else
m_spin_playback_sample = QUIET;
break;
@@ -1446,10 +1667,10 @@ void floppy_sound_device::sound_stream_update(sound_stream &stream, stream_sampl
{
m_seek_sound_timeout--;
- idx = m_step_base + m_seek_playback_sample;
- sampleend = m_sample[idx].data.size();
+ m_idx = m_step_base + m_seek_playback_sample;
+ sampleend = m_sample[m_idx].data.size();
// Mix it into the stream value
- out += m_sample[idx].data[(int)m_seek_samplepos];
+ out += m_sample[m_idx].data[(int)m_seek_samplepos];
// By adding different values than 1, we can change the playback speed
// This will be used to adjust the seek sound
m_seek_samplepos += m_seek_pitch;
@@ -1463,11 +1684,11 @@ void floppy_sound_device::sound_stream_update(sound_stream &stream, stream_sampl
// Stepper sound
if (m_step_playback_sample != QUIET)
{
- idx = m_step_base + m_step_playback_sample;
- sampleend = m_sample[idx].data.size();
+ m_idx = m_step_base + m_step_playback_sample;
+ sampleend = m_sample[m_idx].data.size();
// Mix it into the stream value
- out += m_sample[idx].data[m_step_samplepos++];
+ out += m_sample[m_idx].data[m_step_samplepos++];
if (m_step_samplepos >= sampleend)
{
// Step sample done
@@ -1478,7 +1699,7 @@ void floppy_sound_device::sound_stream_update(sound_stream &stream, stream_sampl
}
// Write to the stream buffer
- *(samplebuffer++) = out;
+ stream.put_int(0, sampindex, out, 32768);
}
}
@@ -1499,6 +1720,53 @@ DEFINE_DEVICE_TYPE(FLOPPYSOUND, floppy_sound_device, "flopsnd", "Floppy sound")
//**************************************************************************
//-------------------------------------------------
+// 3" single-sided single density
+//-------------------------------------------------
+
+floppy_3_sssd::floppy_3_sssd(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ floppy_image_device(mconfig, FLOPPY_3_SSSD, tag, owner, clock)
+{
+}
+
+floppy_3_sssd::~floppy_3_sssd()
+{
+}
+
+void floppy_3_sssd::setup_characteristics()
+{
+ m_form_factor = floppy_image::FF_3;
+ m_tracks = 42;
+ m_sides = 1;
+ set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+}
+
+//-------------------------------------------------
+// 3" double-sided single density
+//-------------------------------------------------
+
+floppy_3_dssd::floppy_3_dssd(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ floppy_image_device(mconfig, FLOPPY_3_DSSD, tag, owner, clock)
+{
+}
+
+floppy_3_dssd::~floppy_3_dssd()
+{
+}
+
+void floppy_3_dssd::setup_characteristics()
+{
+ m_form_factor = floppy_image::FF_3;
+ m_tracks = 42;
+ m_sides = 2;
+ set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::DSSD);
+}
+
+//-------------------------------------------------
// 3" single-sided double density
//-------------------------------------------------
@@ -1513,16 +1781,13 @@ floppy_3_ssdd::~floppy_3_ssdd()
void floppy_3_ssdd::setup_characteristics()
{
- form_factor = floppy_image::FF_3;
- tracks = 42;
- sides = 1;
+ m_form_factor = floppy_image::FF_3;
+ m_tracks = 42;
+ m_sides = 1;
set_rpm(300);
-}
-void floppy_3_ssdd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
}
//-------------------------------------------------
@@ -1540,17 +1805,42 @@ floppy_3_dsdd::~floppy_3_dsdd()
void floppy_3_dsdd::setup_characteristics()
{
- form_factor = floppy_image::FF_3;
- tracks = 42;
- sides = 2;
+ m_form_factor = floppy_image::FF_3;
+ m_tracks = 42;
+ m_sides = 2;
set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::DSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
+}
+
+//-------------------------------------------------
+// 3" double-sided quad density
+//-------------------------------------------------
+
+floppy_3_dsqd::floppy_3_dsqd(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ floppy_image_device(mconfig, FLOPPY_3_DSQD, tag, owner, clock)
+{
+}
+
+floppy_3_dsqd::~floppy_3_dsqd()
+{
}
-void floppy_3_dsdd::handled_variants(uint32_t *variants, int &var_count) const
+void floppy_3_dsqd::setup_characteristics()
{
- var_count = 0;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
+ m_form_factor = floppy_image::FF_3;
+ m_tracks = 84;
+ m_sides = 2;
+ set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::DSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
+ add_variant(floppy_image::DSQD);
}
//-------------------------------------------------
@@ -1568,17 +1858,13 @@ floppy_35_ssdd::~floppy_35_ssdd()
void floppy_35_ssdd::setup_characteristics()
{
- form_factor = floppy_image::FF_35;
- tracks = 84;
- sides = 1;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 84;
+ m_sides = 1;
set_rpm(300);
-}
-void floppy_35_ssdd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
}
//-------------------------------------------------
@@ -1596,18 +1882,14 @@ floppy_35_dd::~floppy_35_dd()
void floppy_35_dd::setup_characteristics()
{
- form_factor = floppy_image::FF_35;
- tracks = 84;
- sides = 2;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 84;
+ m_sides = 2;
set_rpm(300);
-}
-void floppy_35_dd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
}
//-------------------------------------------------
@@ -1625,19 +1907,15 @@ floppy_35_hd::~floppy_35_hd()
void floppy_35_hd::setup_characteristics()
{
- form_factor = floppy_image::FF_35;
- tracks = 84;
- sides = 2;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 84;
+ m_sides = 2;
set_rpm(300);
-}
-void floppy_35_hd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
- variants[var_count++] = floppy_image::DSHD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
+ add_variant(floppy_image::DSHD);
}
//-------------------------------------------------
@@ -1655,20 +1933,16 @@ floppy_35_ed::~floppy_35_ed()
void floppy_35_ed::setup_characteristics()
{
- form_factor = floppy_image::FF_35;
- tracks = 84;
- sides = 2;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 84;
+ m_sides = 2;
set_rpm(300);
-}
-void floppy_35_ed::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
- variants[var_count++] = floppy_image::DSHD;
- variants[var_count++] = floppy_image::DSED;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
+ add_variant(floppy_image::DSHD);
+ add_variant(floppy_image::DSED);
}
//-------------------------------------------------
@@ -1686,16 +1960,12 @@ floppy_525_sssd_35t::~floppy_525_sssd_35t()
void floppy_525_sssd_35t::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 35;
- sides = 1;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 35;
+ m_sides = 1;
set_rpm(300);
-}
-void floppy_525_sssd_35t::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
+ add_variant(floppy_image::SSSD);
}
//-------------------------------------------------
@@ -1713,16 +1983,37 @@ floppy_525_sd_35t::~floppy_525_sd_35t()
void floppy_525_sd_35t::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 35;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 35;
+ m_sides = 2;
set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::DSSD);
}
-void floppy_525_sd_35t::handled_variants(uint32_t *variants, int &var_count) const
+//-------------------------------------------------
+// 5.25" single-sided single density, VTECH edition
+//-------------------------------------------------
+
+floppy_525_vtech::floppy_525_vtech(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ floppy_image_device(mconfig, FLOPPY_525_VTECH, tag, owner, clock)
{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
+ m_amplifier_freakout_time = attotime::from_usec(64);
+}
+
+floppy_525_vtech::~floppy_525_vtech()
+{
+}
+
+void floppy_525_vtech::setup_characteristics()
+{
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 40;
+ m_sides = 1;
+ set_rpm(85);
+
+ add_variant(floppy_image::SSSD);
}
//-------------------------------------------------
@@ -1740,16 +2031,12 @@ floppy_525_sssd::~floppy_525_sssd()
void floppy_525_sssd::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 42;
- sides = 1;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 42;
+ m_sides = 1;
set_rpm(300);
-}
-void floppy_525_sssd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
+ add_variant(floppy_image::SSSD);
}
//-------------------------------------------------
@@ -1767,16 +2054,12 @@ floppy_525_sd::~floppy_525_sd()
void floppy_525_sd::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 42;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 42;
+ m_sides = 2;
set_rpm(300);
-}
-void floppy_525_sd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
+ add_variant(floppy_image::SSSD);
}
//-------------------------------------------------
@@ -1794,17 +2077,13 @@ floppy_525_ssdd::~floppy_525_ssdd()
void floppy_525_ssdd::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 42;
- sides = 1;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 42;
+ m_sides = 1;
set_rpm(300);
-}
-void floppy_525_ssdd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
}
//-------------------------------------------------
@@ -1822,18 +2101,14 @@ floppy_525_dd::~floppy_525_dd()
void floppy_525_dd::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 42;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 42;
+ m_sides = 2;
set_rpm(300);
-}
-void floppy_525_dd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
}
//-------------------------------------------------
@@ -1851,18 +2126,14 @@ floppy_525_ssqd::~floppy_525_ssqd()
void floppy_525_ssqd::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 84;
- sides = 1;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 84;
+ m_sides = 1;
set_rpm(300);
-}
-void floppy_525_ssqd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::SSQD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::SSQD);
}
//-------------------------------------------------
@@ -1880,21 +2151,17 @@ floppy_525_qd::~floppy_525_qd()
void floppy_525_qd::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 84;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 84;
+ m_sides = 2;
set_rpm(300);
-}
-void floppy_525_qd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::SSQD;
- variants[var_count++] = floppy_image::DSSD;
- variants[var_count++] = floppy_image::DSDD;
- variants[var_count++] = floppy_image::DSQD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::SSQD);
+ add_variant(floppy_image::DSSD);
+ add_variant(floppy_image::DSDD);
+ add_variant(floppy_image::DSQD);
}
//-------------------------------------------------
@@ -1912,21 +2179,17 @@ floppy_525_hd::~floppy_525_hd()
void floppy_525_hd::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 84;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 84;
+ m_sides = 2;
set_rpm(360);
-}
-void floppy_525_hd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::SSQD;
- variants[var_count++] = floppy_image::DSDD;
- variants[var_count++] = floppy_image::DSQD;
- variants[var_count++] = floppy_image::DSHD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::SSQD);
+ add_variant(floppy_image::DSDD);
+ add_variant(floppy_image::DSQD);
+ add_variant(floppy_image::DSHD);
}
//-------------------------------------------------
@@ -1944,17 +2207,13 @@ floppy_8_sssd::~floppy_8_sssd()
void floppy_8_sssd::setup_characteristics()
{
- form_factor = floppy_image::FF_8;
- tracks = 77;
- sides = 1;
- motor_always_on = true;
+ m_form_factor = floppy_image::FF_8;
+ m_tracks = 77;
+ m_sides = 1;
+ m_motor_always_on = true;
set_rpm(360);
-}
-void floppy_8_sssd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
+ add_variant(floppy_image::SSSD);
}
//-------------------------------------------------
@@ -1972,18 +2231,14 @@ floppy_8_dssd::~floppy_8_dssd()
void floppy_8_dssd::setup_characteristics()
{
- form_factor = floppy_image::FF_8;
- tracks = 77;
- sides = 2;
- motor_always_on = true;
+ m_form_factor = floppy_image::FF_8;
+ m_tracks = 77;
+ m_sides = 2;
+ m_motor_always_on = true;
set_rpm(360);
-}
-void floppy_8_dssd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::DSSD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::DSSD);
}
//-------------------------------------------------
@@ -2001,18 +2256,14 @@ floppy_8_ssdd::~floppy_8_ssdd()
void floppy_8_ssdd::setup_characteristics()
{
- form_factor = floppy_image::FF_8;
- tracks = 77;
- sides = 1;
- motor_always_on = true;
+ m_form_factor = floppy_image::FF_8;
+ m_tracks = 77;
+ m_sides = 1;
+ m_motor_always_on = true;
set_rpm(360);
-}
-void floppy_8_ssdd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
}
//-------------------------------------------------
@@ -2030,19 +2281,15 @@ floppy_8_dsdd::~floppy_8_dsdd()
void floppy_8_dsdd::setup_characteristics()
{
- form_factor = floppy_image::FF_8;
- tracks = 77;
- sides = 2;
- motor_always_on = true;
+ m_form_factor = floppy_image::FF_8;
+ m_tracks = 77;
+ m_sides = 2;
+ m_motor_always_on = true;
set_rpm(360);
-}
-void floppy_8_dsdd::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
}
@@ -2071,17 +2318,13 @@ epson_smd_165::~epson_smd_165()
void epson_smd_165::setup_characteristics()
{
- form_factor = floppy_image::FF_35;
- tracks = 40;
- sides = 2;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 40;
+ m_sides = 2;
set_rpm(300);
-}
-void epson_smd_165::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::DSSD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::DSSD);
}
//-------------------------------------------------
@@ -2122,18 +2365,14 @@ epson_sd_320::~epson_sd_320()
void epson_sd_320::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 40;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 40;
+ m_sides = 2;
set_rpm(300);
-}
-void epson_sd_320::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
}
//-------------------------------------------------
@@ -2154,18 +2393,47 @@ epson_sd_321::~epson_sd_321()
void epson_sd_321::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 40;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 40;
+ m_sides = 2;
set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
+}
+
+
+//-------------------------------------------------
+// 3.5" Panasonic Flexible Disk Drive JU-363
+//
+// track to track: 3 ms
+// settling time: 15 ms
+// motor start time: 500 ms
+// transfer rate: 250 Kbits/s
+//
+//-------------------------------------------------
+
+pana_ju_363::pana_ju_363(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ floppy_image_device(mconfig, PANA_JU_363, tag, owner, clock)
+{
+}
+
+pana_ju_363::~pana_ju_363()
+{
}
-void epson_sd_321::handled_variants(uint32_t *variants, int &var_count) const
+void pana_ju_363::setup_characteristics()
{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 84;
+ m_sides = 2;
+ m_dskchg_writable = true;
+ set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
}
//-------------------------------------------------
@@ -2189,18 +2457,14 @@ sony_oa_d31v::~sony_oa_d31v()
void sony_oa_d31v::setup_characteristics()
{
- form_factor = floppy_image::FF_35;
- tracks = 70;
- sides = 1;
- dskchg_writable = true;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 70;
+ m_sides = 1;
+ m_dskchg_writable = true;
set_rpm(600);
-}
-void sony_oa_d31v::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
}
//-------------------------------------------------
@@ -2225,19 +2489,15 @@ sony_oa_d32w::~sony_oa_d32w()
void sony_oa_d32w::setup_characteristics()
{
- form_factor = floppy_image::FF_35;
- tracks = 80;
- sides = 2;
- dskchg_writable = true;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 80;
+ m_sides = 2;
+ m_dskchg_writable = true;
set_rpm(600);
-}
-void sony_oa_d32w::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::DSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
}
//-------------------------------------------------
@@ -2262,18 +2522,14 @@ sony_oa_d32v::~sony_oa_d32v()
void sony_oa_d32v::setup_characteristics()
{
- form_factor = floppy_image::FF_35;
- tracks = 80;
- sides = 1;
- dskchg_writable = true;
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 80;
+ m_sides = 1;
+ m_dskchg_writable = true;
set_rpm(600);
-}
-void sony_oa_d32v::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
}
//-------------------------------------------------
@@ -2297,16 +2553,74 @@ teac_fd_30a::~teac_fd_30a()
void teac_fd_30a::setup_characteristics()
{
- form_factor = floppy_image::FF_3;
- tracks = 40;
- sides = 1;
+ m_form_factor = floppy_image::FF_3;
+ m_tracks = 40;
+ m_sides = 1;
set_rpm(300);
+
+ add_variant(floppy_image::SSDD);
}
-void teac_fd_30a::handled_variants(uint32_t *variants, int &var_count) const
+//-------------------------------------------------
+// TEAC FD-55A
+//
+// track to track: 6 ms
+// average: 93 ms
+// setting time: 15 ms
+// motor start time: 400 ms
+//
+//-------------------------------------------------
+
+teac_fd_55a::teac_fd_55a(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : floppy_image_device(mconfig, TEAC_FD_55A, tag, owner, clock)
{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
+}
+
+teac_fd_55a::~teac_fd_55a()
+{
+}
+
+void teac_fd_55a::setup_characteristics()
+{
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 40;
+ m_sides = 1;
+ set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+}
+
+//-------------------------------------------------
+// TEAC FD-55B
+//
+// track to track: 6 ms
+// average: 93 ms
+// setting time: 15 ms
+// motor start time: 400 ms
+//
+//-------------------------------------------------
+
+teac_fd_55b::teac_fd_55b(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : floppy_image_device(mconfig, TEAC_FD_55B, tag, owner, clock)
+{
+}
+
+teac_fd_55b::~teac_fd_55b()
+{
+}
+
+void teac_fd_55b::setup_characteristics()
+{
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 40;
+ m_sides = 2;
+ set_rpm(300);
+
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSSD);
+ add_variant(floppy_image::DSDD);
}
//-------------------------------------------------
@@ -2330,18 +2644,14 @@ teac_fd_55e::~teac_fd_55e()
void teac_fd_55e::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 80;
- sides = 1;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 80;
+ m_sides = 1;
set_rpm(300);
-}
-void teac_fd_55e::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::SSQD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::SSQD);
}
//-------------------------------------------------
@@ -2365,21 +2675,17 @@ teac_fd_55f::~teac_fd_55f()
void teac_fd_55f::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 80;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 80;
+ m_sides = 2;
set_rpm(300);
-}
-void teac_fd_55f::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::SSQD;
- variants[var_count++] = floppy_image::DSSD;
- variants[var_count++] = floppy_image::DSDD;
- variants[var_count++] = floppy_image::DSQD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::SSQD);
+ add_variant(floppy_image::DSSD);
+ add_variant(floppy_image::DSDD);
+ add_variant(floppy_image::DSQD);
}
//-------------------------------------------------
@@ -2403,21 +2709,17 @@ teac_fd_55g::~teac_fd_55g()
void teac_fd_55g::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 77;
- sides = 2;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 77;
+ m_sides = 2;
set_rpm(360);
-}
-void teac_fd_55g::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
- variants[var_count++] = floppy_image::SSDD;
- variants[var_count++] = floppy_image::SSQD;
- variants[var_count++] = floppy_image::DSDD;
- variants[var_count++] = floppy_image::DSQD;
- variants[var_count++] = floppy_image::DSHD;
+ add_variant(floppy_image::SSSD);
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::SSQD);
+ add_variant(floppy_image::DSDD);
+ add_variant(floppy_image::DSQD);
+ add_variant(floppy_image::DSHD);
}
//-------------------------------------------------
@@ -2437,17 +2739,13 @@ alps_3255190x::~alps_3255190x()
void alps_3255190x::setup_characteristics()
{
- form_factor = floppy_image::FF_525;
- tracks = 84;
- sides = 1;
+ m_form_factor = floppy_image::FF_525;
+ m_tracks = 84;
+ m_sides = 1;
set_rpm(300);
- cyl = 34;
-}
+ m_cyl = 34;
-void alps_3255190x::handled_variants(uint32_t *variants, int &var_count) const
-{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
+ add_variant(floppy_image::SSSD);
}
//-------------------------------------------------
@@ -2465,16 +2763,314 @@ ibm_6360::~ibm_6360()
void ibm_6360::setup_characteristics()
{
- form_factor = floppy_image::FF_8;
- tracks = 77;
- sides = 1;
- motor_always_on = true;
- has_trk00_sensor = false;
+ m_form_factor = floppy_image::FF_8;
+ m_tracks = 77;
+ m_sides = 1;
+ m_motor_always_on = true;
+ m_has_trk00_sensor = false;
set_rpm(360);
+
+ add_variant(floppy_image::SSSD);
+}
+
+
+//-------------------------------------------------
+// Variable-speed Macintosh drives
+//-------------------------------------------------
+
+mac_floppy_device::mac_floppy_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : floppy_image_device(mconfig, type, tag, owner, clock)
+{
+ m_has_mfm = false;
+ m_dskchg_writable = true;
+}
+
+void mac_floppy_device::device_start()
+{
+ floppy_image_device::device_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_strb));
}
-void ibm_6360::handled_variants(uint32_t *variants, int &var_count) const
+void mac_floppy_device::device_reset()
{
- var_count = 0;
- variants[var_count++] = floppy_image::SSSD;
+ floppy_image_device::device_reset();
+ m_reg = 0;
+ m_strb = 0;
+ m_mfm = m_has_mfm;
+}
+
+// Initial state of bits f-c (2M, ready, MFM, rd1):
+// 0000 - 400K GCR drive
+// 0001 - 4MB Typhoon drive
+// x011 - Superdrive (x depends on the HD hole of the inserted disk, if any)
+// 1010 - 800K GCR drive
+// 1110 - HD-20 drive
+// 1111 - No drive (pull-up on the sense line)
+
+bool mac_floppy_device::writing_disabled() const
+{
+ return m_wpt;
+}
+
+bool mac_floppy_device::wpt_r()
+{
+ static const char *const regnames[16] = {
+ "Dir", "Step", "Motor", "Eject",
+ "RdData0", "Superdrive", "DoubleSide", "NoDrive",
+ "NoDiskInPl", "NoWrProtect", "NotTrack0", "NoTachPulse",
+ "RdData1", "MFMModeOn", "NoReady", "HD"
+ };
+
+ // m_actual_ss may have changed after the m_phases were set
+ m_reg = (m_reg & 7) | (m_actual_ss ? 8 : 0);
+
+ if(0 && (m_reg != 4 && m_reg != 12 && m_reg != 5 && m_reg != 13))
+ logerror("fdc disk sense reg %x %s %p\n", m_reg, regnames[m_reg], m_image.get());
+
+ switch(m_reg) {
+ case 0x0: // Step direction
+ return m_dir;
+
+ case 0x1: // Step signal
+ // We don't do the delay
+ return true;
+
+ case 0x2: // Is the motor on?
+ return m_mon;
+
+ case 0x3: // Disk change signal
+ return !m_dskchg;
+
+ case 0x4:
+ case 0xc: // Index pulse, probably only in mfm mode and while writing though
+ return !m_has_mfm ? false : !m_image || m_mon ? true : !m_idx;
+
+ case 0x5: // Is it a superdrive (supports 1.4M MFM) ?
+ return m_has_mfm;
+
+ case 0x6: // Is the drive double-sided?
+ return m_sides == 2;
+
+ case 0x7: // Does the drive exist?
+ return false;
+
+ case 0x8: // Is there a disk in the drive?
+ return m_image.get() == nullptr;
+
+ case 0x9: // Is the disk write-protected?
+ return !m_wpt;
+
+ case 0xa: // Not on track 0?
+ return m_cyl != 0;
+
+ case 0xb:{// Tachometer, 60 pulses/rotation
+ if(m_image.get() != nullptr && !m_mon) {
+ attotime base;
+ uint32_t pos = find_position(base, machine().time());
+ uint32_t subpos = pos % 3333334;
+ return subpos < 20000;
+ } else
+ return false;
+ }
+
+ case 0xd: // Is the current mode GCR or MFM?
+ return m_mfm;
+
+ case 0xe: // Is the floppy ready?
+ return m_ready;
+
+ case 0xf: // Does it implement the new interface *or* is the current disk is 1.4M MFM (superdrive only)
+ return is_2m();
+
+ default:
+ return false;
+ }
+}
+
+void mac_floppy_device::seek_phase_w(int phases)
+{
+ static const char *const regnames[16] = {
+ "DirNext", "StepOn", "MotorOn", "EjectOff",
+ "DirPrev", "StepOff", "MotorOff", "EjectOn",
+ "-", "MFMModeOn", "-", "-",
+ "DskchgClear", "GCRModeOn", "-", "-"
+ };
+
+ bool prev_strb = m_strb;
+
+ m_reg = (phases & 7) | (m_actual_ss ? 8 : 0);
+ m_strb = (phases >> 3) & 1;
+
+ if(m_strb && !prev_strb) {
+ switch(m_reg) {
+ case 0x0: // Step to cylinder + 1
+ logerror("cmd step dir +1\n");
+ dir_w(0);
+ break;
+
+ case 0x1: // Step on
+ logerror("cmd step on\n");
+ stp_w(0);
+ // There should be a delay, but it's not necessary
+ stp_w(1);
+ break;
+
+ case 0x2: // Motor on
+ logerror("cmd motor on\n");
+ floppy_image_device::mon_w(0);
+ break;
+
+ case 0x3: // End eject
+ logerror("cmd end eject\n");
+ break;
+
+ case 0x4: // Step to cylinder - 1
+ logerror("cmd step dir -1\n");
+ dir_w(1);
+ break;
+
+ case 0x6: // Motor off
+ logerror("cmd motor off\n");
+ floppy_image_device::mon_w(1);
+ break;
+
+ case 0x7: // Start eject
+ logerror("cmd start eject\n");
+ unload();
+ break;
+
+ case 0x9: // MFM mode on
+ logerror("cmd mfm on\n");
+ if(m_has_mfm) {
+ m_mfm = true;
+ track_changed();
+ }
+ break;
+
+ case 0xc: // Clear m_dskchg
+ logerror("cmd clear m_dskchg\n");
+ m_dskchg = 1;
+ break;
+
+ case 0xd: // GCR mode on
+ logerror("cmd gcr on\n");
+ m_mfm = false;
+ track_changed();
+ break;
+
+ default:
+ logerror("cmd reg %x %s\n", m_reg, regnames[m_reg]);
+ break;
+ }
+ }
+}
+
+void mac_floppy_device::track_changed()
+{
+ floppy_image_device::track_changed();
+
+ float new_rpm;
+ if(m_mfm)
+ new_rpm = is_2m() ? 600 : 300;
+ else if(m_cyl <= 15)
+ new_rpm = 394;
+ else if(m_cyl <= 31)
+ new_rpm = 429;
+ else if(m_cyl <= 47)
+ new_rpm = 472;
+ else if(m_cyl <= 63)
+ new_rpm = 525;
+ else
+ new_rpm = 590;
+
+ if(m_rpm != new_rpm)
+ set_rpm(new_rpm);
+}
+
+void mac_floppy_device::mon_w(int)
+{
+ // Motor control is through commands
+}
+
+void mac_floppy_device::tfsel_w(int state)
+{
+ // if 35SEL line is clear and the motor is on, turn off the motor
+ if ((state == CLEAR_LINE) && (!floppy_image_device::mon_r()))
+ {
+ floppy_image_device::mon_w(1);
+ }
+}
+
+oa_d34v_device::oa_d34v_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : mac_floppy_device(mconfig, OAD34V, tag, owner, clock)
+{
+}
+
+void oa_d34v_device::setup_characteristics()
+{
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 80;
+ m_sides = 1;
+ set_rpm(394);
+
+ add_variant(floppy_image::SSDD);
+}
+
+bool oa_d34v_device::is_2m() const
+{
+ return false;
+}
+
+void oa_d34v_device::track_changed()
+{
+ // Skip the m_rpm-setting mac generic version, the single-sided
+ // drive's m_rpm is externally controlled through a PWM signal.
+
+ floppy_image_device::track_changed();
+}
+
+mfd51w_device::mfd51w_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : mac_floppy_device(mconfig, MFD51W, tag, owner, clock)
+{
+}
+void mfd51w_device::setup_characteristics()
+{
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 80;
+ m_sides = 2;
+ set_rpm(394);
+
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
+}
+
+bool mfd51w_device::is_2m() const
+{
+ return true;
+}
+
+mfd75w_device::mfd75w_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : mac_floppy_device(mconfig, MFD75W, tag, owner, clock)
+{
+ m_has_mfm = true;
+}
+
+void mfd75w_device::setup_characteristics()
+{
+ m_form_factor = floppy_image::FF_35;
+ m_tracks = 80;
+ m_sides = 2;
+ set_rpm(300);
+
+ add_variant(floppy_image::SSDD);
+ add_variant(floppy_image::DSDD);
+ add_variant(floppy_image::DSHD);
+}
+
+bool mfd75w_device::is_2m() const
+{
+ if(!m_image)
+ return false;
+
+ if(m_image->get_variant() == floppy_image::SSDD || m_image->get_variant() == floppy_image::DSDD)
+ return true;
+
+ return false;
}
diff --git a/src/devices/imagedev/floppy.h b/src/devices/imagedev/floppy.h
index c2380d6d02b..2e7b0de3b50 100644
--- a/src/devices/imagedev/floppy.h
+++ b/src/devices/imagedev/floppy.h
@@ -6,46 +6,21 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_FLOPPY_H
-#define MAME_DEVICES_IMAGEDEV_FLOPPY_H
+#ifndef MAME_IMAGEDEV_FLOPPY_H
+#define MAME_IMAGEDEV_FLOPPY_H
#pragma once
-#include "formats/flopimg.h"
-#include "formats/d88_dsk.h"
-#include "formats/dfi_dsk.h"
-#include "formats/hxchfe_dsk.h"
-#include "formats/hxcmfm_dsk.h"
-#include "formats/imd_dsk.h"
-#include "formats/ipf_dsk.h"
-#include "formats/mfi_dsk.h"
-#include "formats/td0_dsk.h"
-#include "formats/cqm_dsk.h"
-#include "formats/dsk_dsk.h"
#include "sound/samples.h"
-#include "softlist_dev.h"
-
-#define DECLARE_FLOPPY_FORMATS(_name) \
- static const floppy_format_type _name []
-
-#define FLOPPY_FORMATS_MEMBER(_member) \
- const floppy_format_type _member [] = {
-#define FLOPPY_FORMATS_END0 \
- , \
- nullptr };
-#define FLOPPY_FORMATS_END \
- , \
- FLOPPY_D88_FORMAT, \
- FLOPPY_DFI_FORMAT, \
- FLOPPY_HFE_FORMAT, \
- FLOPPY_IMD_FORMAT, \
- FLOPPY_IPF_FORMAT, \
- FLOPPY_MFI_FORMAT, \
- FLOPPY_MFM_FORMAT, \
- FLOPPY_TD0_FORMAT, \
- FLOPPY_CQM_FORMAT, \
- FLOPPY_DSK_FORMAT \
- FLOPPY_FORMATS_END0
+
+// forward declarations
+class floppy_image;
+class floppy_image_format_t;
+
+namespace fs {
+ class manager_t;
+ class meta_data;
+};
class floppy_sound_device;
@@ -53,44 +28,87 @@ class floppy_sound_device;
TYPE DEFINITIONS
***************************************************************************/
+class format_registration {
+public:
+ format_registration();
+
+ void add(const floppy_image_format_t &format);
+ void add(const fs::manager_t &fs);
+
+ void add_fm_containers();
+ void add_mfm_containers();
+ void add_pc_formats();
+
+ std::vector<const floppy_image_format_t *> m_formats;
+ std::vector<const fs::manager_t *> m_fs;
+};
+
class floppy_image_device : public device_t,
- public device_image_interface,
- public device_slot_card_interface
+ public device_image_interface
{
public:
- typedef delegate<image_init_result (floppy_image_device *)> load_cb;
+ typedef delegate<void (floppy_image_device *)> load_cb;
typedef delegate<void (floppy_image_device *)> unload_cb;
typedef delegate<void (floppy_image_device *, int)> index_pulse_cb;
typedef delegate<void (floppy_image_device *, int)> ready_cb;
typedef delegate<void (floppy_image_device *, int)> wpt_cb;
typedef delegate<void (floppy_image_device *, int)> led_cb;
+ struct fs_info {
+ const fs::manager_t *m_manager;
+ const floppy_image_format_t *m_type;
+ u32 m_image_size;
+ const char *m_name;
+ u32 m_key;
+ const char *m_description;
+
+ fs_info(const fs::manager_t *manager, const floppy_image_format_t *type, u32 image_size, const char *name, const char *description) :
+ m_manager(manager),
+ m_type(type),
+ m_image_size(image_size),
+ m_name(name),
+ m_key(0),
+ m_description(description)
+ {}
+
+ fs_info(const char *name, u32 key, const char *description) :
+ m_manager(nullptr),
+ m_type(nullptr),
+ m_image_size(0),
+ m_name(name),
+ m_key(key),
+ m_description(description)
+ {}
+ };
+
// construction/destruction
virtual ~floppy_image_device();
- virtual void handled_variants(uint32_t *variants, int &var_count) const = 0;
-
- void set_formats(const floppy_format_type *formats);
- floppy_image_format_t *get_formats() const;
- floppy_image_format_t *get_load_format() const;
- floppy_image_format_t *identify(std::string filename);
+ void set_formats(std::function<void (format_registration &fr)> formats);
+ const std::vector<const floppy_image_format_t *> &get_formats() const;
+ const std::vector<fs_info> &get_fs() const { return m_fs; }
+ const floppy_image_format_t *get_load_format() const;
+ std::pair<std::error_condition, const floppy_image_format_t *> identify(std::string_view filename);
void set_rpm(float rpm);
+ void set_sectoring_type(uint32_t sectoring_type);
+ uint32_t get_sectoring_type();
+
+ void init_fs(const fs_info *fs, const fs::meta_data &meta);
- // image-level overrides
- virtual image_init_result call_load() override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual void call_unload() override;
- virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
- virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); }
- virtual const char *image_interface() const override = 0;
- virtual iodevice_t image_type() const override { return IO_FLOPPY; }
-
- virtual bool is_readable() const override { return true; }
- virtual bool is_writeable() const override { return true; }
- virtual bool is_creatable() const override { return true; }
- virtual bool must_be_loaded() const override { return false; }
- virtual bool is_reset_on_load() const override { return false; }
- virtual const char *file_extensions() const override { return extension_list; }
- void setup_write(floppy_image_format_t *output_format);
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
+ virtual const char *image_interface() const noexcept override = 0;
+
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return true; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *file_extensions() const noexcept override { return m_extension_list; }
+ virtual const char *image_type_name() const noexcept override { return "floppydisk"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "flop"; }
+ void setup_write(const floppy_image_format_t *output_format);
void setup_load_cb(load_cb cb);
void setup_unload_cb(unload_cb cb);
@@ -99,121 +117,153 @@ public:
void setup_wpt_cb(wpt_cb cb);
void setup_led_cb(led_cb cb);
- std::vector<uint32_t> &get_buffer() { return image->get_buffer(cyl, ss, subcyl); }
- int get_cyl() { return cyl; }
+ int get_cyl() const { return m_cyl; }
+ bool on_track() const { return !m_subcyl; }
- void mon_w(int state);
+ virtual void mon_w(int state);
bool ready_r();
void set_ready(bool state);
- double get_pos();
-
- bool wpt_r() { return wpt; }
- int dskchg_r() { return dskchg; }
- bool trk00_r() { return (has_trk00_sensor ? (cyl != 0) : 1); }
- int idx_r() { return idx; }
- int mon_r() { return mon; }
- bool ss_r() { return ss; }
+ virtual void tfsel_w(int state) { } // 35SEL line for Apple Sony drives
+
+ virtual bool wpt_r(); // Mac sony drives using this for various reporting
+ int dskchg_r() { return m_dskchg; }
+ bool trk00_r() { return (m_has_trk00_sensor ? (m_cyl != 0) : 1); }
+ int idx_r() { return m_idx; }
+ int mon_r() { return m_mon; }
+ bool ss_r() { return m_ss; }
bool twosid_r();
+ bool floppy_is_hd();
+ bool floppy_is_ed();
- void seek_phase_w(int phases);
+ virtual bool writing_disabled() const;
+
+ virtual void seek_phase_w(int phases);
void stp_w(int state);
- void dir_w(int state) { dir = state; }
- void ss_w(int state) { if (sides > 1) ss = state; }
+ void dir_w(int state) { m_dir = state; }
+ void ss_w(int state) { m_actual_ss = state; if (m_sides > 1) m_ss = state; }
void inuse_w(int state) { }
- void dskchg_w(int state) { if (dskchg_writable) dskchg = state; }
- void ds_w(int state) { ds = state; check_led(); }
+ void dskchg_w(int state) { if (m_dskchg_writable) m_dskchg = state; }
+ void ds_w(int state) { m_ds = state; check_led(); }
- void index_resync();
attotime time_next_index();
attotime get_next_transition(const attotime &from_when);
void write_flux(const attotime &start, const attotime &end, int transition_count, const attotime *transitions);
void set_write_splice(const attotime &when);
- int get_sides() { return sides; }
+ int get_sides() { return m_sides; }
uint32_t get_form_factor() const;
uint32_t get_variant() const;
- static const floppy_format_type default_floppy_formats[];
+ static void default_fm_floppy_formats(format_registration &fr);
+ static void default_mfm_floppy_formats(format_registration &fr);
+ static void default_pc_floppy_formats(format_registration &fr);
// Enable sound
void enable_sound(bool doit) { m_make_sound = doit; }
protected:
+ struct fs_enum;
+
floppy_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_config_complete() override;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
- virtual void device_add_mconfig(machine_config &config) override;
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override;
+ TIMER_CALLBACK_MEMBER(index_resync);
+
+ virtual void track_changed();
virtual void setup_characteristics() = 0;
void init_floppy_load(bool write_supported);
- floppy_image_format_t *input_format;
- floppy_image_format_t *output_format;
- floppy_image *image;
- char extension_list[256];
- floppy_image_format_t *fif_list;
- emu_timer *index_timer;
+ std::function<void (format_registration &fr)> m_format_registration_cb;
+ const floppy_image_format_t *m_input_format;
+ const floppy_image_format_t *m_output_format;
+ std::vector<uint32_t> m_variants;
+ std::unique_ptr<floppy_image> m_image;
+ char m_extension_list[256];
+ std::vector<const floppy_image_format_t *> m_fif_list;
+ std::vector<fs_info> m_fs;
+ std::vector<const fs::manager_t *> m_fs_managers;
+ emu_timer *m_index_timer;
/* Physical characteristics, filled by setup_characteristics */
- int tracks; /* addressable tracks */
- int sides; /* number of heads */
- uint32_t form_factor; /* 3"5, 5"25, etc */
- bool motor_always_on;
- bool dskchg_writable;
- bool has_trk00_sensor;
+ int m_tracks; /* addressable tracks */
+ int m_sides; /* number of heads */
+ uint32_t m_form_factor; /* 3"5, 5"25, etc */
+ uint32_t m_sectoring_type; /* SOFT, Hard 10/16/32 */
+ bool m_motor_always_on;
+ bool m_dskchg_writable;
+ bool m_has_trk00_sensor;
- int drive_index;
+ int m_drive_index;
/* state of input lines */
- int dir; /* direction */
- int stp; /* step */
- int wtg; /* write gate */
- int mon; /* motor on */
- int ss; /* side select */
- int ds; /* drive select */
+ int m_dir; /* direction */
+ int m_stp; /* step */
+ int m_wtg; /* write gate */
+ int m_mon; /* motor on */
+ int m_ss, m_actual_ss; /* side select (forced to 0 if single-sided drive / actual value) */
+ int m_ds; /* drive select */
+
+ int m_phases; /* phases lines, when they exist */
/* state of output lines */
- int idx; /* index pulse */
- int wpt; /* write protect */
- int rdy; /* ready */
- int dskchg; /* disk changed */
- bool ready;
+ int m_idx; /* index pulse */
+ int m_wpt; /* write protect */
+ int m_rdy; /* ready */
+ int m_dskchg; /* disk changed */
+ bool m_ready;
/* rotation per minute => gives index pulse frequency */
- float rpm;
- int floppy_ratio_1; // rpm/300*1000
-
- attotime revolution_start_time, rev_time;
- uint32_t revolution_count;
- int cyl, subcyl;
+ float m_rpm;
+ /* angular speed, where a full circle is 2e8 */
+ double m_angular_speed;
+ attotime m_revolution_start_time, m_rev_time;
+ uint32_t m_revolution_count;
+ int m_cyl, m_subcyl;
/* Current floppy zone cache */
- attotime cache_start_time, cache_end_time, cache_weak_start;
- int cache_index;
- u32 cache_entry;
- bool cache_weak;
+ attotime m_cache_start_time, m_cache_end_time, m_cache_weak_start;
+ attotime m_amplifier_freakout_time;
+ int m_cache_index;
+ u32 m_cache_entry;
+ bool m_cache_weak;
+
+ bool m_image_dirty, m_track_dirty;
+ int m_ready_counter;
+
+ load_cb m_cur_load_cb;
+ unload_cb m_cur_unload_cb;
+ index_pulse_cb m_cur_index_pulse_cb;
+ ready_cb m_cur_ready_cb;
+ wpt_cb m_cur_wpt_cb;
+ led_cb m_cur_led_cb;
+
+
+ // Temporary structure storing a write span
+ struct wspan {
+ int start, end;
+ std::vector<int> flux_change_positions;
+ };
- bool image_dirty;
- int ready_counter;
+ static void wspan_split_on_wrap(std::vector<wspan> &wspans);
+ static void wspan_remove_damaged(std::vector<wspan> &wspans, const std::vector<uint32_t> &track);
+ static void wspan_write(const std::vector<wspan> &wspans, std::vector<uint32_t> &track);
- load_cb cur_load_cb;
- unload_cb cur_unload_cb;
- index_pulse_cb cur_index_pulse_cb;
- ready_cb cur_ready_cb;
- wpt_cb cur_wpt_cb;
- led_cb cur_led_cb;
+ void register_formats();
+
+ void add_variant(uint32_t variant);
void check_led();
uint32_t find_position(attotime &base, const attotime &when);
- int find_index(uint32_t position, const std::vector<uint32_t> &buf) const;
- bool test_track_last_entry_warps(const std::vector<uint32_t> &buf) const;
attotime position_to_time(const attotime &base, int position) const;
- void write_zone(uint32_t *buf, int &cells, int &index, uint32_t spos, uint32_t epos, uint32_t mg);
void commit_image();
u32 hash32(u32 val) const;
@@ -233,21 +283,24 @@ protected:
public: \
Name(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); \
virtual ~Name(); \
- virtual void handled_variants(uint32_t *variants, int &var_count) const override; \
- virtual const char *image_interface() const override { return Interface; } \
+ virtual const char *image_interface() const noexcept override { return Interface; } \
protected: \
virtual void setup_characteristics() override; \
}; \
DECLARE_DEVICE_TYPE(Type, Name)
+DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_3_SSSD, floppy_3_sssd, "floppy_3")
+DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_3_DSSD, floppy_3_dssd, "floppy_3")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_3_SSDD, floppy_3_ssdd, "floppy_3")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_3_DSDD, floppy_3_dsdd, "floppy_3")
+DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_3_DSQD, floppy_3_dsqd, "floppy_3")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_35_SSDD, floppy_35_ssdd, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_35_DD, floppy_35_dd, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_35_HD, floppy_35_hd, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_35_ED, floppy_35_ed, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_SSSD_35T, floppy_525_sssd_35t, "floppy_5_25")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_SD_35T, floppy_525_sd_35t, "floppy_5_25")
+DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_VTECH, floppy_525_vtech, "floppy_5_25")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_SSSD, floppy_525_sssd, "floppy_5_25")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_SD, floppy_525_sd, "floppy_5_25")
DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_SSDD, floppy_525_ssdd, "floppy_5_25")
@@ -262,10 +315,13 @@ DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_8_DSDD, floppy_8_dsdd, "floppy_8"
DECLARE_FLOPPY_IMAGE_DEVICE(EPSON_SMD_165, epson_smd_165, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(EPSON_SD_320, epson_sd_320, "floppy_5_25")
DECLARE_FLOPPY_IMAGE_DEVICE(EPSON_SD_321, epson_sd_321, "floppy_5_25")
+DECLARE_FLOPPY_IMAGE_DEVICE(PANA_JU_363, pana_ju_363, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(SONY_OA_D31V, sony_oa_d31v, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(SONY_OA_D32W, sony_oa_d32w, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(SONY_OA_D32V, sony_oa_d32v, "floppy_3_5")
DECLARE_FLOPPY_IMAGE_DEVICE(TEAC_FD_30A, teac_fd_30a, "floppy_3")
+DECLARE_FLOPPY_IMAGE_DEVICE(TEAC_FD_55A, teac_fd_55a, "floppy_5_25")
+DECLARE_FLOPPY_IMAGE_DEVICE(TEAC_FD_55B, teac_fd_55b, "floppy_5_25")
DECLARE_FLOPPY_IMAGE_DEVICE(TEAC_FD_55E, teac_fd_55e, "floppy_5_25")
DECLARE_FLOPPY_IMAGE_DEVICE(TEAC_FD_55F, teac_fd_55f, "floppy_5_25")
DECLARE_FLOPPY_IMAGE_DEVICE(TEAC_FD_55G, teac_fd_55g, "floppy_5_25")
@@ -274,6 +330,70 @@ DECLARE_FLOPPY_IMAGE_DEVICE(IBM_6360, ibm_6360, "floppy_8"
DECLARE_DEVICE_TYPE(FLOPPYSOUND, floppy_sound_device)
+class mac_floppy_device : public floppy_image_device {
+public:
+ virtual ~mac_floppy_device() = default;
+
+ virtual bool wpt_r() override;
+ virtual void mon_w(int) override;
+ virtual void tfsel_w(int state) override;
+ virtual void seek_phase_w(int phases) override;
+ virtual const char *image_interface() const noexcept override { return "floppy_3_5"; }
+ virtual bool writing_disabled() const override;
+
+protected:
+ u8 m_reg;
+ bool m_strb;
+ bool m_mfm, m_has_mfm;
+
+ mac_floppy_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void track_changed() override;
+
+ virtual bool is_2m() const = 0;
+};
+
+// 400K GCR
+class oa_d34v_device : public mac_floppy_device {
+public:
+ oa_d34v_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual ~oa_d34v_device() = default;
+protected:
+ virtual void setup_characteristics() override;
+ virtual void track_changed() override;
+
+ virtual bool is_2m() const override;
+};
+
+// 400/800K GCR (e.g. dual-sided)
+class mfd51w_device : public mac_floppy_device {
+public:
+ mfd51w_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual ~mfd51w_device() = default;
+protected:
+ virtual void setup_characteristics() override;
+
+ virtual bool is_2m() const override;
+};
+
+// 400/800K GCR + 1.44 MFM (Superdrive)
+class mfd75w_device : public mac_floppy_device {
+public:
+ mfd75w_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual ~mfd75w_device() = default;
+
+protected:
+ virtual void setup_characteristics() override;
+
+ virtual bool is_2m() const override;
+};
+
+DECLARE_DEVICE_TYPE(OAD34V, oa_d34v_device)
+DECLARE_DEVICE_TYPE(MFD51W, mfd51w_device)
+DECLARE_DEVICE_TYPE(MFD75W, mfd75w_device)
+
/*
Floppy drive sound
@@ -289,11 +409,11 @@ public:
void register_for_save_states();
protected:
- void device_start() override;
+ void device_start() override ATTR_COLD;
private:
// device_sound_interface overrides
- void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream) override;
sound_stream* m_sound;
int m_step_base;
@@ -318,40 +438,47 @@ class floppy_connector: public device_t,
public device_slot_interface
{
public:
- template <typename T>
- floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, T &&opts, const char *dflt, const floppy_format_type formats[], bool fixed = false)
+
+ template <typename T, typename U>
+ floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, T &&opts, const char *dflt, U &&formats, bool fixed = false)
: floppy_connector(mconfig, tag, owner, 0)
{
option_reset();
opts(*this);
set_default_option(dflt);
set_fixed(fixed);
- set_formats(formats);
+ set_formats(std::forward<U>(formats));
}
- floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, const char *option, const device_type &devtype, bool is_default, const floppy_format_type formats[])
+
+ template <typename T>
+ floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, const char *option, device_type drivetype, bool is_default, T &&formats)
: floppy_connector(mconfig, tag, owner, 0)
{
option_reset();
- option_add(option, devtype);
+ option_add(option, drivetype);
if(is_default)
set_default_option(option);
set_fixed(false);
- set_formats(formats);
+ set_formats(std::forward<T>(formats));
}
+
floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual ~floppy_connector();
- void set_formats(const floppy_format_type formats[]);
- floppy_image_device *get_device();
+ template <typename T> void set_formats(T &&_formats) { formats = std::forward<T>(_formats); }
void enable_sound(bool doit) { m_enable_sound = doit; }
+ void set_sectoring_type(uint32_t sectoring_type) { m_sectoring_type = sectoring_type; }
+
+ floppy_image_device *get_device();
protected:
- virtual void device_start() override;
+ virtual void device_start() override ATTR_COLD;
virtual void device_config_complete() override;
private:
- const floppy_format_type *formats;
+ std::function<void (format_registration &fr)> formats;
bool m_enable_sound;
+ uint32_t m_sectoring_type;
};
@@ -361,4 +488,4 @@ DECLARE_DEVICE_TYPE(FLOPPY_CONNECTOR, floppy_connector)
extern template class device_finder<floppy_connector, false>;
extern template class device_finder<floppy_connector, true>;
-#endif // MAME_DEVICES_IMAGEDEV_FLOPPY_H
+#endif // MAME_IMAGEDEV_FLOPPY_H
diff --git a/src/devices/imagedev/harddriv.cpp b/src/devices/imagedev/harddriv.cpp
index cdb4f72e098..078131fca6b 100644
--- a/src/devices/imagedev/harddriv.cpp
+++ b/src/devices/imagedev/harddriv.cpp
@@ -17,9 +17,13 @@
#include "harddriv.h"
#include "emuopts.h"
+#include "fileio.h"
#include "harddisk.h"
#include "romload.h"
+#include "multibyte.h"
+#include "opresolv.h"
+
OPTION_GUIDE_START(hd_option_guide)
OPTION_INT('C', "cylinders", "Cylinders")
@@ -34,7 +38,17 @@ static char const *const hd_option_spec =
// device type definition
-DEFINE_DEVICE_TYPE(HARDDISK, harddisk_image_device, "harddisk_image", "Harddisk")
+DEFINE_DEVICE_TYPE(HARDDISK, harddisk_image_device, "harddisk_image", "Hard disk")
+
+//-------------------------------------------------
+// harddisk_image_base_device - constructor
+//-------------------------------------------------
+
+harddisk_image_base_device::harddisk_image_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_image_interface(mconfig, *this)
+{
+}
//-------------------------------------------------
// harddisk_image_device - constructor
@@ -48,14 +62,14 @@ harddisk_image_device::harddisk_image_device(const machine_config &mconfig, cons
//-------------------------------------------------
// harddisk_image_device - constructor for subclasses
//-------------------------------------------------
+
harddisk_image_device::harddisk_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- device_image_interface(mconfig, *this),
- m_chd(nullptr),
- m_hard_disk_handle(nullptr),
- m_device_image_load(load_delegate()),
- m_device_image_unload(unload_delegate()),
- m_interface(nullptr)
+ : harddisk_image_base_device(mconfig, type, tag, owner, clock)
+ , m_chd(nullptr)
+ , m_hard_disk_handle()
+ , m_device_image_load(*this)
+ , m_device_image_unload(*this)
+ , m_interface(nullptr)
{
}
@@ -89,49 +103,38 @@ const util::option_guide &harddisk_image_device::create_option_guide() const
void harddisk_image_device::device_start()
{
+ m_device_image_load.resolve();
+ m_device_image_unload.resolve();
+
m_chd = nullptr;
- // try to locate the CHD from a DISK_REGION
- chd_file *handle = machine().rom_load().get_disk_handle(tag());
- if (handle != nullptr)
- {
- m_hard_disk_handle = hard_disk_open(handle);
- }
+ if (has_preset_images())
+ setup_current_preset_image();
else
- {
- m_hard_disk_handle = nullptr;
- }
+ m_hard_disk_handle.reset();
}
void harddisk_image_device::device_stop()
{
- if (m_hard_disk_handle != nullptr)
- {
- hard_disk_close(m_hard_disk_handle);
- m_hard_disk_handle = nullptr;
- }
+ m_hard_disk_handle.reset();
}
-image_init_result harddisk_image_device::call_load()
+std::pair<std::error_condition, std::string> harddisk_image_device::call_load()
{
- image_init_result our_result;
-
- our_result = internal_load_hd();
+ std::error_condition our_result = internal_load_hd();
- /* Check if there is an image_load callback defined */
- if (!m_device_image_load.isnull())
+ // Check if there is an image_load callback defined
+ if (!our_result && !m_device_image_load.isnull())
{
- /* Let the override do some additional work/checks */
+ // Let the override do some additional work/checks
our_result = m_device_image_load(*this);
}
- return our_result;
+ return std::make_pair(our_result, std::string());
}
-image_init_result harddisk_image_device::call_create(int create_format, util::option_resolution *create_args)
+std::pair<std::error_condition, std::string> harddisk_image_device::call_create(int create_format, util::option_resolution *create_args)
{
- int err;
-
if (!create_args)
throw emu_fatalerror("harddisk_image_device::call_create: Expected create_args to not be nullptr");
@@ -143,33 +146,38 @@ image_init_result harddisk_image_device::call_create(int create_format, util::op
const uint32_t totalsectors = cylinders * heads * sectors;
- /* create the CHD file */
+ // create the CHD file
chd_codec_type compression[4] = { CHD_CODEC_NONE };
- err = m_origchd.create(image_core_file(), (uint64_t)totalsectors * (uint64_t)sectorsize, hunksize, sectorsize, compression);
- if (err != CHDERR_NONE)
- return image_init_result::FAIL;
-
- /* if we created the image and hence, have metadata to set, set the metadata */
+ util::core_file::ptr proxy;
+ std::error_condition err = util::core_file::open_proxy(image_core_file(), proxy);
+ if (!err)
+ err = m_origchd.create(std::move(proxy), uint64_t(totalsectors) * uint64_t(sectorsize), hunksize, sectorsize, compression);
+ if (err)
+ return std::make_pair(err, std::string());
+
+ // if we created the image and hence, have metadata to set, set the metadata
err = m_origchd.write_metadata(HARD_DISK_METADATA_TAG, 0, string_format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize));
m_origchd.close();
- if (err != CHDERR_NONE)
- return image_init_result::FAIL;
+ if (err)
+ return std::make_pair(err, std::string());
- return internal_load_hd();
+ return std::make_pair(internal_load_hd(), std::string());
+}
+
+void harddisk_image_device::setup_current_preset_image()
+{
+ chd_file *chd = current_preset_image_chd();
+ m_hard_disk_handle.reset(new hard_disk_file(chd));
}
void harddisk_image_device::call_unload()
{
- /* Check if there is an image_unload callback defined */
+ // Check if there is an image_unload callback defined
if (!m_device_image_unload.isnull())
m_device_image_unload(*this);
- if (m_hard_disk_handle != nullptr)
- {
- hard_disk_close(m_hard_disk_handle);
- m_hard_disk_handle = nullptr;
- }
+ m_hard_disk_handle.reset();
if (m_chd)
{
@@ -183,28 +191,28 @@ void harddisk_image_device::call_unload()
open_disk_diff - open a DISK diff file
-------------------------------------------------*/
-static chd_error open_disk_diff(emu_options &options, const char *name, chd_file &source, chd_file &diff_chd)
+static std::error_condition open_disk_diff(emu_options &options, const char *name, chd_file &source, chd_file &diff_chd)
{
std::string fname = std::string(name).append(".dif");
/* try to open the diff */
//printf("Opening differencing image file: %s\n", fname.c_str());
emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE);
- osd_file::error filerr = diff_file.open(fname.c_str());
- if (filerr == osd_file::error::NONE)
+ std::error_condition filerr = diff_file.open(fname);
+ if (!filerr)
{
std::string fullpath(diff_file.fullpath());
diff_file.close();
//printf("Opening differencing image file: %s\n", fullpath.c_str());
- return diff_chd.open(fullpath.c_str(), true, &source);
+ return diff_chd.open(fullpath, true, &source);
}
/* didn't work; try creating it instead */
//printf("Creating differencing image: %s\n", fname.c_str());
diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- filerr = diff_file.open(fname.c_str());
- if (filerr == osd_file::error::NONE)
+ filerr = diff_file.open(fname);
+ if (!filerr)
{
std::string fullpath(diff_file.fullpath());
diff_file.close();
@@ -212,29 +220,31 @@ static chd_error open_disk_diff(emu_options &options, const char *name, chd_file
/* create the CHD */
//printf("Creating differencing image file: %s\n", fupointllpath.c_str());
chd_codec_type compression[4] = { CHD_CODEC_NONE };
- chd_error err = diff_chd.create(fullpath.c_str(), source.logical_bytes(), source.hunk_bytes(), compression, source);
- if (err != CHDERR_NONE)
+ std::error_condition err = diff_chd.create(fullpath, source.logical_bytes(), source.hunk_bytes(), compression, source);
+ if (err)
return err;
return diff_chd.clone_all_metadata(source);
}
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
-image_init_result harddisk_image_device::internal_load_hd()
+std::error_condition harddisk_image_device::internal_load_hd()
{
- chd_error err = CHDERR_NONE;
+ if (has_preset_images())
+ {
+ setup_current_preset_image();
+ return std::error_condition();
+ }
+
+ std::error_condition err;
m_chd = nullptr;
uint8_t header[64];
- if (m_hard_disk_handle != nullptr)
- {
- hard_disk_close(m_hard_disk_handle);
- m_hard_disk_handle = nullptr;
- }
+ m_hard_disk_handle.reset();
- /* open the CHD file */
+ // open the CHD file
if (loaded_through_softlist())
{
m_chd = machine().rom_load().get_disk_handle(device().subtag("harddriv").c_str());
@@ -247,19 +257,25 @@ image_init_result harddisk_image_device::internal_load_hd()
if (!memcmp("MComprHD", header, 8))
{
- err = m_origchd.open(image_core_file(), true);
+ util::core_file::ptr proxy;
+ err = util::core_file::open_proxy(image_core_file(), proxy);
+ if (!err)
+ err = m_origchd.open(std::move(proxy), true);
- if (err == CHDERR_NONE)
+ if (!err)
{
m_chd = &m_origchd;
}
- else if (err == CHDERR_FILE_NOT_WRITEABLE)
+ else if (err == chd_file::error::FILE_NOT_WRITEABLE)
{
- err = m_origchd.open(image_core_file(), false);
- if (err == CHDERR_NONE)
+ err = util::core_file::open_proxy(image_core_file(), proxy);
+ if (!err)
+ err = m_origchd.open(std::move(proxy), false);
+
+ if (!err)
{
err = open_disk_diff(device().machine().options(), basename_noext(), m_origchd, m_diffchd);
- if (err == CHDERR_NONE)
+ if (!err)
{
m_chd = &m_diffchd;
}
@@ -268,69 +284,103 @@ image_init_result harddisk_image_device::internal_load_hd()
}
}
- if (m_chd != nullptr)
+ if (m_chd)
+ {
+ // open the hard disk file
+ try
+ {
+ m_hard_disk_handle.reset(new hard_disk_file(m_chd));
+ if (m_hard_disk_handle)
+ return std::error_condition();
+ }
+ catch (...)
+ {
+ err = image_error::INVALIDIMAGE;
+ }
+ }
+ else if (!is_open())
{
- /* open the hard disk file */
- m_hard_disk_handle = hard_disk_open(m_chd);
- if (m_hard_disk_handle != nullptr)
- return image_init_result::PASS;
+ err = image_error::UNSPECIFIED;
}
else
{
- if (is_open())
- {
- uint32_t skip = 0;
+ uint32_t skip = 0;
- // check for 2MG format
- if (!memcmp(header, "2IMG", 4))
+ if (!memcmp(header, "2IMG", 4)) // check for 2MG format
+ {
+ skip = get_u32le(&header[0x18]);
+ osd_printf_verbose("harddriv: detected 2MG, creator is %c%c%c%c, data at %08x\n", header[4], header[5], header[6], header[7], skip);
+ }
+ else if (is_filetype("hdi")) // check for HDI format
+ {
+ skip = get_u32le(&header[0x8]);
+ uint32_t data_size = get_u32le(&header[0xc]);
+ if (data_size == length() - skip)
{
- skip = header[0x18] | (header[0x19] << 8) | (header[0x1a] << 16) | (header[0x1b] << 24);
- osd_printf_verbose("harddriv: detected 2MG, creator is %c%c%c%c, data at %08x\n", header[4], header[5], header[6], header[7], skip);
+ osd_printf_verbose("harddriv: detected Anex86 HDI, data at %08x\n", skip);
}
- // check for HDI format
- else if (is_filetype("hdi"))
+ else
{
- skip = header[0x8] | (header[0x9] << 8) | (header[0xa] << 16) | (header[0xb] << 24);
- uint32_t data_size = header[0xc] | (header[0xd] << 8) | (header[0xe] << 16) | (header[0xf] << 24);
- if (data_size == image_core_file().size() - skip)
- {
- osd_printf_verbose("harddriv: detected Anex86 HDI, data at %08x\n", skip);
- }
- else
- {
- skip = 0;
- }
+ skip = 0;
}
-
- m_hard_disk_handle = hard_disk_open(image_core_file(), skip);
- if (m_hard_disk_handle != nullptr)
- return image_init_result::PASS;
}
- return image_init_result::FAIL;
+ try
+ {
+ m_hard_disk_handle.reset(new hard_disk_file(image_core_file(), skip));
+ if (m_hard_disk_handle)
+ return std::error_condition();
+ }
+ catch (...)
+ {
+ err = image_error::INVALIDIMAGE;
+ }
}
/* if we had an error, close out the CHD */
- m_origchd.close();
m_diffchd.close();
+ m_origchd.close();
m_chd = nullptr;
- seterror(IMAGE_ERROR_UNSPECIFIED, chd_file::error_string(err));
- return image_init_result::FAIL;
+ if (err)
+ return err;
+ else
+ return image_error::UNSPECIFIED;
}
-/*************************************
- *
- * Get the CHD file (from the src/chd.c core)
- * after an image has been opened with the hd core
- *
- *************************************/
+const hard_disk_file::info &harddisk_image_device::get_info() const
+{
+ return m_hard_disk_handle->get_info();
+}
-chd_file *harddisk_image_device::get_chd_file()
+bool harddisk_image_device::read(uint32_t lbasector, void *buffer)
{
- chd_file *result = nullptr;
- hard_disk_file *hd_file = get_hard_disk_file();
- if (hd_file)
- result = hard_disk_get_chd(hd_file);
- return result;
+ return m_hard_disk_handle->read(lbasector, buffer);
}
+
+bool harddisk_image_device::write(uint32_t lbasector, const void *buffer)
+{
+ return m_hard_disk_handle->write(lbasector, buffer);
+}
+
+
+bool harddisk_image_device::set_block_size(uint32_t blocksize)
+{
+ return m_hard_disk_handle->set_block_size(blocksize);
+}
+
+std::error_condition harddisk_image_device::get_inquiry_data(std::vector<uint8_t> &data) const
+{
+ return m_hard_disk_handle->get_inquiry_data(data);
+}
+
+std::error_condition harddisk_image_device::get_cis_data(std::vector<uint8_t> &data) const
+{
+ return m_hard_disk_handle->get_cis_data(data);
+}
+
+std::error_condition harddisk_image_device::get_disk_key_data(std::vector<uint8_t> &data) const
+{
+ return m_hard_disk_handle->get_disk_key_data(data);
+}
+
diff --git a/src/devices/imagedev/harddriv.h b/src/devices/imagedev/harddriv.h
index 65a13df10d3..852c1f3c79a 100644
--- a/src/devices/imagedev/harddriv.h
+++ b/src/devices/imagedev/harddriv.h
@@ -8,22 +8,49 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_HARDDRIV_H
-#define MAME_DEVICES_IMAGEDEV_HARDDRIV_H
+#ifndef MAME_IMAGEDEV_HARDDRIV_H
+#define MAME_IMAGEDEV_HARDDRIV_H
-#include "harddisk.h"
#include "softlist_dev.h"
+#include "chd.h"
+#include "harddisk.h"
+
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
+// ======================> harddisk_image_base_device
+
+class harddisk_image_base_device : public device_t, public device_image_interface
+{
+protected:
+ // construction/destruction
+ harddisk_image_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_image_interface implementation
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *image_type_name() const noexcept override { return "harddisk"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "hard"; }
+};
+
// ======================> harddisk_image_device
-class harddisk_image_device : public device_t,
- public device_image_interface
+class harddisk_image_device : public harddisk_image_base_device
{
public:
+ typedef device_delegate<std::error_condition (device_image_interface &)> load_delegate;
+ typedef device_delegate<void (device_image_interface &)> unload_delegate;
+
// construction/destruction
harddisk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, const char *intf)
: harddisk_image_device(mconfig, tag, owner, (uint32_t)0)
@@ -33,45 +60,48 @@ public:
harddisk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual ~harddisk_image_device();
- template <typename... T> void set_device_load(T &&... args) { m_device_image_load = load_delegate(std::forward<T>(args)...); }
- template <typename... T> void set_device_unload(T &&... args) { m_device_image_unload = unload_delegate(std::forward<T>(args)...); }
+ template <typename... T> void set_device_load(T &&... args) { m_device_image_load.set(std::forward<T>(args)...); }
+ template <typename... T> void set_device_unload(T &&... args) { m_device_image_unload.set(std::forward<T>(args)...); }
void set_interface(const char *interface) { m_interface = interface; }
- // image-level overrides
- virtual image_init_result call_load() override;
- virtual image_init_result call_create(int create_format, util::option_resolution *create_args) override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int create_format, util::option_resolution *create_args) override;
virtual void call_unload() override;
- virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
-
- virtual iodevice_t image_type() const override { return IO_HARDDISK; }
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 1; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override { return m_interface; }
- virtual const char *file_extensions() const override { return "chd,hd,hdv,2mg,hdi"; }
+ virtual bool image_is_chd_type() const noexcept override { return true; }
+ virtual const char *image_interface() const noexcept override { return m_interface; }
+ virtual const char *file_extensions() const noexcept override { return "chd,hd,hdv,2mg,hdi"; }
virtual const util::option_guide &create_option_guide() const override;
- // specific implementation
- hard_disk_file *get_hard_disk_file() { return m_hard_disk_handle; }
- chd_file *get_chd_file();
+ const hard_disk_file::info &get_info() const;
+ bool read(uint32_t lbasector, void *buffer);
+ bool write(uint32_t lbasector, const void *buffer);
+
+ bool set_block_size(uint32_t blocksize);
+
+ std::error_condition get_inquiry_data(std::vector<uint8_t> &data) const;
+ std::error_condition get_cis_data(std::vector<uint8_t> &data) const;
+ std::error_condition get_disk_key_data(std::vector<uint8_t> &data) const;
protected:
harddisk_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
+ // device_t implementation
virtual void device_config_complete() override;
- virtual void device_start() override;
- virtual void device_stop() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_stop() override ATTR_COLD;
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
- image_init_result internal_load_hd();
+ void setup_current_preset_image();
+ std::error_condition internal_load_hd();
chd_file *m_chd;
- chd_file m_origchd; /* handle to the original CHD */
- chd_file m_diffchd; /* handle to the diff CHD */
- hard_disk_file *m_hard_disk_handle;
+ chd_file m_origchd; // handle to the original CHD
+ chd_file m_diffchd; // handle to the diff CHD
+ std::unique_ptr<hard_disk_file> m_hard_disk_handle;
load_delegate m_device_image_load;
unload_delegate m_device_image_unload;
@@ -81,4 +111,4 @@ protected:
// device type definition
DECLARE_DEVICE_TYPE(HARDDISK, harddisk_image_device)
-#endif // MAME_DEVICES_IMAGEDEV_HARDDRIV_H
+#endif // MAME_IMAGEDEV_HARDDRIV_H
diff --git a/src/devices/imagedev/magtape.cpp b/src/devices/imagedev/magtape.cpp
new file mode 100644
index 00000000000..dd1754ff4e3
--- /dev/null
+++ b/src/devices/imagedev/magtape.cpp
@@ -0,0 +1,35 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/*********************************************************************
+
+ magtape.cpp
+
+ Base classes for magnetic tape image devices.
+
+ TODO: figure out how to best differentiate actual devices.
+ Perhaps multiple microtape types should be completely split from
+ both each other and 7-track/9-track magnetic tape?
+
+*********************************************************************/
+
+#include "emu.h"
+#include "magtape.h"
+
+#include "softlist_dev.h"
+
+
+magtape_image_device::magtape_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_image_interface(mconfig, *this)
+{
+}
+
+microtape_image_device::microtape_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : magtape_image_device(mconfig, type, tag, owner, clock)
+{
+}
+
+const software_list_loader &magtape_image_device::get_software_list_loader() const
+{
+ return image_software_list_loader::instance();
+}
diff --git a/src/devices/imagedev/magtape.h b/src/devices/imagedev/magtape.h
new file mode 100644
index 00000000000..200c5252925
--- /dev/null
+++ b/src/devices/imagedev/magtape.h
@@ -0,0 +1,56 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/*********************************************************************
+
+ magtape.h
+
+ Base classes for magnetic tape image devices.
+
+*********************************************************************/
+
+#ifndef MAME_IMAGEDEV_MAGTAPE_H
+#define MAME_IMAGEDEV_MAGTAPE_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> magtape_image_device
+
+class magtape_image_device : public device_t, public device_image_interface
+{
+public:
+ // image-level overrides
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return true; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual bool support_command_line_image_creation() const noexcept override { return true; }
+ virtual const char *image_type_name() const noexcept override { return "magtape"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "mtap"; }
+
+protected:
+ // construction/destruction
+ magtape_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override;
+};
+
+// ======================> microtape_image_device
+
+class microtape_image_device : public magtape_image_device
+{
+protected:
+ // construction/destruction
+ microtape_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // image-level overrides
+ virtual const char *image_type_name() const noexcept override { return "microtape"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "utap"; }
+};
+
+#endif // MAME_IMAGEDEV_MAGTAPE_H
diff --git a/src/devices/imagedev/memcard.cpp b/src/devices/imagedev/memcard.cpp
new file mode 100644
index 00000000000..a01a2375a12
--- /dev/null
+++ b/src/devices/imagedev/memcard.cpp
@@ -0,0 +1,18 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/*********************************************************************
+
+ memcard.cpp
+
+ Base class for memory card image devices.
+
+*********************************************************************/
+
+#include "emu.h"
+#include "memcard.h"
+
+
+device_memcard_image_interface::device_memcard_image_interface(const machine_config &mconfig, device_t &device)
+ : device_image_interface(mconfig, device)
+{
+}
diff --git a/src/devices/imagedev/memcard.h b/src/devices/imagedev/memcard.h
new file mode 100644
index 00000000000..8bc41fd1425
--- /dev/null
+++ b/src/devices/imagedev/memcard.h
@@ -0,0 +1,39 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/*********************************************************************
+
+ memcard.h
+
+ Base class for memory card image devices.
+
+*********************************************************************/
+
+#ifndef MAME_IMAGEDEV_MEMCARD_H
+#define MAME_IMAGEDEV_MEMCARD_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> device_memcard_image_interface
+
+class device_memcard_image_interface : public device_image_interface
+{
+public:
+ // image-level overrides
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return true; }
+ virtual bool support_command_line_image_creation() const noexcept override { return true; }
+ virtual const char *image_type_name() const noexcept override { return "memcard"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "memc"; }
+
+protected:
+ // construction/destruction
+ device_memcard_image_interface(const machine_config &mconfig, device_t &device);
+};
+
+#endif // MAME_IMAGEDEV_MEMCARD_H
diff --git a/src/devices/imagedev/mfmhd.cpp b/src/devices/imagedev/mfmhd.cpp
index 1d6d3574c07..ecb886676a0 100644
--- a/src/devices/imagedev/mfmhd.cpp
+++ b/src/devices/imagedev/mfmhd.cpp
@@ -270,24 +270,29 @@
**************************************************************************/
#include "emu.h"
-#include "harddisk.h"
+#include "romload.h"
#include "mfmhd.h"
+#include "util/ioprocs.h"
+#include "util/ioprocsfilter.h"
-#define TRACE_STEPS 0
-#define TRACE_SIGNALS 0
-#define TRACE_READ 0
-#define TRACE_WRITE 0
-#define TRACE_CACHE 0
-#define TRACE_BITS 0
-#define TRACE_DETAIL 0
-#define TRACE_TIMING 0
-#define TRACE_STATE 1
-#define TRACE_CONFIG 1
+#define LOG_WARN (1U << 1) // Warnings
+#define LOG_CONFIG (1U << 2) // Configuration
+#define LOG_STEPS (1U << 3) // Steps
+#define LOG_STEPSDETAIL (1U << 4) // Steps, more detail
+#define LOG_SIGNALS (1U << 5) // Signals
+#define LOG_READ (1U << 6) // Read operations
+#define LOG_WRITE (1U << 7) // Write operations
+#define LOG_BITS (1U << 8) // Bit transfer
+#define LOG_TIMING (1U << 9) // Timing
+
+
+#define VERBOSE (LOG_GENERAL | LOG_CONFIG | LOG_WARN)
+
+#include "logmacro.h"
enum
{
INDEX_TM = 0,
- SPINUP_TM,
SEEK_TM,
CACHE_TM
};
@@ -299,17 +304,9 @@ enum
STEP_SETTLE
};
-std::string mfm_harddisk_device::tts(const attotime &t)
-{
- char buf[256];
- int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
- return buf;
-}
-
mfm_harddisk_device::mfm_harddisk_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : harddisk_image_device(mconfig, type, tag, owner, clock),
- device_slot_card_interface(mconfig, *this),
+ : device_t(mconfig, type, tag, owner, clock),
+ device_image_interface(mconfig, *this),
m_index_timer(nullptr),
m_spinup_timer(nullptr),
m_seek_timer(nullptr),
@@ -352,10 +349,10 @@ mfm_harddisk_device::~mfm_harddisk_device()
void mfm_harddisk_device::device_start()
{
- m_index_timer = timer_alloc(INDEX_TM);
- m_spinup_timer = timer_alloc(SPINUP_TM);
- m_seek_timer = timer_alloc(SEEK_TM);
- m_cache_timer = timer_alloc(CACHE_TM);
+ m_index_timer = timer_alloc(FUNC(mfm_harddisk_device::index_timer), this);
+ m_spinup_timer = timer_alloc(FUNC(mfm_harddisk_device::recalibrate), this);
+ m_seek_timer = timer_alloc(FUNC(mfm_harddisk_device::seek_update), this);
+ m_cache_timer = timer_alloc(FUNC(mfm_harddisk_device::cache_update), this);
m_rev_time = attotime::from_hz(m_rpm/60);
m_index_timer->adjust(attotime::from_hz(m_rpm/60), 0, attotime::from_hz(m_rpm/60));
@@ -363,7 +360,7 @@ void mfm_harddisk_device::device_start()
m_current_cylinder = m_landing_zone; // Park position
m_spinup_timer->adjust(attotime::from_msec(m_spinupms));
- m_cache = global_alloc(mfmhd_trackimage_cache(machine()));
+ m_cache = std::make_unique<mfmhd_trackimage_cache>(machine());
// In 5 second periods, check whether the cache has dirty lines
m_cache_timer->adjust(attotime::from_msec(5000), 0, attotime::from_msec(5000));
@@ -408,7 +405,7 @@ void mfm_harddisk_device::device_reset()
void mfm_harddisk_device::device_stop()
{
- if (m_cache!=nullptr) global_free(m_cache);
+ m_cache.reset();
}
/*
@@ -416,129 +413,135 @@ void mfm_harddisk_device::device_stop()
because we need the number of cylinders, and for generic drives we get
them from the CHD.
*/
-image_init_result mfm_harddisk_device::call_load()
+std::pair<std::error_condition, std::string> mfm_harddisk_device::call_load()
{
- image_init_result loaded = harddisk_image_device::call_load();
+ std::error_condition err;
+
+ /* open the CHD file */
+ if (loaded_through_softlist())
+ {
+ m_chd = machine().rom_load().get_disk_handle(device().subtag("harddriv").c_str());
+ }
+ else
+ {
+ auto io = util::random_read_write_fill(image_core_file(), 0xff);
+ if (!io)
+ return std::make_pair(std::errc::not_enough_memory, std::string());
+
+ m_chd = new chd_file; // FIXME: this is never deleted
+ err = m_chd->open(std::move(io), true);
+ }
std::string devtag(tag());
devtag += ":format";
m_format->set_tag(devtag);
- if (loaded==image_init_result::PASS)
+ if (err)
{
- std::string metadata;
- chd_file* chdfile = get_chd_file();
+ LOGMASKED(LOG_WARN, "Could not load CHD\n");
+ return std::make_pair(err, std::string());
+ }
- if (chdfile==nullptr)
- {
- logerror("chdfile is null\n");
- return image_init_result::FAIL;
- }
+ if (!m_chd)
+ {
+ LOG("m_chd is null\n");
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
+ }
- // Read the hard disk metadata
- chd_error state = chdfile->read_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
- if (state != CHDERR_NONE)
- {
- logerror("Failed to read CHD metadata\n");
- return image_init_result::FAIL;
- }
+ // Read the hard disk metadata
+ std::string metadata;
+ std::error_condition state = m_chd->read_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
+ if (state)
+ return std::make_pair(state, "Failed to read CHD metadata");
- if (TRACE_CONFIG) logerror("CHD metadata: %s\n", metadata.c_str());
+ LOGMASKED(LOG_CONFIG, "CHD metadata: %s\n", metadata.c_str());
- // Parse the metadata
- mfmhd_layout_params param;
- param.encoding = m_encoding;
- if (TRACE_CONFIG) logerror("Set encoding to %d\n", m_encoding);
+ // Parse the metadata
+ mfmhd_layout_params param;
+ param.encoding = m_encoding;
+ LOGMASKED(LOG_CONFIG, "Set encoding to %d\n", m_encoding);
- if (sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &param.cylinders, &param.heads, &param.sectors_per_track, &param.sector_size) != 4)
- {
- logerror("Invalid CHD metadata\n");
- return image_init_result::FAIL;
- }
+ if (sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &param.cylinders, &param.heads, &param.sectors_per_track, &param.sector_size) != 4)
+ return std::make_pair(image_error::INVALIDIMAGE, "Invalid CHD metadata");
- if (TRACE_CONFIG) logerror("CHD image has geometry cyl=%d, head=%d, sect=%d, size=%d\n", param.cylinders, param.heads, param.sectors_per_track, param.sector_size);
+ LOGMASKED(LOG_CONFIG, "CHD image has geometry cyl=%d, head=%d, sect=%d, size=%d\n", param.cylinders, param.heads, param.sectors_per_track, param.sector_size);
- if (m_max_cylinders != 0 && (param.cylinders != m_max_cylinders || param.heads != m_max_heads))
- {
- throw emu_fatalerror("Image geometry does not fit this kind of hard drive: drive=(%d,%d), image=(%d,%d)", m_max_cylinders, m_max_heads, param.cylinders, param.heads);
- }
+ if (m_max_cylinders != 0 && (param.cylinders != m_max_cylinders || param.heads != m_max_heads))
+ {
+ // TODO: does this really need to be a fatal error?
+ throw emu_fatalerror("Image geometry does not fit this kind of hard drive: drive=(%d,%d), image=(%d,%d)", m_max_cylinders, m_max_heads, param.cylinders, param.heads);
+ }
- // MDM format specs
- param.interleave = 0;
- param.cylskew = 0;
- param.headskew = 0;
- param.write_precomp_cylinder = -1;
- param.reduced_wcurr_cylinder = -1;
+ // MDM format specs
+ param.interleave = 0;
+ param.cylskew = 0;
+ param.headskew = 0;
+ param.write_precomp_cylinder = -1;
+ param.reduced_wcurr_cylinder = -1;
- state = chdfile->read_metadata(MFM_HARD_DISK_METADATA_TAG, 0, metadata);
- if (state != CHDERR_NONE)
- {
- logerror("Failed to read CHD sector arrangement/recording specs, applying defaults\n");
- }
- else
- {
- sscanf(metadata.c_str(), MFMHD_REC_METADATA_FORMAT, &param.interleave, &param.cylskew, &param.headskew, &param.write_precomp_cylinder, &param.reduced_wcurr_cylinder);
- }
+ state = m_chd->read_metadata(MFM_HARD_DISK_METADATA_TAG, 0, metadata);
+ if (state)
+ LOGMASKED(LOG_WARN, "Failed to read CHD sector arrangement/recording specs, applying defaults\n");
+ else
+ sscanf(metadata.c_str(), MFMHD_REC_METADATA_FORMAT, &param.interleave, &param.cylskew, &param.headskew, &param.write_precomp_cylinder, &param.reduced_wcurr_cylinder);
- if (!param.sane_rec())
- {
- if (TRACE_CONFIG) logerror("Sector arrangement/recording specs have invalid values, applying defaults\n");
- param.reset_rec();
- }
- else
- if (TRACE_CONFIG) logerror("MFM HD rec specs: interleave=%d, cylskew=%d, headskew=%d, wpcom=%d, rwc=%d\n",
+ if (!param.sane_rec())
+ {
+ LOGMASKED(LOG_CONFIG, "Sector arrangement/recording specs have invalid values, applying defaults\n");
+ param.reset_rec();
+ }
+ else
+ {
+ LOGMASKED(LOG_CONFIG,
+ "MFM HD rec specs: interleave=%d, cylskew=%d, headskew=%d, wpcom=%d, rwc=%d\n",
param.interleave, param.cylskew, param.headskew, param.write_precomp_cylinder, param.reduced_wcurr_cylinder);
+ }
- state = chdfile->read_metadata(MFM_HARD_DISK_METADATA_TAG, 1, metadata);
- if (state != CHDERR_NONE)
- {
- logerror("Failed to read CHD track gap specs, applying defaults\n");
- }
- else
- {
- sscanf(metadata.c_str(), MFMHD_GAP_METADATA_FORMAT, &param.gap1, &param.gap2, &param.gap3, &param.sync, &param.headerlen, &param.ecctype);
- }
+ state = m_chd->read_metadata(MFM_HARD_DISK_METADATA_TAG, 1, metadata);
+ if (state)
+ LOGMASKED(LOG_WARN, "Failed to read CHD track gap specs, applying defaults\n");
+ else
+ sscanf(metadata.c_str(), MFMHD_GAP_METADATA_FORMAT, &param.gap1, &param.gap2, &param.gap3, &param.sync, &param.headerlen, &param.ecctype);
- if (!param.sane_gap())
- {
- if (TRACE_CONFIG) logerror("MFM HD gap specs have invalid values, applying defaults\n");
- param.reset_gap();
- }
- else
- if (TRACE_CONFIG) logerror("MFM HD gap specs: gap1=%d, gap2=%d, gap3=%d, sync=%d, headerlen=%d, ecctype=%d\n",
+ if (!param.sane_gap())
+ {
+ LOGMASKED(LOG_CONFIG, "MFM HD gap specs have invalid values, applying defaults\n");
+ param.reset_gap();
+ }
+ else
+ {
+ LOGMASKED(LOG_CONFIG,
+ "MFM HD gap specs: gap1=%d, gap2=%d, gap3=%d, sync=%d, headerlen=%d, ecctype=%d\n",
param.gap1, param.gap2, param.gap3, param.sync, param.headerlen, param.ecctype);
+ }
- m_format->set_layout_params(param);
+ m_format->set_layout_params(param);
- m_cache->init(this, m_trackimage_size, m_cachelines);
+ m_cache->init(this, m_trackimage_size, m_cachelines);
- // Head timing
- // We assume that the real times are 80% of the max times
- // The single-step time includes the settle time, so does the max time
- // From that we calculate the actual cylinder-by-cylinder time and the settle time
+ // Head timing
+ // We assume that the real times are 80% of the max times
+ // The single-step time includes the settle time, so does the max time
+ // From that we calculate the actual cylinder-by-cylinder time and the settle time
- m_actual_cylinders = param.cylinders;
+ m_actual_cylinders = param.cylinders;
- if (m_phys_cylinders == 0) m_phys_cylinders = m_actual_cylinders+1;
- if (m_landing_zone == 0) m_landing_zone = m_phys_cylinders-1;
+ if (m_phys_cylinders == 0) m_phys_cylinders = m_actual_cylinders+1;
+ if (m_landing_zone == 0) m_landing_zone = m_phys_cylinders-1;
- float realnext = (m_seeknext_time==0)? 10 : (m_seeknext_time * 0.8);
- float realmax = (m_maxseek_time==0)? (m_actual_cylinders * 0.2) : (m_maxseek_time * 0.8);
- float settle_us = ((m_actual_cylinders-1.0) * realnext - realmax) / (m_actual_cylinders-2.0) * 1000;
- float step_us = realnext * 1000 - settle_us;
- if (TRACE_CONFIG) logerror("Calculated settle time: %0.2f ms, step: %d us\n", settle_us/1000, (int)step_us);
+ float realnext = (m_seeknext_time==0)? 10 : (m_seeknext_time * 0.8);
+ float realmax = (m_maxseek_time==0)? (m_actual_cylinders * 0.2) : (m_maxseek_time * 0.8);
+ float settle_us = ((m_actual_cylinders-1.0) * realnext - realmax) / (m_actual_cylinders-2.0) * 1000;
+ float step_us = realnext * 1000 - settle_us;
+ LOGMASKED(LOG_CONFIG, "Calculated settle time: %0.2f ms, step: %d us\n", settle_us/1000, (int)step_us);
- m_settle_time = attotime::from_usec((int)settle_us);
- m_step_time = attotime::from_usec((int)step_us);
+ m_settle_time = attotime::from_usec((int)settle_us);
+ m_step_time = attotime::from_usec((int)step_us);
- m_current_cylinder = m_landing_zone;
- }
- else
- {
- logerror("Could not load CHD\n");
- }
- return loaded;
+ m_current_cylinder = m_landing_zone;
+
+ return std::make_pair(std::error_condition(), std::string());
}
const char *MFMHD_REC_METADATA_FORMAT = "IL:%d,CSKEW:%d,HSKEW:%d,WPCOM:%d,RWC:%d";
@@ -555,29 +558,26 @@ void mfm_harddisk_device::call_unload()
if (m_format->save_param(MFMHD_IL) && !params->equals_rec(oldparams))
{
- logerror("MFM HD sector arrangement and recording specs have changed; updating CHD metadata\n");
- chd_file* chdfile = get_chd_file();
-
- chd_error err = chdfile->write_metadata(MFM_HARD_DISK_METADATA_TAG, 0, string_format(MFMHD_REC_METADATA_FORMAT, params->interleave, params->cylskew, params->headskew, params->write_precomp_cylinder, params->reduced_wcurr_cylinder), 0);
- if (err != CHDERR_NONE)
+ LOGMASKED(LOG_WARN, "MFM HD sector arrangement and recording specs have changed; updating CHD metadata\n");
+ std::error_condition err = m_chd->write_metadata(MFM_HARD_DISK_METADATA_TAG, 0, string_format(MFMHD_REC_METADATA_FORMAT, params->interleave, params->cylskew, params->headskew, params->write_precomp_cylinder, params->reduced_wcurr_cylinder), 0);
+ if (err)
{
- logerror("Failed to save MFM HD sector arrangement/recording specs to CHD\n");
+ LOGMASKED(LOG_WARN, "Failed to save MFM HD sector arrangement/recording specs to CHD\n");
}
}
if (m_format->save_param(MFMHD_GAP1) && !params->equals_gap(oldparams))
{
- logerror("MFM HD track gap specs have changed; updating CHD metadata\n");
- chd_file* chdfile = get_chd_file();
-
- chd_error err = chdfile->write_metadata(MFM_HARD_DISK_METADATA_TAG, 1, string_format(MFMHD_GAP_METADATA_FORMAT, params->gap1, params->gap2, params->gap3, params->sync, params->headerlen, params->ecctype), 0);
- if (err != CHDERR_NONE)
+ LOGMASKED(LOG_WARN, "MFM HD track gap specs have changed; updating CHD metadata\n");
+ std::error_condition err = m_chd->write_metadata(MFM_HARD_DISK_METADATA_TAG, 1, string_format(MFMHD_GAP_METADATA_FORMAT, params->gap1, params->gap2, params->gap3, params->sync, params->headerlen, params->ecctype), 0);
+ if (err)
{
- logerror("Failed to save MFM HD track gap specs to CHD\n");
+ LOGMASKED(LOG_WARN, "Failed to save MFM HD track gap specs to CHD\n");
}
}
}
- harddisk_image_device::call_unload();
+
+ m_chd = nullptr;
}
void mfm_harddisk_device::setup_index_pulse_cb(index_pulse_cb cb)
@@ -612,104 +612,99 @@ attotime mfm_harddisk_device::track_end_time()
if (!m_revolution_start_time.is_never())
{
endtime = m_revolution_start_time + nexttime;
- if (TRACE_TIMING) logerror("Track start time = %s, end time = %s\n", tts(m_revolution_start_time).c_str(), tts(endtime).c_str());
+ LOGMASKED(LOG_TIMING, "Track start time = %s, end time = %s\n", (m_revolution_start_time).to_string(), (endtime).to_string());
}
return endtime;
}
-void mfm_harddisk_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(mfm_harddisk_device::index_timer)
{
- switch (id)
+ // Simple index hole handling. We assume that there is only a short pulse.
+ m_revolution_start_time = machine().time();
+ if (!m_index_pulse_cb.isnull())
{
- case INDEX_TM:
- // Simple index hole handling. We assume that there is only a short pulse.
- m_revolution_start_time = machine().time();
- if (!m_index_pulse_cb.isnull())
- {
- m_index_pulse_cb(this, ASSERT_LINE);
- m_index_pulse_cb(this, CLEAR_LINE);
- }
- break;
+ m_index_pulse_cb(this, ASSERT_LINE);
+ m_index_pulse_cb(this, CLEAR_LINE);
+ }
+}
- case SPINUP_TM:
- recalibrate();
- break;
+TIMER_CALLBACK_MEMBER(mfm_harddisk_device::recalibrate)
+{
+ LOGMASKED(LOG_STEPS, "Recalibrate to track 0\n");
+ direction_in_w(CLEAR_LINE);
+ while (-m_track_delta < m_phys_cylinders)
+ {
+ step_w(ASSERT_LINE);
+ step_w(CLEAR_LINE);
+ }
+}
- case CACHE_TM:
- m_cache->write_back_one();
+TIMER_CALLBACK_MEMBER(mfm_harddisk_device::seek_update)
+{
+ switch (m_step_phase)
+ {
+ case STEP_COLLECT:
+ // Collect timer has expired; start moving head
+ head_move();
break;
-
- case SEEK_TM:
- switch (m_step_phase)
+ case STEP_MOVING:
+ // Head has reached final position
+ // Check whether we have a new delta
+ if (m_track_delta == 0)
+ {
+ // Start the settle timer
+ m_step_phase = STEP_SETTLE;
+ m_seek_timer->adjust(m_settle_time);
+ LOGMASKED(LOG_STEPSDETAIL, "Arrived at target cylinder %d, settling ...[%s]\n", m_current_cylinder, machine().time().to_string());
+ }
+ else
{
- case STEP_COLLECT:
- // Collect timer has expired; start moving head
+ // need to move the head again
head_move();
- break;
- case STEP_MOVING:
- // Head has reached final position
- // Check whether we have a new delta
- if (m_track_delta == 0)
- {
- // Start the settle timer
- m_step_phase = STEP_SETTLE;
- m_seek_timer->adjust(m_settle_time);
- if (TRACE_STEPS && TRACE_DETAIL) logerror("Arrived at target cylinder %d, settling ...\n", m_current_cylinder);
- }
- else
+ }
+ break;
+ case STEP_SETTLE:
+ // Do we have new step pulses?
+ if (m_track_delta != 0) head_move();
+ else
+ {
+ // Seek completed
+ if (!m_recalibrated)
{
- // need to move the head again
- head_move();
+ m_ready = true;
+ m_recalibrated = true;
+ LOGMASKED(LOG_CONFIG, "Spinup complete, drive recalibrated and positioned at cylinder %d; drive is READY\n", m_current_cylinder);
+ if (!m_ready_cb.isnull()) m_ready_cb(this, ASSERT_LINE);
}
- break;
- case STEP_SETTLE:
- // Do we have new step pulses?
- if (m_track_delta != 0) head_move();
else
{
- // Seek completed
- if (!m_recalibrated)
- {
- m_ready = true;
- m_recalibrated = true;
- if (TRACE_STATE) logerror("Spinup complete, drive recalibrated and positioned at cylinder %d; drive is READY\n", m_current_cylinder);
- if (!m_ready_cb.isnull()) m_ready_cb(this, ASSERT_LINE);
- }
- else
- {
- if (TRACE_SIGNALS) logerror("Settling done at cylinder %d, seek complete\n", m_current_cylinder);
- }
- m_seek_complete = true;
- if (!m_seek_complete_cb.isnull()) m_seek_complete_cb(this, ASSERT_LINE);
- m_step_phase = STEP_COLLECT;
+ LOGMASKED(LOG_STEPSDETAIL, "Settling done at cylinder %d, seek complete [%s]\n", m_current_cylinder, machine().time().to_string());
}
- break;
+ m_seek_complete = true;
+ if (!m_seek_complete_cb.isnull()) m_seek_complete_cb(this, ASSERT_LINE);
+ m_step_phase = STEP_COLLECT;
}
+ break;
}
}
-void mfm_harddisk_device::recalibrate()
+TIMER_CALLBACK_MEMBER(mfm_harddisk_device::cache_update)
{
- if (TRACE_STEPS) logerror("Recalibrate to track 0\n");
- direction_in_w(CLEAR_LINE);
- while (-m_track_delta < m_phys_cylinders)
- {
- step_w(ASSERT_LINE);
- step_w(CLEAR_LINE);
- }
+ m_cache->write_back_one();
}
void mfm_harddisk_device::head_move()
{
int steps = m_track_delta;
if (steps < 0) steps = -steps;
- if (TRACE_STEPS) logerror("Moving head by %d step(s) %s\n", steps, (m_track_delta<0)? "outward" : "inward");
+ LOGMASKED(LOG_STEPS, "Moving head by %d step(s) %s\n", steps, (m_track_delta<0)? "outward" : "inward");
// We simulate the head movement by pausing for n*step_time with n being the cylinder delta
m_step_phase = STEP_MOVING;
m_seek_timer->adjust(m_step_time * steps);
- if (TRACE_TIMING) logerror("Head movement takes %s time\n", tts(m_step_time * steps).c_str());
+ long moveus = (m_step_time.attoseconds() * steps) / ATTOSECONDS_PER_MICROSECOND;
+ LOGMASKED(LOG_STEPSDETAIL, "Head movement takes %.1f ms time [%s]\n", moveus/1000., machine().time().to_string());
// We pretend that we already arrived
// TODO: Check auto truncation?
m_current_cylinder += m_track_delta;
@@ -720,8 +715,8 @@ void mfm_harddisk_device::head_move()
void mfm_harddisk_device::direction_in_w(line_state line)
{
+ if (m_seek_inward != (line == ASSERT_LINE)) LOGMASKED(LOG_STEPSDETAIL, "Setting seek direction %s\n", m_seek_inward? "inward" : "outward");
m_seek_inward = (line == ASSERT_LINE);
- if (TRACE_STEPS && TRACE_DETAIL) logerror("Setting seek direction %s\n", m_seek_inward? "inward" : "outward");
}
/*
@@ -772,10 +767,10 @@ void mfm_harddisk_device::step_w(line_state line)
// Counter will be adjusted according to the direction (+-1)
m_track_delta += (m_seek_inward)? +1 : -1;
- if (TRACE_STEPS && TRACE_DETAIL) logerror("Got seek pulse; track delta %d\n", m_track_delta);
+ LOGMASKED(LOG_STEPSDETAIL, "Got seek pulse; track delta %d\n", m_track_delta);
if (m_track_delta < -m_phys_cylinders || m_track_delta > m_phys_cylinders)
{
- if (TRACE_STEPS) logerror("Excessive step pulses - doing auto-truncation\n");
+ LOGMASKED(LOG_STEPS, "Excessive step pulses - doing auto-truncation\n");
m_autotruncation = true;
}
m_seek_timer->adjust(attotime::from_usec(250)); // Start step collect timer
@@ -808,7 +803,7 @@ bool mfm_harddisk_device::find_position(attotime &from_when, const attotime &lim
// Reached the end
if (bytepos >= m_trackimage_size)
{
- if (TRACE_TIMING) logerror("Reached end: rev_start = %s, live = %s\n", tts(m_revolution_start_time).c_str(), tts(from_when).c_str());
+ LOGMASKED(LOG_TIMING, "Reached end: rev_start = %s, live = %s\n", (m_revolution_start_time).to_string(), (from_when).to_string());
m_revolution_start_time += m_rev_time;
cell = (from_when - m_revolution_start_time).as_ticks(freq);
bytepos = cell / 16;
@@ -816,7 +811,7 @@ bool mfm_harddisk_device::find_position(attotime &from_when, const attotime &lim
if (bytepos < 0)
{
- if (TRACE_TIMING) logerror("Negative cell number: rev_start = %s, live = %s\n", tts(m_revolution_start_time).c_str(), tts(from_when).c_str());
+ LOGMASKED(LOG_TIMING, "Negative cell number: rev_start = %s, live = %s\n", (m_revolution_start_time).to_string(), (from_when).to_string());
bytepos = 0;
}
bit = cell % 16;
@@ -837,7 +832,9 @@ bool mfm_harddisk_device::read(attotime &from_when, const attotime &limit, uint1
if (track==nullptr)
{
// What shall we do in this case?
- throw emu_fatalerror("Cannot read CHD image");
+ // throw emu_fatalerror("Cannot read CHD image"); // a bit too harsh, just return a constant 0
+ cdata = 0;
+ return false;
}
// Get a copy for later debug output
@@ -853,12 +850,12 @@ bool mfm_harddisk_device::read(attotime &from_when, const attotime &limit, uint1
{
// We will deliver a single bit
cdata = ((track[bytepos] << bitpos) & 0x8000) >> 15;
- if (TRACE_BITS) logerror("Reading (c=%d,h=%d,bit=%d) at cell %d [%s] = %d\n", m_current_cylinder, m_current_head, bitpos, ((bytepos<<4) + bitpos), tts(fw).c_str(), cdata);
+ LOGMASKED(LOG_BITS, "Reading (c=%d,h=%d,bit=%d) at cell %d [%s] = %d\n", m_current_cylinder, m_current_head, bitpos, ((bytepos<<4) + bitpos), fw.to_string(), cdata);
}
else
{
// We will deliver a whole byte
- if (TRACE_READ) logerror("Reading (c=%d,h=%d) at position %d\n", m_current_cylinder, m_current_head, bytepos);
+ LOGMASKED(LOG_READ, "Reading (c=%d,h=%d) at position %d\n", m_current_cylinder, m_current_head, bytepos);
cdata = track[bytepos];
}
return false;
@@ -876,7 +873,8 @@ bool mfm_harddisk_device::write(attotime &from_when, const attotime &limit, uint
if (track==nullptr)
{
// What shall we do in this case?
- throw emu_fatalerror("Cannot read CHD image");
+ // throw emu_fatalerror("Cannot read CHD image"); // a bit too harsh, just return without doing anything
+ return false;
}
int bytepos = 0;
@@ -911,14 +909,14 @@ bool mfm_harddisk_device::write(attotime &from_when, const attotime &limit, uint
if (wpcom && (params->write_precomp_cylinder == -1 || m_current_cylinder < params->write_precomp_cylinder))
params->write_precomp_cylinder = m_current_cylinder;
- if (TRACE_WRITE) if ((bitpos&0x0f)==0) logerror("Wrote data=%04x (c=%d,h=%d) at position %04x, wpcom=%d, rwc=%d\n", track[bytepos], m_current_cylinder, m_current_head, bytepos, wpcom, reduced_wc);
+ if ((bitpos&0x0f)==0)
+ LOGMASKED(LOG_WRITE, "Wrote data=%04x (c=%d,h=%d) at position %04x, wpcom=%d, rwc=%d\n", track[bytepos], m_current_cylinder, m_current_head, bytepos, wpcom, reduced_wc);
return false;
}
-chd_error mfm_harddisk_device::load_track(uint16_t* data, int cylinder, int head)
+std::error_condition mfm_harddisk_device::load_track(uint16_t* data, int cylinder, int head)
{
- chd_error state = m_format->load(m_chd, data, m_trackimage_size, cylinder, head);
- return state;
+ return m_format->load(m_chd, data, m_trackimage_size, cylinder, head);
}
void mfm_harddisk_device::write_track(uint16_t* data, int cylinder, int head)
@@ -989,6 +987,9 @@ DEFINE_DEVICE_TYPE(MFMHD_ST251, mfm_hd_st251_device, "mfm_hd_st251", "Seagate ST
// This is a write-back LRU cache.
// ===========================================================
+#define TRACE_CACHE 0
+#define TRACE_DETAIL 0
+
mfmhd_trackimage_cache::mfmhd_trackimage_cache(running_machine &machine):
m_mfmhd(nullptr),
m_tracks(nullptr),
@@ -1003,9 +1004,8 @@ mfmhd_trackimage_cache::~mfmhd_trackimage_cache()
while (current != nullptr)
{
- global_free_array(current->encdata);
mfmhd_trackimage* currenttmp = current->next;
- global_free(current);
+ delete current;
current = currenttmp;
}
}
@@ -1018,7 +1018,7 @@ void mfmhd_trackimage_cache::write_back_one()
{
if (current->dirty)
{
- m_mfmhd->write_track(current->encdata, current->cylinder, current->head);
+ m_mfmhd->write_track(current->encdata.get(), current->cylinder, current->head);
current->dirty = false;
break;
}
@@ -1038,7 +1038,7 @@ void mfmhd_trackimage_cache::cleanup()
if (TRACE_CACHE) m_machine.logerror("[%s:cache] MFM HD cache: evict line cylinder=%d head=%d\n", m_mfmhd->tag(), current->cylinder, current->head);
if (current->dirty)
{
- m_mfmhd->write_track(current->encdata, current->cylinder, current->head);
+ m_mfmhd->write_track(current->encdata.get(), current->cylinder, current->head);
current->dirty = false;
}
mfmhd_trackimage* currenttmp = current->next;
@@ -1055,8 +1055,6 @@ void mfmhd_trackimage_cache::mark_current_as_dirty()
m_tracks->dirty = true;
}
-const char *encnames[] = { "MFM_BITS","MFM_BYTE","SEPARATE","SSIMPLE " };
-
/*
Initialize the cache by loading the first <trackslots> tracks.
*/
@@ -1064,7 +1062,7 @@ void mfmhd_trackimage_cache::init(mfm_harddisk_device* mfmhd, int tracksize, int
{
if (TRACE_CACHE) m_machine.logerror("[%s:cache] MFM HD cache init; cache size is %d tracks\n", mfmhd->tag(), trackslots);
- chd_error state;
+ std::error_condition state;
mfmhd_trackimage* previous;
mfmhd_trackimage* current = nullptr;
@@ -1078,14 +1076,15 @@ void mfmhd_trackimage_cache::init(mfm_harddisk_device* mfmhd, int tracksize, int
while (track < trackslots)
{
- if (TRACE_CACHE && TRACE_DETAIL) m_machine.logerror("[%s:cache] MFM HD allocate cache slot\n", mfmhd->tag());
+ if (TRACE_DETAIL) m_machine.logerror("[%s:cache] MFM HD allocate cache slot\n", mfmhd->tag());
previous = current;
- current = global_alloc(mfmhd_trackimage);
- current->encdata = global_alloc_array(uint16_t, tracksize);
+ current = new mfmhd_trackimage;
+ current->encdata = std::make_unique<uint16_t []>(tracksize);
// Load the first tracks into the slots
- state = m_mfmhd->load_track(current->encdata, cylinder, head);
- if (state != CHDERR_NONE) throw emu_fatalerror("Cannot load (c=%d,h=%d) from hard disk", cylinder, head);
+ state = m_mfmhd->load_track(current->encdata.get(), cylinder, head);
+ if (state)
+ throw emu_fatalerror("Cannot load (c=%d,h=%d) from hard disk", cylinder, head);
current->dirty = false;
current->cylinder = cylinder;
@@ -1122,11 +1121,11 @@ uint16_t* mfmhd_trackimage_cache::get_trackimage(int cylinder, int head)
mfmhd_trackimage* current = m_tracks;
mfmhd_trackimage* previous = nullptr;
- chd_error state = CHDERR_NONE;
+ std::error_condition state;
// Repeat the search. This loop should run at most twice; once for a direct hit,
// and twice on miss, then the second iteration will be a hit.
- while (state == CHDERR_NONE)
+ while (!state)
{
// A simple linear search
while (current != nullptr)
@@ -1141,7 +1140,7 @@ uint16_t* mfmhd_trackimage_cache::get_trackimage(int cylinder, int head)
current->next = m_tracks; // put the previous head into the next field
m_tracks = current; // set this line as new head
}
- return current->encdata;
+ return current->encdata.get();
}
else
{
@@ -1156,16 +1155,21 @@ uint16_t* mfmhd_trackimage_cache::get_trackimage(int cylinder, int head)
// Then look it up again, which will move it to the front
// previous points to the second to last element
+
+ // If still null, the cache was never initialized, which means there is no drive image
+ if (previous == nullptr)
+ return nullptr;
+
current = previous->next;
if (TRACE_CACHE) m_machine.logerror("[%s:cache] evict line (c=%d,h=%d)\n", m_mfmhd->tag(), current->cylinder, current->head);
if (current->dirty)
{
- m_mfmhd->write_track(current->encdata, current->cylinder, current->head);
+ m_mfmhd->write_track(current->encdata.get(), current->cylinder, current->head);
current->dirty = false;
}
- state = m_mfmhd->load_track(current->encdata, cylinder, head);
+ state = m_mfmhd->load_track(current->encdata.get(), cylinder, head);
current->dirty = false;
current->cylinder = cylinder;
diff --git a/src/devices/imagedev/mfmhd.h b/src/devices/imagedev/mfmhd.h
index a46dab519b7..2d733f5a9af 100644
--- a/src/devices/imagedev/mfmhd.h
+++ b/src/devices/imagedev/mfmhd.h
@@ -11,14 +11,20 @@
*****************************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_MFMHD_H
-#define MAME_DEVICES_IMAGEDEV_MFMHD_H
+#ifndef MAME_IMAGEDEV_MFMHD_H
+#define MAME_IMAGEDEV_MFMHD_H
#pragma once
#include "imagedev/harddriv.h"
+
#include "formats/mfm_hd.h"
+#include <string>
+#include <system_error>
+#include <utility>
+
+
class mfm_harddisk_device;
class mfmhd_trackimage
@@ -27,7 +33,7 @@ public:
bool dirty;
int cylinder;
int head;
- uint16_t* encdata; // MFM encoding per byte
+ std::unique_ptr<uint16_t []> encdata; // MFM encoding per byte
mfmhd_trackimage* next;
};
@@ -48,8 +54,7 @@ private:
running_machine & m_machine;
};
-class mfm_harddisk_device : public harddisk_image_device,
- public device_slot_card_interface
+class mfm_harddisk_device : public device_t, public device_image_interface
{
public:
~mfm_harddisk_device();
@@ -58,6 +63,14 @@ public:
typedef delegate<void (mfm_harddisk_device*, int)> ready_cb;
typedef delegate<void (mfm_harddisk_device*, int)> seek_complete_cb;
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *image_type_name() const noexcept override { return "harddisk"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "hard"; }
+ virtual const char *file_extensions() const noexcept override { return "chd"; }
+
void setup_index_pulse_cb(index_pulse_cb cb);
void setup_ready_cb(ready_cb cb);
void setup_seek_complete_cb(seek_complete_cb cb);
@@ -72,7 +85,7 @@ public:
// Active low lines. We're using ASSERT=0 / CLEAR=1
line_state ready_r() { return m_ready? ASSERT_LINE : CLEAR_LINE; }
- line_state seek_complete_r() { return m_seek_complete? ASSERT_LINE : CLEAR_LINE; } ;
+ line_state seek_complete_r() { return m_seek_complete? ASSERT_LINE : CLEAR_LINE; }
line_state trk00_r() { return m_current_cylinder==0? ASSERT_LINE : CLEAR_LINE; }
// Data output towards controller
@@ -88,14 +101,14 @@ public:
// Head select
void headsel_w(int head) { m_current_head = head & 0x0f; }
- image_init_result call_load() override;
+ std::pair<std::error_condition, std::string> call_load() override;
void call_unload() override;
// Tells us the time when the track ends (next index pulse). Needed by the controller.
attotime track_end_time();
// Access the tracks on the image. Used as a callback from the cache.
- chd_error load_track(uint16_t* data, int cylinder, int head);
+ std::error_condition load_track(uint16_t* data, int cylinder, int head);
void write_track(uint16_t* data, int cylinder, int head);
// Delivers the number of heads according to the loaded image
@@ -104,12 +117,14 @@ public:
protected:
mfm_harddisk_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- void device_start() override;
- void device_stop() override;
- void device_reset() override;
- void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ virtual void device_start() override;
+ virtual void device_stop() override;
+ virtual void device_reset() override;
- std::string tts(const attotime &t);
+ TIMER_CALLBACK_MEMBER(index_timer);
+ TIMER_CALLBACK_MEMBER(recalibrate);
+ TIMER_CALLBACK_MEMBER(seek_update);
+ TIMER_CALLBACK_MEMBER(cache_update);
emu_timer *m_index_timer, *m_spinup_timer, *m_seek_timer, *m_cache_timer;
index_pulse_cb m_index_pulse_cb;
@@ -153,11 +168,10 @@ private:
attotime m_settle_time;
attotime m_step_time;
- mfmhd_trackimage_cache* m_cache;
+ std::unique_ptr<mfmhd_trackimage_cache> m_cache;
mfmhd_image_format_t* m_format;
-
+ chd_file *m_chd;
void head_move();
- void recalibrate();
// Common routine for read/write
bool find_position(attotime &from_when, const attotime &limit, int &bytepos, int &bitpos);
@@ -243,16 +257,16 @@ public:
void configure(mfmhd_enc_t encoding, int spinupms, int cache, mfmhd_format_type format);
protected:
- void device_start() override;
+ void device_start() override ATTR_COLD;
void device_config_complete() override;
private:
mfmhd_enc_t m_encoding;
int m_spinupms;
int m_cachesize;
- mfmhd_image_format_t* m_format;
+ mfmhd_image_format_t *m_format;
};
DECLARE_DEVICE_TYPE(MFM_HD_CONNECTOR, mfm_harddisk_connector)
-#endif // MAME_DEVICES_IMAGEDEV_MFMHD_H
+#endif // MAME_IMAGEDEV_MFMHD_H
diff --git a/src/devices/imagedev/microdrv.cpp b/src/devices/imagedev/microdrv.cpp
index 854b8d55197..2f8ae27ba9a 100644
--- a/src/devices/imagedev/microdrv.cpp
+++ b/src/devices/imagedev/microdrv.cpp
@@ -46,8 +46,7 @@ DEFINE_DEVICE_TYPE(MICRODRIVE, microdrive_image_device, "microdrive_image", "Sin
//-------------------------------------------------
microdrive_image_device::microdrive_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, MICRODRIVE, tag, owner, clock),
- device_image_interface(mconfig, *this),
+ microtape_image_device(mconfig, MICRODRIVE, tag, owner, clock),
m_write_comms_out(*this)
{
}
@@ -63,15 +62,12 @@ microdrive_image_device::~microdrive_image_device()
void microdrive_image_device::device_start()
{
- // resolve callbacks
- m_write_comms_out.resolve_safe();
-
// allocate track buffers
m_left = std::make_unique<uint8_t[]>(MDV_IMAGE_LENGTH / 2);
m_right = std::make_unique<uint8_t[]>(MDV_IMAGE_LENGTH / 2);
// allocate timers
- m_bit_timer = timer_alloc();
+ m_bit_timer = timer_alloc(FUNC(microdrive_image_device::bit_timer), this);
m_bit_timer->adjust(attotime::zero, 0, attotime::from_hz(MDV_BITRATE));
m_bit_timer->enable(0);
@@ -80,10 +76,10 @@ void microdrive_image_device::device_start()
m_comms_out = 0;
}
-image_init_result microdrive_image_device::call_load()
+std::pair<std::error_condition, std::string> microdrive_image_device::call_load()
{
if (length() != MDV_IMAGE_LENGTH)
- return image_init_result::FAIL;
+ return std::make_pair(image_error::INVALIDLENGTH, std::string());
// huh
for (int i = 0; i < MDV_IMAGE_LENGTH / 2; i++)
@@ -95,7 +91,7 @@ image_init_result microdrive_image_device::call_load()
m_bit_offset = 0;
m_byte_offset = 0;
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
void microdrive_image_device::call_unload()
@@ -107,7 +103,7 @@ void microdrive_image_device::call_unload()
memset(m_right.get(), 0, MDV_IMAGE_LENGTH / 2);
}
-void microdrive_image_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(microdrive_image_device::bit_timer)
{
m_bit_offset++;
@@ -123,7 +119,7 @@ void microdrive_image_device::device_timer(emu_timer &timer, device_timer_id id,
}
}
-WRITE_LINE_MEMBER( microdrive_image_device::clk_w )
+void microdrive_image_device::clk_w(int state)
{
if (LOG) logerror("Microdrive '%s' CLK: %u\n", tag(), state);
if (!m_clk && state)
@@ -136,25 +132,25 @@ WRITE_LINE_MEMBER( microdrive_image_device::clk_w )
m_clk = state;
}
-WRITE_LINE_MEMBER( microdrive_image_device::comms_in_w )
+void microdrive_image_device::comms_in_w(int state)
{
if (LOG) logerror("Microdrive '%s' COMMS IN: %u\n", tag(), state);
m_comms_in = state;
}
-WRITE_LINE_MEMBER( microdrive_image_device::erase_w )
+void microdrive_image_device::erase_w(int state)
{
if (LOG) logerror("Microdrive '%s' ERASE: %u\n", tag(), state);
m_erase = state;
}
-WRITE_LINE_MEMBER( microdrive_image_device::read_write_w )
+void microdrive_image_device::read_write_w(int state)
{
if (LOG) logerror("Microdrive '%s' READ/WRITE: %u\n", tag(), state);
m_read_write = state;
}
-WRITE_LINE_MEMBER( microdrive_image_device::data1_w )
+void microdrive_image_device::data1_w(int state)
{
if (m_comms_out && !m_read_write)
{
@@ -162,7 +158,7 @@ WRITE_LINE_MEMBER( microdrive_image_device::data1_w )
}
}
-WRITE_LINE_MEMBER( microdrive_image_device::data2_w )
+void microdrive_image_device::data2_w(int state)
{
if (m_comms_out && !m_read_write)
{
@@ -170,7 +166,7 @@ WRITE_LINE_MEMBER( microdrive_image_device::data2_w )
}
}
-READ_LINE_MEMBER( microdrive_image_device::data1_r )
+int microdrive_image_device::data1_r()
{
int data = 0;
if (m_comms_out && m_read_write)
@@ -180,7 +176,7 @@ READ_LINE_MEMBER( microdrive_image_device::data1_r )
return data;
}
-READ_LINE_MEMBER( microdrive_image_device::data2_r )
+int microdrive_image_device::data2_r()
{
int data = 0;
if (m_comms_out && m_read_write)
diff --git a/src/devices/imagedev/microdrv.h b/src/devices/imagedev/microdrv.h
index 30ff82724fc..c4480fade69 100644
--- a/src/devices/imagedev/microdrv.h
+++ b/src/devices/imagedev/microdrv.h
@@ -8,12 +8,12 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_MICRODRV_H
-#define MAME_DEVICES_IMAGEDEV_MICRODRV_H
+#ifndef MAME_IMAGEDEV_MICRODRV_H
+#define MAME_IMAGEDEV_MICRODRV_H
#pragma once
-#include "softlist_dev.h"
+#include "magtape.h"
//**************************************************************************
@@ -30,8 +30,7 @@
// ======================> microdrive_image_device
-class microdrive_image_device : public device_t,
- public device_image_interface
+class microdrive_image_device : public microtape_image_device
{
public:
// construction/destruction
@@ -40,35 +39,30 @@ public:
auto comms_out_wr_callback() { return m_write_comms_out.bind(); }
- // image-level overrides
- virtual image_init_result call_load() override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual void call_unload() override;
- virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); }
- virtual iodevice_t image_type() const override { return IO_MAGTAPE; }
-
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 1; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override { return "ql_cass"; }
- virtual const char *file_extensions() const override { return "mdv,mdr"; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual const char *image_interface() const noexcept override { return "ql_cass"; }
+ virtual const char *file_extensions() const noexcept override { return "mdv,mdr"; }
// specific implementation
- DECLARE_WRITE_LINE_MEMBER( clk_w );
- DECLARE_WRITE_LINE_MEMBER( comms_in_w );
- DECLARE_WRITE_LINE_MEMBER( erase_w );
- DECLARE_WRITE_LINE_MEMBER( read_write_w );
- DECLARE_WRITE_LINE_MEMBER( data1_w );
- DECLARE_WRITE_LINE_MEMBER( data2_w );
- DECLARE_READ_LINE_MEMBER ( data1_r );
- DECLARE_READ_LINE_MEMBER ( data2_r );
+ void clk_w(int state);
+ void comms_in_w(int state);
+ void erase_w(int state);
+ void read_write_w(int state);
+ void data1_w(int state);
+ void data2_w(int state);
+ int data1_r();
+ int data2_r();
protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
+
+ TIMER_CALLBACK_MEMBER(bit_timer);
+
private:
devcb_write_line m_write_comms_out;
@@ -91,4 +85,4 @@ private:
// device type definition
DECLARE_DEVICE_TYPE(MICRODRIVE, microdrive_image_device)
-#endif // MAME_DEVICES_IMAGEDEV_MICRODRV_H
+#endif // MAME_IMAGEDEV_MICRODRV_H
diff --git a/src/devices/imagedev/midiin.cpp b/src/devices/imagedev/midiin.cpp
index 6086cb48a3e..62c8954e93e 100644
--- a/src/devices/imagedev/midiin.cpp
+++ b/src/devices/imagedev/midiin.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:R. Belmont
+// copyright-holders:R. Belmont,Aaron Giles
/*********************************************************************
midiin.c
@@ -10,29 +10,67 @@
#include "emu.h"
#include "midiin.h"
+
#include "osdepend.h"
+
/***************************************************************************
IMPLEMENTATION
***************************************************************************/
DEFINE_DEVICE_TYPE(MIDIIN, midiin_device, "midiin", "MIDI In image device")
+namespace {
+
+INPUT_PORTS_START(midiin)
+ PORT_START("CFG")
+ PORT_CONFNAME(0xff, 0xff, "MIDI file mode")
+ PORT_CONFSETTING( 0xff, "Multi")
+ PORT_CONFSETTING( 0x00, "Poly: Channel 1")
+ PORT_CONFSETTING( 0x01, "Poly: Channel 2")
+ PORT_CONFSETTING( 0x02, "Poly: Channel 3")
+ PORT_CONFSETTING( 0x03, "Poly: Channel 4")
+ PORT_CONFSETTING( 0x04, "Poly: Channel 5")
+ PORT_CONFSETTING( 0x05, "Poly: Channel 6")
+ PORT_CONFSETTING( 0x06, "Poly: Channel 7")
+ PORT_CONFSETTING( 0x07, "Poly: Channel 8")
+ PORT_CONFSETTING( 0x08, "Poly: Channel 9")
+ PORT_CONFSETTING( 0x09, "Poly: Channel 10")
+ PORT_CONFSETTING( 0x0a, "Poly: Channel 11")
+ PORT_CONFSETTING( 0x0b, "Poly: Channel 12")
+ PORT_CONFSETTING( 0x0c, "Poly: Channel 13")
+ PORT_CONFSETTING( 0x0d, "Poly: Channel 14")
+ PORT_CONFSETTING( 0x0e, "Poly: Channel 15")
+ PORT_CONFSETTING( 0x0f, "Poly: Channel 16")
+INPUT_PORTS_END
+
+} // anonymous namespace
+
/*-------------------------------------------------
ctor
-------------------------------------------------*/
midiin_device::midiin_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MIDIIN, tag, owner, clock),
- device_image_interface(mconfig, *this),
- device_serial_interface(mconfig, *this),
- m_midi(nullptr),
- m_timer(nullptr),
- m_input_cb(*this),
- m_xmit_read(0),
- m_xmit_write(0),
- m_tx_busy(false)
+ : device_t(mconfig, MIDIIN, tag, owner, clock)
+ , device_image_interface(mconfig, *this)
+ , device_serial_interface(mconfig, *this)
+ , m_midi()
+ , m_config(*this, "CFG")
+ , m_timer(nullptr)
+ , m_input_cb(*this)
+ , m_xmit_read(0)
+ , m_xmit_write(0)
+ , m_tx_busy(false)
+{
+}
+
+midiin_device::~midiin_device()
+{
+}
+
+ioport_constructor midiin_device::device_input_ports() const
{
+ return INPUT_PORTS_NAME(midiin);
}
/*-------------------------------------------------
@@ -41,9 +79,8 @@ midiin_device::midiin_device(const machine_config &mconfig, const char *tag, dev
void midiin_device::device_start()
{
- m_input_cb.resolve_safe();
- m_timer = timer_alloc(0);
- m_midi = nullptr;
+ m_timer = timer_alloc(FUNC(midiin_device::midi_update), this);
+ m_midi.reset();
m_timer->enable(false);
}
@@ -59,18 +96,56 @@ void midiin_device::device_reset()
}
/*-------------------------------------------------
- device_timer
+ midi_update
-------------------------------------------------*/
-void midiin_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(midiin_device::midi_update)
{
- if (!id) {
- uint8_t buf[8192*4];
- int bytesRead;
+ // if there's a sequence playing, that takes priority
+ midi_event *event = m_sequence.current_event();
+ if (event != nullptr)
+ {
+ attotime curtime = m_timer->expire();
+ if (curtime < m_sequence_start)
+ {
+ // we could get called before we're supposed to start; show a countdown
+ attotime delta = m_sequence_start - curtime;
+ popmessage("Waiting to start MIDI playback... %d", delta.seconds());
+ m_timer->adjust(std::min(delta, attotime(1, 0)));
+ }
+ else
+ {
+ // update the playback time
+ curtime -= m_sequence_start;
+ popmessage("Playing MIDI file: %d:%02d / %d:%02d", curtime.seconds() / 60, curtime.seconds() % 60, m_sequence.duration().seconds() / 60, m_sequence.duration().seconds() % 60);
- if (m_midi == nullptr) {
- return;
+ // if it's time to process the current event, do it and advance
+ if (curtime >= event->time())
+ {
+ const u8 force_channel = m_config->read();
+
+ for (u8 curbyte : event->data())
+ {
+ if (force_channel <= 15 && curbyte >= 0x80 && curbyte < 0xf0)
+ curbyte = (curbyte & 0xf0) | force_channel;
+
+ xmit_char(curbyte);
+ }
+ event = m_sequence.advance_event();
+ }
+
+ // if there are more events, set a timer to trigger them
+ // (minimum duration 1 sec so that our playback time doesn't skip)
+ if (event != nullptr)
+ m_timer->adjust(std::min(event->time() - curtime, attotime(1, 0)));
+ else
+ popmessage("End of MIDI file");
}
+ }
+ else if (m_midi)
+ {
+ uint8_t buf[8192*4];
+ int bytesRead;
while (m_midi->poll())
{
@@ -91,35 +166,55 @@ void midiin_device::device_timer(emu_timer &timer, device_timer_id id, int param
call_load
-------------------------------------------------*/
-image_init_result midiin_device::call_load(void)
+std::pair<std::error_condition, std::string> midiin_device::call_load()
{
- m_midi = machine().osd().create_midi_device();
-
- if (!m_midi->open_input(filename()))
+ // attempt to load if it's a real file
+ std::error_condition err = load_image_by_path(OPEN_FLAG_READ, filename());
+ if (!err)
{
- global_free(m_midi);
- m_midi = nullptr;
- return image_init_result::FAIL;
+ // if the parsing succeeds, schedule the start to happen at least
+ // 10 seconds after starting to allow the keyboards to initialize
+ // TODO: this should perhaps be a driver-configurable parameter?
+ err = m_sequence.parse(image_core_file(), length());
+ if (!err)
+ {
+ m_sequence_start = std::max(machine().time(), attotime(10, 0));
+ m_timer->adjust(attotime::zero);
+ }
+ return std::make_pair(err, std::string());
}
+ else
+ {
+ m_midi = machine().osd().create_midi_input(filename());
+ if (!m_midi)
+ {
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
+ }
- m_timer->adjust(attotime::from_hz(1500), 0, attotime::from_hz(1500));
- m_timer->enable(true);
- return image_init_result::PASS;
+ m_timer->adjust(attotime::from_hz(1500), 0, attotime::from_hz(1500));
+ return std::make_pair(std::error_condition(), std::string());
+ }
}
/*-------------------------------------------------
call_unload
-------------------------------------------------*/
-void midiin_device::call_unload(void)
+void midiin_device::call_unload()
{
- if (m_midi)
+ if (!m_midi)
{
- m_midi->close();
- global_free(m_midi);
+ // send "all notes off" CC if unloading a MIDI file
+ for (u8 channel = 0; channel < 0x10; channel++)
+ {
+ xmit_char(0xb0 | channel);
+ xmit_char(123);
+ xmit_char(0);
+ }
}
- m_timer->enable(false);
- m_midi = nullptr;
+ m_midi.reset();
+ m_sequence.clear();
+ m_timer->enable(false);
}
void midiin_device::tra_complete()
@@ -167,3 +262,403 @@ void midiin_device::xmit_char(uint8_t data)
}
}
}
+
+
+//-------------------------------------------------
+// fourcc_le - helper to compute the little-endian
+// version of a fourcc value from a string
+//-------------------------------------------------
+
+static constexpr u32 fourcc_le(char const *string)
+{
+ return string[0] | (string[1] << 8) | (string[2] << 16) | (string[3] << 24);
+}
+
+
+//-------------------------------------------------
+// midi_parser - constructor
+//-------------------------------------------------
+
+midiin_device::midi_parser::midi_parser(util::random_read &stream, u32 length, u32 offset) :
+ m_stream(stream),
+ m_length(length),
+ m_offset(offset)
+{
+}
+
+
+//-------------------------------------------------
+// subset - construct a midi_parser that
+// represents a subset of the buffer, and advance
+// our offset past it
+//-------------------------------------------------
+
+midiin_device::midi_parser midiin_device::midi_parser::subset(u32 length)
+{
+ check_bounds(length);
+ midi_parser result(m_stream, m_offset + length, m_offset);
+ m_offset += length;
+ return result;
+}
+
+
+//-------------------------------------------------
+// rewind - back up by the given number of bytes
+//-------------------------------------------------
+
+midiin_device::midi_parser &midiin_device::midi_parser::rewind(u32 count)
+{
+ count = std::min(count, m_offset);
+ m_offset -= count;
+ return *this;
+}
+
+
+//-------------------------------------------------
+// variable - return the MIDI standard "variable"
+// value
+//-------------------------------------------------
+
+u32 midiin_device::midi_parser::variable()
+{
+ u32 result = 0;
+ for (int which = 0; which < 4; which++)
+ {
+ u8 curbyte = byte();
+ result = (result << 7) | (curbyte & 0x7f);
+ if ((curbyte & 0x80) == 0)
+ return result;
+ }
+ throw error("Invalid variable length field");
+}
+
+
+//-------------------------------------------------
+// byte - read 8 bits of data
+//-------------------------------------------------
+
+u8 midiin_device::midi_parser::byte()
+{
+ check_bounds(1);
+
+ u8 result = 0;
+ auto const [err, actual] = read_at(m_stream, m_offset, &result, 1);
+ if (err || actual != 1)
+ throw error("Error reading data");
+ m_offset++;
+ return result;
+}
+
+
+//-------------------------------------------------
+// word_be - read 16 bits of big-endian data
+//-------------------------------------------------
+
+u16 midiin_device::midi_parser::word_be()
+{
+ check_bounds(2);
+
+ u16 result = 0;
+ auto const [err, actual] = read_at(m_stream, m_offset, &result, 2);
+ if (err || actual != 2)
+ throw error("Error reading data");
+ m_offset += 2;
+ return big_endianize_int16(result);
+}
+
+
+//-------------------------------------------------
+// triple_be - read 24 bits of big-endian data
+//-------------------------------------------------
+
+u32 midiin_device::midi_parser::triple_be()
+{
+ check_bounds(3);
+
+ u32 result = 0;
+ auto const [err, actual] = read_at(m_stream, m_offset, &result, 3);
+ if (err || actual != 3)
+ throw error("Error reading data");
+ m_offset += 3;
+ return big_endianize_int32(result) >> 8;
+}
+
+
+//-------------------------------------------------
+// dword_be - read 32 bits of big-endian data
+//-------------------------------------------------
+
+u32 midiin_device::midi_parser::dword_be()
+{
+ check_bounds(4);
+
+ u32 result = 0;
+ auto const [err, actual] = read_at(m_stream, m_offset, &result, 4);
+ if (err || actual != 4)
+ throw error("Error reading data");
+ m_offset += 4;
+ return big_endianize_int32(result);
+}
+
+
+//-------------------------------------------------
+// dword_le - read 32 bits of little-endian data
+//-------------------------------------------------
+
+u32 midiin_device::midi_parser::dword_le()
+{
+ check_bounds(4);
+
+ u32 result = 0;
+ auto const [err, actual] = read_at(m_stream, m_offset, &result, 4);
+ if (err || actual != 4)
+ throw error("Error reading data");
+ m_offset += 4;
+ return little_endianize_int32(result);
+}
+
+
+//-------------------------------------------------
+// check_bounds - check to see if we have at least
+// 'length' bytes left to consume; if not,
+// throw an error
+//-------------------------------------------------
+
+void midiin_device::midi_parser::check_bounds(u32 length)
+{
+ if (m_offset + length > m_length)
+ throw error("Out of bounds error");
+}
+
+
+//-------------------------------------------------
+// event_at - return a reference to the sequence
+// event at the given tick, or create a new one
+// if one doesn't yet exist
+//-------------------------------------------------
+
+midiin_device::midi_event &midiin_device::midi_sequence::event_at(u32 tick)
+{
+ for (auto it = m_list.begin(); it != m_list.end(); ++it)
+ {
+ if (it->tick() == tick)
+ return *it;
+ if (it->tick() > tick)
+ return *m_list.emplace(it, tick);
+ }
+ m_list.emplace_back(tick);
+ return m_list.back();
+}
+
+
+//-------------------------------------------------
+// parse - parse a MIDI sequence from a buffer
+//-------------------------------------------------
+
+std::error_condition midiin_device::midi_sequence::parse(util::random_read &stream, u32 length)
+{
+ // start with an empty list of events
+ m_list.clear();
+
+ // by default parse the whole data
+ midi_parser buffer(stream, length, 0);
+
+ // catch errors to make parsing easier
+ try
+ {
+ const u32 type = buffer.dword_le();
+ if (type == fourcc_le("RIFF"))
+ {
+ // check the RIFF type and size
+ u32 riffsize = buffer.dword_le();
+ u32 rifftype = buffer.dword_le();
+ if (rifftype != fourcc_le("RMID"))
+ throw midi_parser::error("Input RIFF file is not of type RMID");
+
+ // loop over RIFF chunks
+ midi_parser riffdata = buffer.subset(riffsize - 4);
+ while (!riffdata.eob())
+ {
+ u32 chunktype = riffdata.dword_le();
+ u32 chunksize = riffdata.dword_le();
+ midi_parser chunk = riffdata.subset(chunksize);
+ if (chunktype == fourcc_le("data"))
+ {
+ parse_midi_data(chunk);
+ break;
+ }
+ }
+ }
+ else if ((u8)type == 0xf0)
+ parse_sysex_data(buffer.reset());
+ else
+ parse_midi_data(buffer.reset());
+
+ m_iterator = m_list.begin();
+ return std::error_condition();
+ }
+ catch (midi_parser::error &err)
+ {
+ osd_printf_error("MIDI file error: %s\n", err.description());
+ m_list.clear();
+ m_iterator = m_list.begin();
+ return image_error::UNSPECIFIED;
+ }
+}
+
+
+//-------------------------------------------------
+// parse_midi_data - parse the core MIDI format
+// into tracks
+//-------------------------------------------------
+
+void midiin_device::midi_sequence::parse_midi_data(midi_parser &buffer)
+{
+ // scan for syntactic correctness, and to find global state
+ u32 headertype = buffer.dword_le();
+ if (headertype != fourcc_le("MThd"))
+ throw midi_parser::error("Input file is not a MIDI file.");
+ if (buffer.dword_be() != 0x00000006)
+ throw midi_parser::error("Invalid MIDI file header.");
+
+ // parse format info
+ int format = buffer.word_be();
+ if (format > 2)
+ throw midi_parser::error("Invalid MIDI file header.");
+
+ // parse track count
+ u16 tracks = buffer.word_be();
+ if (format == 0 && tracks != 1)
+ throw midi_parser::error("MIDI format 0 expects exactly one track.");
+
+ // parse time divisor
+ u16 timediv = buffer.word_be();
+ if ((timediv & 0x8000) != 0)
+ throw midi_parser::error("SMPTE timecode time division not supported.");
+ if (timediv == 0)
+ throw midi_parser::error("Invalid time divisor of 0.");
+
+ // iterate over tracks
+ u32 curtick = 0;
+ for (u16 index = 0; index < tracks; index++)
+ {
+ // verify header
+ if (buffer.dword_le() != fourcc_le("MTrk"))
+ throw midi_parser::error("Invalid MIDI track header.");
+ u32 chunksize = buffer.dword_be();
+
+ // parse the track data
+ midi_parser trackdata = buffer.subset(chunksize);
+ u32 numticks = parse_track_data(trackdata, curtick);
+ if (format == 2)
+ curtick += numticks;
+ }
+
+ // now go through the event list and compute times
+ u32 lasttick = 0;
+ attotime ticktime = attotime::from_usec(1000000) / timediv;
+ attotime curtime;
+ for (auto &event : m_list)
+ {
+ // update the elapsed time
+ u32 curtick = event.tick();
+ curtime += ticktime * (curtick - lasttick);
+ lasttick = curtick;
+
+ // determine if we have a new tempo here before replacing the time
+ if (!event.time().is_zero())
+ ticktime = event.time() / timediv;
+ event.set_time(curtime);
+ }
+}
+
+
+//-------------------------------------------------
+// parse_track_data - parse data from a track and
+// add it to the buffer
+//-------------------------------------------------
+
+u32 midiin_device::midi_sequence::parse_track_data(midi_parser &buffer, u32 start_tick)
+{
+ u32 curtick = start_tick;
+ u8 last_type = 0;
+ while (!buffer.eob())
+ {
+ // parse the time delta
+ curtick += buffer.variable();
+ midi_event &event = event_at(curtick);
+
+ // handle running status
+ u8 type = buffer.byte();
+ if (BIT(type, 7) != 0)
+ last_type = type;
+ else
+ {
+ type = last_type;
+ buffer.rewind(1);
+ }
+
+ // determine the event class
+ uint8_t eclass = type >> 4;
+ if (eclass != 15)
+ {
+ // simple events: all but program change and aftertouch have a second parameter
+ event.append(type);
+ event.append(buffer.byte());
+ if (eclass != 12 && eclass != 13)
+ event.append(buffer.byte());
+ }
+ else if (type != 0xff)
+ {
+ // handle non-meta events
+ midi_parser eventdata = buffer.subset(buffer.variable());
+ event.append(type);
+ while (!eventdata.eob())
+ event.append(eventdata.byte());
+ }
+ else
+ {
+ // handle meta-events
+ u8 type = buffer.byte();
+ midi_parser eventdata = buffer.subset(buffer.variable());
+
+ // end of data?
+ if (type == 0x2f)
+ break;
+
+ // only care about tempo events; set the "time" to the new tick
+ // value; we will sweep this later and compute actual times
+ if (type == 0x51)
+ {
+ u32 usec_per_quarter = eventdata.triple_be();
+ if (usec_per_quarter != 0)
+ event.set_time(attotime::from_usec(usec_per_quarter));
+ }
+ }
+ }
+ return curtick;
+}
+
+//-------------------------------------------------
+// parse_sysex_data - parse a sysex dump into a
+// single MIDI event
+//-------------------------------------------------
+
+void midiin_device::midi_sequence::parse_sysex_data(midi_parser &buffer)
+{
+ u32 msg = 0;
+ attotime curtime;
+ while (!buffer.eob())
+ {
+ midi_event &event = event_at(msg++);
+ event.set_time(curtime);
+
+ u8 data = 0;
+ while (!buffer.eob() && data != 0xf7)
+ event.append(data = buffer.byte());
+
+ // add 100 ms between the end of this sysex and the start of the next one, if there is one
+ curtime += attotime::from_ticks((u64)10 * event.data().size(), 31250)
+ + attotime::from_msec(100);
+ }
+}
diff --git a/src/devices/imagedev/midiin.h b/src/devices/imagedev/midiin.h
index 8254c6965a0..a7a30166218 100644
--- a/src/devices/imagedev/midiin.h
+++ b/src/devices/imagedev/midiin.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:R. Belmont
+// copyright-holders:R. Belmont,Aaron Giles
/*********************************************************************
midiin.h
@@ -15,6 +15,13 @@
#include "diserial.h"
+#include "interface/midiport.h"
+
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
/***************************************************************************
TYPE DEFINITIONS
@@ -27,51 +34,162 @@ class midiin_device : public device_t,
public:
// construction/destruction
midiin_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ~midiin_device();
auto input_callback() { return m_input_cb.bind(); }
- // image-level overrides
- virtual image_init_result call_load() override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual void call_unload() override;
// image device
- virtual iodevice_t image_type() const override { return IO_MIDIIN; }
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 0; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *file_extensions() const override { return "mid"; }
- virtual bool core_opens_image_file() const override { return false; }
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return false; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *file_extensions() const noexcept override { return "mid,syx"; }
+ virtual bool core_opens_image_file() const noexcept override { return false; }
+ virtual const char *image_type_name() const noexcept override { return "midiin"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "min"; }
protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
-
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ // device_t implementation
+ virtual ioport_constructor device_input_ports() const override ATTR_COLD;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
- // serial overrides
+ // device_serial_interface implementation
virtual void tra_complete() override; // Tx completed sending byte
virtual void tra_callback() override; // Tx send bit
+ TIMER_CALLBACK_MEMBER(midi_update);
+
private:
static const int XMIT_RING_SIZE = (8192*4*4);
void xmit_char(uint8_t data);
- osd_midi_device *m_midi;
+ std::unique_ptr<osd::midi_input_port> m_midi;
+ required_ioport m_config;
emu_timer *m_timer;
devcb_write_line m_input_cb;
uint8_t m_xmitring[XMIT_RING_SIZE];
int m_xmit_read, m_xmit_write;
bool m_tx_busy;
+
+ // internal helper class for parsing
+ class midi_parser
+ {
+ public:
+ // minimal error class
+ class error
+ {
+ public:
+ error(char const *description) : m_description(description) { }
+ char const *description() const { return m_description; }
+ private:
+ char const *m_description;
+ };
+
+ // construction
+ midi_parser(util::random_read &stream, u32 length, u32 offset);
+
+ // end of buffer?
+ bool eob() const { return (m_offset >= m_length); }
+
+ // create a subset
+ midi_parser subset(u32 length);
+
+ // change position within buffer
+ midi_parser &rewind(u32 count);
+ midi_parser &reset() { return rewind(m_offset); }
+
+ // read data of various sizes and endiannesses
+ u8 byte();
+ u16 word_be();
+ u32 triple_be();
+ u32 dword_be();
+ u32 dword_le();
+
+ // special variable reader for MIDI
+ u32 variable();
+
+ private:
+ // internal helper
+ void check_bounds(u32 length);
+
+ // internal state
+ util::random_read &m_stream;
+ u32 m_length;
+ u32 m_offset;
+ };
+
+ // internal helper class reperesenting an event at a given
+ // time containing MIDI data
+ class midi_event
+ {
+ public:
+ // constructor
+ midi_event(u32 tick) :
+ m_tick(tick) { }
+
+ // simple getters
+ u32 tick() const { return m_tick; }
+ attotime const &time() const { return m_time; }
+ std::vector<u8> const &data() const { return m_data; }
+
+ // simple setters
+ void set_time(attotime const &time) { m_time = time; }
+
+ // append data to the buffer
+ midi_event &append(u8 byte) { m_data.push_back(byte); return *this; }
+
+ private:
+ // internal state
+ u32 m_tick;
+ attotime m_time;
+ std::vector<u8> m_data;
+ };
+
+ // internal helper class representing a MIDI sequence
+ class midi_sequence
+ {
+ public:
+ // constructor
+ midi_sequence() : m_iterator(m_list.begin()) { }
+
+ // clear the sequence
+ void clear() { m_list.clear(); }
+
+ // parse a new sequence
+ std::error_condition parse(util::random_read &stream, u32 length);
+
+ // rewind to the start of time
+ void rewind(attotime const &basetime);
+ midi_event *current_event() const { return (m_iterator == m_list.end()) ? nullptr : &(*m_iterator); }
+ midi_event *advance_event() { ++m_iterator; return current_event(); }
+ attotime const &duration() { return m_list.back().time(); }
+
+ private:
+ // internal helpers
+ midi_event &event_at(u32 tick);
+ u32 parse_track_data(midi_parser &buffer, u32 start_tick);
+ void parse_midi_data(midi_parser &buffer);
+ void parse_sysex_data(midi_parser &buffer);
+
+ // internal state
+ std::list<midi_event> m_list;
+ std::list<midi_event>::iterator m_iterator;
+ };
+
+ midi_sequence m_sequence;
+ attotime m_sequence_start;
};
// device type definition
DECLARE_DEVICE_TYPE(MIDIIN, midiin_device)
// device iterator
-typedef device_type_iterator<midiin_device> midiin_device_iterator;
+typedef device_type_enumerator<midiin_device> midiin_device_enumerator;
#endif // MAME_IMAGEDEV_MIDIIN_H
diff --git a/src/devices/imagedev/midiout.cpp b/src/devices/imagedev/midiout.cpp
index 3c0613e2015..67efce46f93 100644
--- a/src/devices/imagedev/midiout.cpp
+++ b/src/devices/imagedev/midiout.cpp
@@ -9,9 +9,11 @@
*********************************************************************/
#include "emu.h"
-#include "osdepend.h"
#include "midiout.h"
+#include "osdepend.h"
+
+
/***************************************************************************
IMPLEMENTATION
***************************************************************************/
@@ -23,10 +25,14 @@ DEFINE_DEVICE_TYPE(MIDIOUT, midiout_device, "midiout", "MIDI Out image device")
-------------------------------------------------*/
midiout_device::midiout_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MIDIOUT, tag, owner, clock),
- device_image_interface(mconfig, *this),
- device_serial_interface(mconfig, *this),
- m_midi(nullptr)
+ : device_t(mconfig, MIDIOUT, tag, owner, clock)
+ , device_image_interface(mconfig, *this)
+ , device_serial_interface(mconfig, *this)
+ , m_midi()
+{
+}
+
+midiout_device::~midiout_device()
{
}
@@ -36,7 +42,7 @@ midiout_device::midiout_device(const machine_config &mconfig, const char *tag, d
void midiout_device::device_start()
{
- m_midi = nullptr;
+ m_midi.reset();
}
void midiout_device::device_reset()
@@ -51,32 +57,24 @@ void midiout_device::device_reset()
call_load
-------------------------------------------------*/
-image_init_result midiout_device::call_load(void)
+std::pair<std::error_condition, std::string> midiout_device::call_load()
{
- m_midi = machine().osd().create_midi_device();
-
- if (!m_midi->open_output(filename()))
+ m_midi = machine().osd().create_midi_output(filename());
+ if (!m_midi)
{
- global_free(m_midi);
- m_midi = nullptr;
- return image_init_result::FAIL;
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
}
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
/*-------------------------------------------------
call_unload
-------------------------------------------------*/
-void midiout_device::call_unload(void)
+void midiout_device::call_unload()
{
- if (m_midi)
- {
- m_midi->close();
- global_free(m_midi);
- m_midi = nullptr;
- }
+ m_midi.reset();
}
void midiout_device::rcv_complete() // Rx completed receiving byte
diff --git a/src/devices/imagedev/midiout.h b/src/devices/imagedev/midiout.h
index 159e71cab17..6640d94b3f8 100644
--- a/src/devices/imagedev/midiout.h
+++ b/src/devices/imagedev/midiout.h
@@ -15,6 +15,13 @@
#include "diserial.h"
+#include "interface/midiport.h"
+
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
/***************************************************************************
TYPE DEFINITIONS
@@ -27,39 +34,40 @@ class midiout_device : public device_t,
public:
// construction/destruction
midiout_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ~midiout_device();
- // image-level overrides
- virtual image_init_result call_load() override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual void call_unload() override;
// image device
- virtual iodevice_t image_type() const override { return IO_MIDIOUT; }
- virtual bool is_readable() const override { return 0; }
- virtual bool is_writeable() const override { return 1; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *file_extensions() const override { return "mid"; }
- virtual bool core_opens_image_file() const override { return false; }
+ virtual bool is_readable() const noexcept override { return false; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *file_extensions() const noexcept override { return "mid"; }
+ virtual bool core_opens_image_file() const noexcept override { return false; }
+ virtual const char *image_type_name() const noexcept override { return "midiout"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "mout"; }
virtual void tx(uint8_t state) { rx_w(state); }
protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
- // serial overrides
+ // device_serial_interface implementation
virtual void rcv_complete() override; // Rx completed receiving byte
private:
- osd_midi_device *m_midi;
+ std::unique_ptr<osd::midi_output_port> m_midi;
};
// device type definition
DECLARE_DEVICE_TYPE(MIDIOUT, midiout_device)
// device iterator
-typedef device_type_iterator<midiout_device> midiout_device_iterator;
+typedef device_type_enumerator<midiout_device> midiout_device_enumerator;
#endif // MAME_IMAGEDEV_MIDIOUT_H
diff --git a/src/devices/imagedev/papertape.cpp b/src/devices/imagedev/papertape.cpp
new file mode 100644
index 00000000000..f8cea6b2996
--- /dev/null
+++ b/src/devices/imagedev/papertape.cpp
@@ -0,0 +1,38 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/*********************************************************************
+
+ papertape.cpp
+
+ Base classes for paper tape reader and punch devices.
+
+ TODO: move some actual implementation here
+
+*********************************************************************/
+
+#include "emu.h"
+#include "papertape.h"
+
+#include "softlist_dev.h"
+
+
+paper_tape_image_device::paper_tape_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_image_interface(mconfig, *this)
+{
+}
+
+paper_tape_reader_device::paper_tape_reader_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : paper_tape_image_device(mconfig, type, tag, owner, clock)
+{
+}
+
+paper_tape_punch_device::paper_tape_punch_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : paper_tape_image_device(mconfig, type, tag, owner, clock)
+{
+}
+
+const software_list_loader &paper_tape_reader_device::get_software_list_loader() const
+{
+ return image_software_list_loader::instance();
+}
diff --git a/src/devices/imagedev/papertape.h b/src/devices/imagedev/papertape.h
new file mode 100644
index 00000000000..cb4359860c1
--- /dev/null
+++ b/src/devices/imagedev/papertape.h
@@ -0,0 +1,71 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/*********************************************************************
+
+ papertape.h
+
+ Base classes for paper tape reader and punch devices.
+
+*********************************************************************/
+
+#ifndef MAME_IMAGEDEV_PAPERTAPE_H
+#define MAME_IMAGEDEV_PAPERTAPE_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> paper_tape_image_device
+
+class paper_tape_image_device : public device_t, public device_image_interface
+{
+public:
+ // image-level overrides
+ virtual const char *image_type_name() const noexcept override { return "punchtape"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "ptap"; }
+
+protected:
+ // construction/destruction
+ paper_tape_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+};
+
+// ======================> paper_tape_reader_device
+
+class paper_tape_reader_device : public paper_tape_image_device
+{
+public:
+ // image-level overrides
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return false; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+
+protected:
+ // construction/destruction
+ paper_tape_reader_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override;
+};
+
+// ======================> paper_tape_punch_device
+
+class paper_tape_punch_device : public paper_tape_image_device
+{
+public:
+ // image-level overrides
+ virtual bool is_readable() const noexcept override { return false; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return true; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual bool support_command_line_image_creation() const noexcept override { return true; }
+
+protected:
+ // construction/destruction
+ paper_tape_punch_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+};
+
+#endif // MAME_IMAGEDEV_PAPERTAPE_H
diff --git a/src/devices/imagedev/picture.cpp b/src/devices/imagedev/picture.cpp
index f80bfb2885e..77e25c2e903 100644
--- a/src/devices/imagedev/picture.cpp
+++ b/src/devices/imagedev/picture.cpp
@@ -10,7 +10,7 @@
#include "emu.h"
#include "picture.h"
-#include "png.h"
+#include "rendutil.h"
/***************************************************************************
TYPE DEFINITIONS
@@ -25,8 +25,7 @@ DEFINE_DEVICE_TYPE(IMAGE_PICTURE, picture_image_device, "picture_image", "Still
picture_image_device::picture_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, IMAGE_PICTURE, tag, owner, clock),
- device_image_interface(mconfig, *this),
- m_picture(nullptr)
+ device_image_interface(mconfig, *this)
{
}
@@ -36,11 +35,6 @@ picture_image_device::picture_image_device(const machine_config &mconfig, const
picture_image_device::~picture_image_device()
{
- if (m_picture)
- {
- delete m_picture;
- m_picture = nullptr;
- }
}
@@ -48,26 +42,37 @@ void picture_image_device::device_start()
{
}
-image_init_result picture_image_device::call_load()
+std::pair<std::error_condition, std::string> picture_image_device::call_load()
{
- m_picture = new bitmap_argb32;
- if (png_read_bitmap(image_core_file(), *m_picture) != PNGERR_NONE)
+ switch (render_detect_image(image_core_file()))
{
- delete m_picture;
- m_picture = nullptr;
-
- // todo: try JPEG here.
- return image_init_result::FAIL;
+ case RENDUTIL_IMGFORMAT_PNG:
+ render_load_png(m_picture, image_core_file());
+ if (!m_picture.valid())
+ return std::make_pair(image_error::INVALIDIMAGE, "Invalid or unsupported PNG file");
+ break;
+
+ case RENDUTIL_IMGFORMAT_JPEG:
+ render_load_jpeg(m_picture, image_core_file());
+ if (!m_picture.valid())
+ return std::make_pair(image_error::INVALIDIMAGE, "Invalid or unsupported JPEG file");
+ break;
+
+ case RENDUTIL_IMGFORMAT_MSDIB:
+ render_load_msdib(m_picture, image_core_file());
+ if (!m_picture.valid())
+ return std::make_pair(image_error::INVALIDIMAGE, "Invalid or unsupported Microsoft DIB (BMP) file");
+ break;
+
+ default:
+ m_picture.reset();
+ return std::make_pair(image_error::INVALIDIMAGE, "Unsupported image file format");
}
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
void picture_image_device::call_unload()
{
- if (m_picture)
- {
- delete m_picture;
- m_picture = nullptr;
- }
+ m_picture.reset();
}
diff --git a/src/devices/imagedev/picture.h b/src/devices/imagedev/picture.h
index 4261d6cf351..4e57d01714f 100644
--- a/src/devices/imagedev/picture.h
+++ b/src/devices/imagedev/picture.h
@@ -8,8 +8,8 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_PICTURE_H
-#define MAME_DEVICES_IMAGEDEV_PICTURE_H
+#ifndef MAME_IMAGEDEV_PICTURE_H
+#define MAME_IMAGEDEV_PICTURE_H
#pragma once
@@ -29,30 +29,30 @@ public:
picture_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual ~picture_image_device();
- // image-level overrides
- virtual image_init_result call_load() override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual void call_unload() override;
- virtual iodevice_t image_type() const override { return IO_PICTURE; }
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 0; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *file_extensions() const override { return "png"; }
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return false; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *file_extensions() const noexcept override { return "png,jpg,jpeg,jfif,bmp,dib"; }
+ virtual const char *image_type_name() const noexcept override { return "picture"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "pic"; }
- bitmap_argb32 &get_bitmap() { return *m_picture; }
+ const bitmap_argb32 &get_bitmap() { return m_picture; }
protected:
- // device-level overrides
- virtual void device_start() override;
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
private:
- bitmap_argb32 *m_picture;
+ bitmap_argb32 m_picture;
};
// device type definition
DECLARE_DEVICE_TYPE(IMAGE_PICTURE, picture_image_device)
-#endif // MAME_DEVICES_IMAGEDEV_PICTURE_H
+#endif // MAME_IMAGEDEV_PICTURE_H
diff --git a/src/devices/imagedev/printer.cpp b/src/devices/imagedev/printer.cpp
index 2eb187d843a..22e0a80a2a3 100644
--- a/src/devices/imagedev/printer.cpp
+++ b/src/devices/imagedev/printer.cpp
@@ -33,7 +33,6 @@ printer_image_device::printer_image_device(const machine_config &mconfig, const
void printer_image_device::device_start()
{
- m_online_cb.resolve();
}
/***************************************************************************
@@ -68,7 +67,7 @@ void printer_image_device::output(uint8_t data)
DEVICE_IMAGE_CREATE( printer )
-------------------------------------------------*/
-image_init_result printer_image_device::call_create(int format_type, util::option_resolution *format_options)
+std::pair<std::error_condition, std::string> printer_image_device::call_create(int format_type, util::option_resolution *format_options)
{
return call_load();
}
@@ -76,14 +75,13 @@ image_init_result printer_image_device::call_create(int format_type, util::optio
/*-------------------------------------------------
DEVICE_IMAGE_LOAD( printer )
-------------------------------------------------*/
-image_init_result printer_image_device::call_load()
+std::pair<std::error_condition, std::string> printer_image_device::call_load()
{
- /* send notify that the printer is now online */
- if (!m_online_cb.isnull())
- m_online_cb(true);
+ // send notify that the printer is now online
+ m_online_cb(true);
- /* we don't need to do anything special */
- return image_init_result::PASS;
+ // we don't need to do anything special
+ return std::make_pair(std::error_condition(), std::string());
}
@@ -92,7 +90,6 @@ image_init_result printer_image_device::call_load()
-------------------------------------------------*/
void printer_image_device::call_unload()
{
- /* send notify that the printer is now offline */
- if (!m_online_cb.isnull())
- m_online_cb(false);
+ // send notify that the printer is now offline
+ m_online_cb(false);
}
diff --git a/src/devices/imagedev/printer.h b/src/devices/imagedev/printer.h
index 359faca8951..46346a87ff4 100644
--- a/src/devices/imagedev/printer.h
+++ b/src/devices/imagedev/printer.h
@@ -8,8 +8,8 @@
****************************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_PRINTER_H
-#define MAME_DEVICES_IMAGEDEV_PRINTER_H
+#ifndef MAME_IMAGEDEV_PRINTER_H
+#define MAME_IMAGEDEV_PRINTER_H
#pragma once
@@ -29,19 +29,19 @@ public:
auto online_callback() { return m_online_cb.bind(); }
- // image-level overrides
- virtual image_init_result call_load() override;
- virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
virtual void call_unload() override;
- // image device
- virtual iodevice_t image_type() const override { return IO_PRINTER; }
- virtual bool is_readable() const override { return 0; }
- virtual bool is_writeable() const override { return 1; }
- virtual bool is_creatable() const override { return 1; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *file_extensions() const override { return "prn"; }
+ virtual bool is_readable() const noexcept override { return false; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return true; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual bool support_command_line_image_creation() const noexcept override { return true; }
+ virtual const char *file_extensions() const noexcept override { return "prn"; }
+ virtual const char *image_type_name() const noexcept override { return "printout"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "prin"; }
// specific implementation
@@ -49,9 +49,10 @@ public:
int is_ready();
/* outputs data to a printer */
void output(uint8_t data);
+
protected:
- // device-level overrides
- virtual void device_start() override;
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
devcb_write_line m_online_cb;
};
@@ -60,4 +61,4 @@ protected:
// device type definition
DECLARE_DEVICE_TYPE(PRINTER, printer_image_device)
-#endif // MAME_DEVICES_IMAGEDEV_PRINTER_H
+#endif // MAME_IMAGEDEV_PRINTER_H
diff --git a/src/devices/imagedev/simh_tape_image.cpp b/src/devices/imagedev/simh_tape_image.cpp
new file mode 100644
index 00000000000..fc85c75bac4
--- /dev/null
+++ b/src/devices/imagedev/simh_tape_image.cpp
@@ -0,0 +1,85 @@
+// license:BSD-3-Clause
+// copyright-holders:Mietek Bak
+
+#include "emu.h"
+
+#include "simh_tape_image.h"
+
+// #define VERBOSE LOG_GENERAL
+// #define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(SIMH_TAPE_IMAGE, simh_tape_image_device, "simh_tape_image", "SIMH tape image");
+
+//////////////////////////////////////////////////////////////////////////////
+
+// construction
+
+simh_tape_image_device::simh_tape_image_device(const machine_config &config, device_type type, const char *tag, device_t *owner, u32 clock)
+ : microtape_image_device(config, type, tag, owner, clock)
+ , m_file()
+ , m_interface(nullptr)
+{
+}
+
+simh_tape_image_device::simh_tape_image_device(const machine_config &config, const char *tag, device_t *owner, u32 clock)
+ : simh_tape_image_device(config, SIMH_TAPE_IMAGE, tag, owner, clock)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// device_image_interface implementation
+
+std::pair<std::error_condition, std::string> simh_tape_image_device::call_load()
+{
+ LOG("simh_tape_image_device::call_load filename=%s\n", filename());
+ try {
+ m_file.reset(new simh_tape_file(image_core_file(), length(), is_readonly()));
+ }
+ catch (std::exception &e) { // error: loading tape failed
+ return std::make_pair(image_error::INTERNAL, std::string(e.what()));
+ }
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+std::pair<std::error_condition, std::string> simh_tape_image_device::call_create(int format_type, util::option_resolution *format_options)
+{
+ LOG("simh_tape_image_device::call_create filename=%s format_type=%d\n", filename(), format_type);
+ try {
+ u64 file_size = 62914560; // we default to 60MB; TODO: allow specifying tape image size, once MAME supports it
+ m_file.reset(new simh_tape_file(image_core_file(), file_size, is_readonly(), true));
+ }
+ catch (std::exception &e) { // error: creating tape failed
+ return std::make_pair(image_error::INTERNAL, std::string(e.what()));
+ }
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+void simh_tape_image_device::call_unload()
+{
+ LOG("simh_tape_image_device::call_unload\n");
+ m_file.reset();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// device_t implementation
+
+void simh_tape_image_device::device_config_complete()
+{
+ LOG("simh_tape_image_device::device_config_complete\n");
+ add_format(image_brief_type_name(), image_type_name(), file_extensions(), ""); // TODO: not sure these strings are correct
+}
+
+void simh_tape_image_device::device_start()
+{
+ LOG("simh_tape_image_device::device_start\n");
+}
+
+void simh_tape_image_device::device_stop()
+{
+ LOG("simh_tape_image_device::device_stop\n");
+}
+
+//////////////////////////////////////////////////////////////////////////////
diff --git a/src/devices/imagedev/simh_tape_image.h b/src/devices/imagedev/simh_tape_image.h
new file mode 100644
index 00000000000..887122be593
--- /dev/null
+++ b/src/devices/imagedev/simh_tape_image.h
@@ -0,0 +1,52 @@
+// license:BSD-3-Clause
+// copyright-holders:Mietek Bak
+
+#ifndef MAME_IMAGEDEV_SIMH_TAPE_IMAGE_H
+#define MAME_IMAGEDEV_SIMH_TAPE_IMAGE_H
+
+#pragma once
+
+#include "magtape.h"
+
+#include "util/simh_tape_file.h"
+
+DECLARE_DEVICE_TYPE(SIMH_TAPE_IMAGE, simh_tape_image_device);
+
+//////////////////////////////////////////////////////////////////////////////
+
+class simh_tape_image_device : public microtape_image_device
+{
+public:
+ // construction
+ simh_tape_image_device(const machine_config &config, const char *tag, device_t *owner, u32 clock = 0);
+
+ // device_image_interface implementation
+ virtual const char *image_interface() const noexcept override { return m_interface; }
+ virtual const char *file_extensions() const noexcept override { return "tap"; }
+ virtual const char *image_type_name() const noexcept override { return "tape"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "tap"; }
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
+ virtual void call_unload() override;
+
+ // miscellaneous
+ void set_interface(const char *interface) { m_interface = interface; }
+ simh_tape_file *get_file() const { return m_file.get(); }
+
+protected:
+ // construction
+ simh_tape_image_device(const machine_config &config, device_type type, const char *tag, device_t *owner, u32 clock);
+
+ // device_t implementation
+ virtual void device_config_complete() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_stop() override ATTR_COLD;
+
+ // state
+ std::unique_ptr<simh_tape_file> m_file; // tape image file
+ const char *m_interface; // image interface
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // MAME_IMAGEDEV_SIMH_TAPE_IMAGE_H
diff --git a/src/devices/imagedev/snapquik.cpp b/src/devices/imagedev/snapquik.cpp
index 811910c1422..a0a75c13f1f 100644
--- a/src/devices/imagedev/snapquik.cpp
+++ b/src/devices/imagedev/snapquik.cpp
@@ -11,8 +11,11 @@
#include "emu.h"
#include "snapquik.h"
+#include "softlist_dev.h"
+#include "ui/uimain.h"
+
// device type definition
-DEFINE_DEVICE_TYPE(SNAPSHOT, snapshot_image_device, "snapsot_image", "Snapshot")
+DEFINE_DEVICE_TYPE(SNAPSHOT, snapshot_image_device, "snapshot_image", "Snapshot")
//-------------------------------------------------
// snapshot_image_device - constructor
@@ -26,12 +29,14 @@ snapshot_image_device::snapshot_image_device(const machine_config &mconfig, cons
snapshot_image_device::snapshot_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, device_image_interface(mconfig, *this)
+ , m_load(*this)
, m_file_extensions(nullptr)
, m_interface(nullptr)
, m_delay(attotime::zero)
, m_timer(nullptr)
{
}
+
//-------------------------------------------------
// snapshot_image_device - destructor
//-------------------------------------------------
@@ -46,8 +51,28 @@ snapshot_image_device::~snapshot_image_device()
TIMER_CALLBACK_MEMBER(snapshot_image_device::process_snapshot_or_quickload)
{
- /* invoke the load */
- m_load(*this, filetype().c_str(), length());
+ check_for_file();
+
+ // invoke the load (FIXME: better way to report errors?)
+ auto [err, message] = m_load(*this);
+ if (err)
+ {
+ osd_printf_error(
+ !message.empty()
+ ? "%1$s: Error loading '%2$s': %3$s (%4$s:%5$d %6$s)\n"
+ : "%1$s: Error loading '%2$s': %6$s (%4$s:%5$d)\n",
+ tag(),
+ basename(),
+ message,
+ err.category().name(),
+ err.value(),
+ err.message());
+ popmessage(
+ !message.empty() ? "Error loading '%1$s': %2$s" : "Error loading '%1$s': %3$s",
+ basename(),
+ message,
+ err.message());
+ }
}
//-------------------------------------------------
@@ -56,20 +81,40 @@ TIMER_CALLBACK_MEMBER(snapshot_image_device::process_snapshot_or_quickload)
void snapshot_image_device::device_start()
{
- /* allocate a timer */
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(snapshot_image_device::process_snapshot_or_quickload),this));
+ m_load.resolve();
+
+ // allocate a timer
+ m_timer = timer_alloc(FUNC(snapshot_image_device::process_snapshot_or_quickload), this);
}
/*-------------------------------------------------
call_load
-------------------------------------------------*/
-image_init_result snapshot_image_device::call_load()
+std::pair<std::error_condition, std::string> snapshot_image_device::call_load()
{
- /* adjust the timer */
+ // adjust the timer
m_timer->adjust(m_delay, 0);
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+const software_list_loader &snapshot_image_device::get_software_list_loader() const
+{
+ return image_software_list_loader::instance();
+}
+
+
+//-------------------------------------------------
+// show_message - used to display a message while
+// loading
+//-------------------------------------------------
+
+void snapshot_image_device::show_message(util::format_argument_pack<char> const &args)
+{
+ // display the popup for a standard amount of time
+ machine().ui().popup_time(5, "%s: %s", basename(), util::string_format(args));
}
+
// device type definition
DEFINE_DEVICE_TYPE(QUICKLOAD, quickload_image_device, "quickload", "Quickload")
diff --git a/src/devices/imagedev/snapquik.h b/src/devices/imagedev/snapquik.h
index bb3d9f1f1c3..7e12778a3b0 100644
--- a/src/devices/imagedev/snapquik.h
+++ b/src/devices/imagedev/snapquik.h
@@ -8,19 +8,22 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_SNAPQUIK_H
-#define MAME_DEVICES_IMAGEDEV_SNAPQUIK_H
+#ifndef MAME_IMAGEDEV_SNAPQUIK_H
+#define MAME_IMAGEDEV_SNAPQUIK_H
#pragma once
-#include "softlist_dev.h"
+#include <string>
+#include <system_error>
+#include <utility>
+
// ======================> snapshot_image_device
class snapshot_image_device : public device_t,
public device_image_interface
{
public:
- typedef device_delegate<image_init_result (device_image_interface &, const char *, int)> load_delegate;
+ typedef device_delegate<std::pair<std::error_condition, std::string> (snapshot_image_device &)> load_delegate;
// construction/destruction
snapshot_image_device(const machine_config &mconfig, const char *tag, device_t *owner, const char* extensions, attotime delay = attotime::zero)
@@ -34,31 +37,41 @@ public:
void set_interface(const char *interface) { m_interface = interface; }
- // image-level overrides
- virtual image_init_result call_load() override;
- virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); }
- virtual iodevice_t image_type() const override { return IO_SNAPSHOT; }
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 0; }
- virtual bool is_creatable() const override { return 0; }
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override { return m_interface; }
- virtual const char *file_extensions() const override { return m_file_extensions; }
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return false; }
+ virtual bool is_creatable() const noexcept override { return false; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *image_interface() const noexcept override { return m_interface; }
+ virtual const char *file_extensions() const noexcept override { return m_file_extensions; }
+ virtual const char *image_type_name() const noexcept override { return "snapshot"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "dump"; }
void set_extensions(const char *ext) { m_file_extensions = ext; }
void set_delay(attotime delay) { m_delay = delay; }
- template <typename... T> void set_load_callback(T &&... args) { m_load = load_delegate(std::forward<T>(args)...); }
+ template <typename... T> void set_load_callback(T &&... args) { m_load.set(std::forward<T>(args)...); }
+
+ template <typename Format, typename... Params> void message(Format &&fmt, Params &&...args)
+ {
+ // format the message
+ show_message(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+ }
protected:
snapshot_image_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
- virtual void device_start() override;
+ virtual void device_start() override ATTR_COLD;
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override;
TIMER_CALLBACK_MEMBER(process_snapshot_or_quickload);
+ void show_message(util::format_argument_pack<char> const &args);
+
load_delegate m_load; /* loading function */
const char * m_file_extensions; /* file extensions */
const char * m_interface;
@@ -83,7 +96,8 @@ public:
}
quickload_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U);
- virtual iodevice_t image_type() const override { return IO_QUICKLOAD; }
+ virtual const char *image_type_name() const noexcept override { return "quickload"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "quik"; }
};
// device type definition
@@ -92,10 +106,10 @@ DECLARE_DEVICE_TYPE(QUICKLOAD, quickload_image_device)
/***************************************************************************
DEVICE CONFIGURATION MACROS
***************************************************************************/
-#define SNAPSHOT_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image, const char *file_type, int snapshot_size)
+#define SNAPSHOT_LOAD_MEMBER(_name) std::pair<std::error_condition, std::string> _name(snapshot_image_device &image)
#define DECLARE_SNAPSHOT_LOAD_MEMBER(_name) SNAPSHOT_LOAD_MEMBER(_name)
-#define QUICKLOAD_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image, const char *file_type, int quickload_size)
+#define QUICKLOAD_LOAD_MEMBER(_name) std::pair<std::error_condition, std::string> _name(snapshot_image_device &image)
#define DECLARE_QUICKLOAD_LOAD_MEMBER(_name) QUICKLOAD_LOAD_MEMBER(_name)
-#endif // MAME_DEVICES_IMAGEDEV_SNAPQUIK_H
+#endif // MAME_IMAGEDEV_SNAPQUIK_H
diff --git a/src/devices/imagedev/wafadrive.cpp b/src/devices/imagedev/wafadrive.cpp
index 658e845cb74..3bbdfa994ec 100644
--- a/src/devices/imagedev/wafadrive.cpp
+++ b/src/devices/imagedev/wafadrive.cpp
@@ -20,17 +20,16 @@
DEFINE_DEVICE_TYPE(WAFADRIVE_IMAGE, wafadrive_image_device, "wafadrive_image", "Sinclair Wafadrive Image")
//-------------------------------------------------
-// microdrive_image_device - constructor
+// wafadrive_image_device - constructor
//-------------------------------------------------
wafadrive_image_device::wafadrive_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, WAFADRIVE_IMAGE, tag, owner, clock),
- device_image_interface(mconfig, *this)
+ microtape_image_device(mconfig, WAFADRIVE_IMAGE, tag, owner, clock)
{
}
//-------------------------------------------------
-// microdrive_image_device - destructor
+// wafadrive_image_device - destructor
//-------------------------------------------------
wafadrive_image_device::~wafadrive_image_device()
@@ -42,9 +41,9 @@ void wafadrive_image_device::device_start()
{
}
-image_init_result wafadrive_image_device::call_load()
+std::pair<std::error_condition, std::string> wafadrive_image_device::call_load()
{
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
void wafadrive_image_device::call_unload()
diff --git a/src/devices/imagedev/wafadrive.h b/src/devices/imagedev/wafadrive.h
index 72dcb99b089..79e20ea913b 100644
--- a/src/devices/imagedev/wafadrive.h
+++ b/src/devices/imagedev/wafadrive.h
@@ -9,50 +9,41 @@
*********************************************************************/
-#ifndef MAME_DEVICES_IMAGEDEV_WAFADRIVE_H
-#define MAME_DEVICES_IMAGEDEV_WAFADRIVE_H
-
-#include "softlist_dev.h"
+#ifndef MAME_IMAGEDEV_WAFADRIVE_H
+#define MAME_IMAGEDEV_WAFADRIVE_H
#pragma once
+#include "magtape.h"
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
// ======================> microdrive_image_device
-class wafadrive_image_device : public device_t,
- public device_image_interface
+class wafadrive_image_device : public microtape_image_device
{
public:
// construction/destruction
wafadrive_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual ~wafadrive_image_device();
- // image-level overrides
- virtual image_init_result call_load() override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual void call_unload() override;
- virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); }
-
- virtual iodevice_t image_type() const override { return IO_MAGTAPE; } // what are these classed as? they're infinite loop tapes, in a cartridge shell that operate like discs
- virtual bool is_readable() const override { return 1; }
- virtual bool is_writeable() const override { return 1; }
- virtual bool is_creatable() const override { return 0; } // should be (although would need a way to specify size)
- virtual bool must_be_loaded() const override { return 0; }
- virtual bool is_reset_on_load() const override { return 0; }
- virtual const char *image_interface() const override { return "wafadrive_cart"; }
- virtual const char *file_extensions() const override { return "wdr"; }
+ virtual bool is_creatable() const noexcept override { return false; } // should be (although would need a way to specify size)
+ virtual const char *image_interface() const noexcept override { return "wafadrive_cart"; }
+ virtual const char *file_extensions() const noexcept override { return "wdr"; }
protected:
- // device-level overrides
- virtual void device_start() override;
-private:
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
};
// device type definition
DECLARE_DEVICE_TYPE(WAFADRIVE_IMAGE, wafadrive_image_device)
-#endif // MAME_DEVICES_IMAGEDEV_WAFADRIVE_H
+#endif // MAME_IMAGEDEV_WAFADRIVE_H