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
|
// 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 "imagedev/harddriv.h"
#include "formats/mfm_hd.h"
class mfm_harddisk_device;
class mfmhd_trackimage
{
public:
bool dirty;
int cylinder;
int head;
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 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_t 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_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.
chd_error 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:
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;
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 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_t 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_t 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_t 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_t 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_t 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() override;
void device_config_complete() override;
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
|