diff options
Diffstat (limited to 'src/devices/imagedev/mfmhd.h')
-rw-r--r-- | src/devices/imagedev/mfmhd.h | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/src/devices/imagedev/mfmhd.h b/src/devices/imagedev/mfmhd.h new file mode 100644 index 00000000000..c15b892423d --- /dev/null +++ b/src/devices/imagedev/mfmhd.h @@ -0,0 +1,250 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + MFM hard disk emulation + + See mfmhd.c for documentation + + Michael Zapf + August 2015 + +*****************************************************************************/ + +#ifndef __MFMHD__ +#define __MFMHD__ + +#include "emu.h" +#include "imagedev/harddriv.h" +#include "formats/mfm_hd.h" + +class mfm_harddisk_device; + +class mfmhd_trackimage +{ +public: + bool dirty; + int cylinder; + int head; + UINT16* encdata; // MFM encoding per byte + mfmhd_trackimage* next; +}; + +class mfmhd_trackimage_cache +{ +public: + mfmhd_trackimage_cache(); + ~mfmhd_trackimage_cache(); + void init(mfm_harddisk_device* mfmhd, int tracksize, int trackslots); + UINT16* get_trackimage(int cylinder, int head); + void mark_current_as_dirty(); + void cleanup(); + void write_back_one(); + +private: + mfm_harddisk_device* m_mfmhd; + mfmhd_trackimage* m_tracks; +}; + +class mfm_harddisk_device : public harddisk_image_device, + public device_slot_card_interface +{ +public: + mfm_harddisk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~mfm_harddisk_device(); + + typedef delegate<void (mfm_harddisk_device*, int)> index_pulse_cb; + typedef delegate<void (mfm_harddisk_device*, int)> ready_cb; + typedef delegate<void (mfm_harddisk_device*, int)> seek_complete_cb; + + 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); + + // Configuration + void set_encoding(mfmhd_enc_t encoding) { m_encoding = encoding; } + void set_spinup_time(int spinupms) { m_spinupms = spinupms; } + void set_cache_size(int tracks) { m_cachelines = tracks; } + void set_format(mfmhd_image_format_t* format) { m_format = format; } + + mfmhd_enc_t get_encoding() { return m_encoding; } + + // 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 trk00_r() { return m_current_cylinder==0? ASSERT_LINE : CLEAR_LINE; } + + // Data output towards controller + bool read(attotime &from_when, const attotime &limit, UINT16 &data); + + // Data input from controller + bool write(attotime &from_when, const attotime &limit, UINT16 cdata, bool wpcom=false, bool reduced_wc=false); + + // Step + void step_w(line_state line); + void direction_in_w(line_state line); + + // Head select + void headsel_w(int head) { m_current_head = head & 0x0f; } + + bool call_load(); + void call_unload(); + + // 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* data, int cylinder, int head); + void write_track(UINT16* data, int cylinder, int head); + + // Delivers the number of heads according to the loaded image + int get_actual_heads(); + +protected: + void device_start(); + void device_stop(); + void device_reset(); + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + std::string tts(const attotime &t); + + emu_timer *m_index_timer, *m_spinup_timer, *m_seek_timer, *m_cache_timer; + index_pulse_cb m_index_pulse_cb; + ready_cb m_ready_cb; + seek_complete_cb m_seek_complete_cb; + + int m_max_cylinders; + int m_phys_cylinders; + int m_actual_cylinders; // after reading the CHD + int m_max_heads; + int m_landing_zone; + int m_precomp_cyl; + int m_redwc_cyl; + + int m_maxseek_time; + int m_seeknext_time; + +private: + mfmhd_enc_t m_encoding; + int m_cell_size; // nanoseconds + int m_trackimage_size; // number of 16-bit cell blocks (data bytes) + int m_spinupms; + int m_rpm; + int m_interleave; + int m_cachelines; + bool m_ready; + int m_current_cylinder; + int m_current_head; + int m_track_delta; + int m_step_phase; + bool m_seek_complete; + bool m_seek_inward; + bool m_autotruncation; + bool m_recalibrated; + line_state m_step_line; // keep the last state + + attotime m_spinup_time; + attotime m_revolution_start_time; + attotime m_rev_time; + + attotime m_settle_time; + attotime m_step_time; + + mfmhd_trackimage_cache* m_cache; + mfmhd_image_format_t* m_format; + + void prepare_track(int cylinder, int head); + void head_move(); + void recalibrate(); + + // Common routine for read/write + bool find_position(attotime &from_when, const attotime &limit, int &bytepos, int &bitpos); +}; + +/* + The Generic drive is a MFM drive that has just enough heads and cylinders + to handle the CHD image. + + Specific Seagate models: + + ST-213: 10 MB + ST-225: 20 MB + ST-251: 40 MB +*/ +class mfm_hd_generic_device : public mfm_harddisk_device +{ +public: + mfm_hd_generic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_GENERIC; + +class mfm_hd_st213_device : public mfm_harddisk_device +{ +public: + mfm_hd_st213_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_ST213; + +class mfm_hd_st225_device : public mfm_harddisk_device +{ +public: + mfm_hd_st225_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_ST225; + +class mfm_hd_st251_device : public mfm_harddisk_device +{ +public: + mfm_hd_st251_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_ST251; + + +/* Connector for a MFM hard disk. See also floppy.c */ +class mfm_harddisk_connector : public device_t, + public device_slot_interface +{ +public: + mfm_harddisk_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mfm_harddisk_connector(); + + mfm_harddisk_device *get_device(); + + void configure(mfmhd_enc_t encoding, int spinupms, int cache, mfmhd_format_type format); + +protected: + void device_start() { }; + void device_config_complete(); + +private: + mfmhd_enc_t m_encoding; + int m_spinupms; + int m_cachesize; + mfmhd_image_format_t* m_format; +}; + +extern const device_type MFM_HD_CONNECTOR; + +/* + Add a harddisk connector. + Parameters: + _tag = Tag of the connector + _slot_intf = Selection of hard drives + _def_slot = Default hard drive + _enc = Encoding (see comments in mfm_hd.c) + _spinupms = Spinup time in milliseconds (some configurations assume that the + user has turned on the hard disk before turning on the system. We cannot + emulate this, so we allow for shorter times) + _cache = number of cached MFM tracks +*/ +#define MCFG_MFM_HARDDISK_CONN_ADD(_tag, _slot_intf, _def_slot, _enc, _spinupms, _cache, _format) \ + MCFG_DEVICE_ADD(_tag, MFM_HD_CONNECTOR, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast<mfm_harddisk_connector *>(device)->configure(_enc, _spinupms, _cache, _format); + + +#endif |