diff options
Diffstat (limited to 'src/devices/imagedev')
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, §or_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, §or, §or_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, ¶m.cylinders, ¶m.heads, ¶m.sectors_per_track, ¶m.sector_size) != 4) - { - logerror("Invalid CHD metadata\n"); - return image_init_result::FAIL; - } + if (sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, ¶m.cylinders, ¶m.heads, ¶m.sectors_per_track, ¶m.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, ¶m.interleave, ¶m.cylskew, ¶m.headskew, ¶m.write_precomp_cylinder, ¶m.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, ¶m.interleave, ¶m.cylskew, ¶m.headskew, ¶m.write_precomp_cylinder, ¶m.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, ¶m.gap1, ¶m.gap2, ¶m.gap3, ¶m.sync, ¶m.headerlen, ¶m.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, ¶m.gap1, ¶m.gap2, ¶m.gap3, ¶m.sync, ¶m.headerlen, ¶m.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 |