// license:BSD-3-Clause // copyright-holders:Nathan Woods, Olivier Galibert, Miodrag Milanovic /********************************************************************* floppy.h *********************************************************************/ #ifndef MAME_DEVICES_IMAGEDEV_FLOPPY_H #define MAME_DEVICES_IMAGEDEV_FLOPPY_H #pragma once #include "sound/samples.h" #include "screen.h" class floppy_image; class floppy_image_format_t; namespace fs { class manager_t; class meta_data; }; 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 m_formats; std::vector m_fs; }; class floppy_image_device : public device_t, public device_image_interface { public: typedef delegate load_cb; typedef delegate unload_cb; typedef delegate index_pulse_cb; typedef delegate ready_cb; typedef delegate wpt_cb; typedef delegate 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(); void set_formats(std::function formats); const std::vector &get_formats() const; const std::vector &get_fs() const { return m_fs; } const floppy_image_format_t *get_load_format() const; std::pair identify(std::string_view filename); void set_rpm(float rpm); void init_fs(const fs_info *fs, const fs::meta_data &meta); // device_image_interface implementation virtual std::pair call_load() override; virtual void call_unload() override; virtual std::pair 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); void setup_index_pulse_cb(index_pulse_cb cb); void setup_ready_cb(ready_cb cb); void setup_wpt_cb(wpt_cb cb); void setup_led_cb(led_cb cb); int get_cyl() const { return m_cyl; } bool on_track() const { return !m_subcyl; } virtual void mon_w(int state); bool ready_r(); void set_ready(bool state); double get_pos(); 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(); virtual bool writing_disabled() const; virtual void seek_phase_w(int phases); void stp_w(int 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 (m_dskchg_writable) m_dskchg = state; } void ds_w(int state) { m_ds = state; check_led(); } 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 m_sides; } uint32_t get_form_factor() const; uint32_t get_variant() const; 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_t implementation virtual void device_start() override; virtual void device_reset() override; virtual void device_config_complete() override; 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); std::function m_format_registration_cb; const floppy_image_format_t *m_input_format; const floppy_image_format_t *m_output_format; std::vector m_variants; std::unique_ptr m_image; char m_extension_list[256]; std::vector m_fif_list; std::vector m_fs; std::vector m_fs_managers; emu_timer *m_index_timer; /* Physical characteristics, filled by setup_characteristics */ int m_tracks; /* addressable tracks */ int m_sides; /* number of heads */ uint32_t m_form_factor; /* 3"5, 5"25, etc */ bool m_motor_always_on; bool m_dskchg_writable; bool m_has_trk00_sensor; int m_drive_index; /* state of input lines */ 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 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 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 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 flux_change_positions; }; static void wspan_split_on_wrap(std::vector &wspans); static void wspan_remove_damaged(std::vector &wspans, const std::vector &track); static void wspan_write(const std::vector &wspans, std::vector &track); void register_formats(); void check_led(); uint32_t find_position(attotime &base, const attotime &when); int find_index(uint32_t position, const std::vector &buf) const; attotime position_to_time(const attotime &base, int position) const; void commit_image(); u32 hash32(u32 val) const; void cache_clear(); void cache_fill_index(const std::vector &buf, int &index, attotime &base); void cache_fill(const attotime &when); void cache_weakness_setup(); // Sound bool m_make_sound; floppy_sound_device* m_sound_out; // Flux visualization struct flux_per_pixel_info { uint32_t m_position; // 0-199999999 Angular position in the track, 0xffffffff if not in the floppy image uint16_t m_r; // Distance from the center uint8_t m_combined_track; // No need to store head, it's y >= flux_screen_sy/2 uint8_t m_color; // Computed gray level from the flux counts }; struct flux_per_combined_track_info { std::vector m_pixels[2]; uint32_t m_span; uint8_t m_track; uint8_t m_subtrack; }; std::vector m_flux_per_pixel_infos; std::vector m_flux_per_combined_track_infos; optional_device m_flux_screen; static constexpr int flux_screen_sx = 501; static constexpr int flux_screen_sy = 1002; static constexpr int flux_min_r = 100; static constexpr int flux_max_r = 245; void flux_image_prepare(); void flux_image_compute_for_track(int track, int head); uint32_t flux_screen_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect); }; #define DECLARE_FLOPPY_IMAGE_DEVICE(Type, Name, Interface) \ class Name : public floppy_image_device { \ public: \ Name(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); \ virtual ~Name(); \ 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_SSDD, floppy_3_ssdd, "floppy_3") DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_3_DSDD, floppy_3_dsdd, "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") DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_DD, floppy_525_dd, "floppy_5_25") DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_SSQD, floppy_525_ssqd, "floppy_5_25") DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_QD, floppy_525_qd, "floppy_5_25") DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_525_HD, floppy_525_hd, "floppy_5_25") DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_8_SSSD, floppy_8_sssd, "floppy_8") DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_8_DSSD, floppy_8_dssd, "floppy_8") DECLARE_FLOPPY_IMAGE_DEVICE(FLOPPY_8_SSDD, floppy_8_ssdd, "floppy_8") 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") DECLARE_FLOPPY_IMAGE_DEVICE(ALPS_3255190X, alps_3255190x, "floppy_5_25") 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; virtual void device_reset() override; 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 */ class floppy_sound_device : public samples_device { public: floppy_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); void motor(bool on, bool withdisk); void step(int track); bool samples_loaded() { return m_loaded; } void register_for_save_states(); protected: void device_start() override; private: // device_sound_interface overrides virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; sound_stream* m_sound; int m_step_base; int m_spin_samples; int m_step_samples; int m_spin_samplepos; int m_step_samplepos; int m_seek_sound_timeout; int m_zones; int m_spin_playback_sample; int m_step_playback_sample; int m_seek_playback_sample; bool m_motor_on; bool m_with_disk; bool m_loaded; double m_seek_pitch; double m_seek_samplepos; }; class floppy_connector: public device_t, public device_slot_interface { public: template 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(std::forward(formats)); } template 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, drivetype); if(is_default) set_default_option(option); set_fixed(false); set_formats(std::forward(formats)); } floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); virtual ~floppy_connector(); template void set_formats(T &&_formats) { formats = std::forward(_formats); } void enable_sound(bool doit) { m_enable_sound = doit; } floppy_image_device *get_device(); protected: virtual void device_start() override; virtual void device_config_complete() override; private: std::function formats; bool m_enable_sound; }; // device type definition DECLARE_DEVICE_TYPE(FLOPPY_CONNECTOR, floppy_connector) extern template class device_finder; extern template class device_finder; #endif // MAME_DEVICES_IMAGEDEV_FLOPPY_H