summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/mfm_hd.h
blob: 7d28adc518df516ab8196c5b54c7097f92db071b (plain) (blame)
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 MAME_FORMATS_MFM_HD_H
#define MAME_FORMATS_MFM_HD_H

#pragma once

#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_t* trackimage, int tracksize, int cylinder, int head) = 0;

	// Save the image.
	virtual chd_error save(chd_file* chdfile, uint16_t* 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_t* trackimage, int& position, uint8_t byte, int count=1);
	void    mfm_encode_a1(uint16_t* trackimage, int& position);
	void    mfm_encode_mask(uint16_t* trackimage, int& position, uint8_t byte, int count, int mask);
	uint8_t   mfm_decode(uint16_t raw);

	// Deliver defaults.
	virtual int get_default(mfmhd_param_t type) =0;

	// Debugging
	void    showtrack(uint16_t* 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_t* trackimage, int tracksize, int cylinder, int head) override;
	chd_error save(chd_file* chdfile, uint16_t* 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_t   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 // MAME_FORMATS_MFM_HD_H