1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
|
// license:LGPL-2.1+
// copyright-holders:Michael Zapf
/****************************************************************************
MFM hard disk emulation
See mfmhd.c for documentation
Michael Zapf
August 2015
*****************************************************************************/
#ifndef MAME_DEVICES_IMAGEDEV_MFMHD_H
#define MAME_DEVICES_IMAGEDEV_MFMHD_H
#pragma once
#include "imagedev/harddriv.h"
#include "formats/mfm_hd.h"
#include <system_error>
class mfm_harddisk_device;
class mfmhd_trackimage
{
public:
bool dirty;
int cylinder;
int head;
std::unique_ptr<uint16_t []> encdata; // MFM encoding per byte
mfmhd_trackimage* next;
};
class mfmhd_trackimage_cache
{
public:
mfmhd_trackimage_cache(running_machine &machine);
~mfmhd_trackimage_cache();
void init(mfm_harddisk_device* mfmhd, int tracksize, int trackslots);
uint16_t* 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;
running_machine & m_machine;
};
class mfm_harddisk_device : public device_t, public device_image_interface
{
public:
~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;
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);
// 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_t &data);
// Data input from controller
bool write(attotime &from_when, const attotime &limit, uint16_t 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; }
image_init_result 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.
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
int get_actual_heads();
protected:
mfm_harddisk_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_stop() override;
virtual void device_reset() override;
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;
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;
std::unique_ptr<mfmhd_trackimage_cache> m_cache;
mfmhd_image_format_t* m_format;
chd_file *m_chd;
void head_move();
// 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_t clock);
};
DECLARE_DEVICE_TYPE(MFMHD_GENERIC, mfm_hd_generic_device)
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_t clock);
};
DECLARE_DEVICE_TYPE(MFMHD_ST213, mfm_hd_st213_device)
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_t clock);
};
DECLARE_DEVICE_TYPE(MFMHD_ST225, mfm_hd_st225_device)
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_t clock);
};
DECLARE_DEVICE_TYPE(MFMHD_ST251, mfm_hd_st251_device)
/*
Connector for a MFM hard disk. Similar concept as in floppy.cpp.
*/
class mfm_harddisk_connector : public device_t,
public device_slot_interface
{
public:
template <typename T>
mfm_harddisk_connector(const machine_config &mconfig, const char *tag, device_t *owner, T &&opts,
const char *dflt, mfmhd_enc_t enc, int spinup, int cache, const mfmhd_format_type format, bool fixed = false)
: mfm_harddisk_connector(mconfig, tag, owner, 0)
{
option_reset();
opts(*this);
set_default_option(dflt);
set_fixed(fixed);
configure(enc, spinup, cache, format);
}
mfm_harddisk_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
~mfm_harddisk_connector();
mfm_harddisk_device *get_device();
/*
Configuration parameters:
encoding = Encoding (see comments in mfm_hd.c)
spinupms = Spinup time in milliseconds. Even though this is a property
of the physical device, we need a way to configure it per system;
some systems expect the hard disk to be turned on before the
main system, and expect it to be ready when they try to access it
cache = number of cached MFM tracks
format = MFMHD_GEN_FORMAT (see formats/mfm_hd.h; currently the only value)
*/
void configure(mfmhd_enc_t encoding, int spinupms, int cache, mfmhd_format_type format);
protected:
void device_start() override;
void device_config_complete() override;
private:
mfmhd_enc_t m_encoding;
int m_spinupms;
int m_cachesize;
mfmhd_image_format_t* m_format;
};
DECLARE_DEVICE_TYPE(MFM_HD_CONNECTOR, mfm_harddisk_connector)
#endif // MAME_DEVICES_IMAGEDEV_MFMHD_H
|