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
|
// license:LGPL-2.1+
// copyright-holders:Michael Zapf
/****************************************************************************
Hard disk support
See mfm_hd.c for documentation
Michael Zapf
February 2012: Rewritten as class
*****************************************************************************/
#ifndef __MFMHDFMT__
#define __MFMHDFMT__
#include "emu.h"
#include "chd.h"
const chd_metadata_tag MFM_HARD_DISK_METADATA_TAG = CHD_MAKE_TAG('G','D','D','I');
extern const char *MFMHD_REC_METADATA_FORMAT;
extern const char *MFMHD_GAP_METADATA_FORMAT;
/*
Determine how data are passed from the hard disk to the controller. We
allow for different degrees of hardware emulation.
*/
enum mfmhd_enc_t
{
MFM_BITS, // One bit at a time
MFM_BYTE, // One data byte with interleaved clock bits
SEPARATED, // 8 clock bits (most sig byte), one data byte (least sig byte)
SEPARATED_SIMPLE // MSB: 00/FF (standard / mark) clock, LSB: one data byte
};
class mfmhd_image_format_t;
// Pointer to its alloc function
typedef mfmhd_image_format_t *(*mfmhd_format_type)();
template<class _FormatClass>
mfmhd_image_format_t *mfmhd_image_format_creator()
{
return new _FormatClass();
}
/*
Parameters for the track layout
*/
class mfmhd_layout_params
{
public:
// Geometry params. These are fixed for the device. However, sector sizes
// could be changed, but we do not support this (yet). These are defined
// in the CHD and must match those of the device. They are stored by the GDDD tag.
// The encoding is not stored in the CHD but is also supposed to be immutable.
int cylinders;
int heads;
int sectors_per_track;
int sector_size;
mfmhd_enc_t encoding;
// Parameters like interleave, precompensation, write current can be changed
// on every write operation. They are stored by the GDDI tag (first record).
int interleave;
int cylskew;
int headskew;
int write_precomp_cylinder; // if -1, no wpcom on the disks
int reduced_wcurr_cylinder; // if -1, no rwc on the disks
// Parameters for the track layout that are supposed to be the same for
// all tracks and that do not change (until the next reformat).
// Also, they do not have any influence on the CHD file.
// They are stored by the GDDI tag (second record).
int gap1;
int gap2;
int gap3;
int sync;
int headerlen;
int ecctype; // -1 is CRC
bool sane_rec() const
{
return ((interleave > 0 && interleave < 32) && (cylskew >= 0 && cylskew < 32) && (headskew >= 0 && headskew < 32)
&& (write_precomp_cylinder >= -1 && write_precomp_cylinder < 100000)
&& (reduced_wcurr_cylinder >= -1 && reduced_wcurr_cylinder < 100000));
}
void reset_rec()
{
interleave = cylskew = headskew = 0;
write_precomp_cylinder = reduced_wcurr_cylinder = -1;
}
bool sane_gap() const
{
return ((gap1 >= 1 && gap1 < 1000) && (gap2 >= 1 && gap2 < 20) && (gap3 >= 1 && gap3 < 1000)
&& (sync >= 10 && sync < 20)
&& (headerlen >= 4 && headerlen<=5) && (ecctype>=-1 && ecctype < 10));
}
void reset_gap()
{
gap1 = gap2 = gap3 = sync = headerlen = ecctype = 0;
}
bool equals_rec(mfmhd_layout_params* other) const
{
return ((interleave == other->interleave) &&
(cylskew == other->cylskew) &&
(headskew == other->headskew) &&
(write_precomp_cylinder == other->write_precomp_cylinder) &&
(reduced_wcurr_cylinder == other->reduced_wcurr_cylinder));
}
bool equals_gap(mfmhd_layout_params* other) const
{
return ((gap1 == other->gap1) &&
(gap2 == other->gap2) &&
(gap3 == other->gap3) &&
(sync == other->sync) &&
(headerlen == other->headerlen) &&
(ecctype == other->ecctype));
}
};
enum mfmhd_param_t
{
MFMHD_IL,
MFMHD_HSKEW,
MFMHD_CSKEW,
MFMHD_WPCOM,
MFMHD_RWC,
MFMHD_GAP1,
MFMHD_GAP2,
MFMHD_GAP3,
MFMHD_SYNC,
MFMHD_HLEN,
MFMHD_ECC
};
/*
Hard disk format
*/
class mfmhd_image_format_t
{
public:
mfmhd_image_format_t(): m_lastbit(false), m_current_crc(0)
{ m_devtag = std::string("mfmhd_image_format_t"); };
virtual ~mfmhd_image_format_t() {};
// Load the image.
virtual chd_error load(chd_file* chdfile, UINT16* trackimage, int tracksize, int cylinder, int head) = 0;
// Save the image.
virtual chd_error save(chd_file* chdfile, UINT16* trackimage, int tracksize, int cylinder, int head) = 0;
// Return the original parameters of the image
mfmhd_layout_params* get_initial_params() { return &m_param_old; }
// Return the recent parameters of the image
mfmhd_layout_params* get_current_params() { return &m_param; }
// Set the track layout parameters (and reset the skew detection values)
void set_layout_params(mfmhd_layout_params param);
// Concrete format shall decide whether we want to save the retrieved parameters or not.
virtual bool save_param(mfmhd_param_t type) =0;
// Accept a tag for log output, since this is not a device instance
void set_tag(std::string tag) { m_devtag = tag; }
protected:
bool m_lastbit;
int m_current_crc;
int m_secnumber[4]; // used to determine the skew values
std::string m_devtag;
mfmhd_layout_params m_param, m_param_old;
void mfm_encode(UINT16* trackimage, int& position, UINT8 byte, int count=1);
void mfm_encode_a1(UINT16* trackimage, int& position);
void mfm_encode_mask(UINT16* trackimage, int& position, UINT8 byte, int count, int mask);
UINT8 mfm_decode(UINT16 raw);
// Deliver defaults.
virtual int get_default(mfmhd_param_t type) =0;
// Debugging
void showtrack(UINT16* enctrack, int length);
virtual const char* tag() { return m_devtag.c_str(); }
};
class mfmhd_generic_format : public mfmhd_image_format_t
{
public:
mfmhd_generic_format() { m_devtag = std::string("mfmhd_generic_format"); };
chd_error load(chd_file* chdfile, UINT16* trackimage, int tracksize, int cylinder, int head) override;
chd_error save(chd_file* chdfile, UINT16* trackimage, int tracksize, int cylinder, int head) override;
// Yes, we want to save all parameters
virtual bool save_param(mfmhd_param_t type) override { return true; }
virtual int get_default(mfmhd_param_t type) override;
protected:
virtual UINT8 cylinder_to_ident(int cylinder);
virtual int chs_to_lba(int cylinder, int head, int sector);
};
extern const mfmhd_format_type MFMHD_GEN_FORMAT;
#endif
|