1 // license:LGPL-2.1+
2 // copyright-holders:Michael Zapf
3 /****************************************************************************
4 
5     Hard disk support
6     See mfm_hd.c for documentation
7 
8     Michael Zapf
9 
10     February 2012: Rewritten as class
11 
12 *****************************************************************************/
13 #ifndef MAME_FORMATS_MFM_HD_H
14 #define MAME_FORMATS_MFM_HD_H
15 
16 #pragma once
17 
18 #include "chd.h"
19 
20 const chd_metadata_tag MFM_HARD_DISK_METADATA_TAG = CHD_MAKE_TAG('G','D','D','I');
21 
22 extern const char *MFMHD_REC_METADATA_FORMAT;
23 extern const char *MFMHD_GAP_METADATA_FORMAT;
24 
25 /*
26     Determine how data are passed from the hard disk to the controller. We
27     allow for different degrees of hardware emulation.
28 */
29 enum mfmhd_enc_t
30 {
31 	MFM_BITS,               // One bit at a time
32 	MFM_BYTE,               // One data byte with interleaved clock bits
33 	SEPARATED,              // 8 clock bits (most sig byte), one data byte (least sig byte)
34 	SEPARATED_SIMPLE        // MSB: 00/FF (standard / mark) clock, LSB: one data byte
35 };
36 
37 class mfmhd_image_format_t;
38 
39 // Pointer to its alloc function
40 typedef mfmhd_image_format_t *(*mfmhd_format_type)();
41 
42 template<class _FormatClass>
mfmhd_image_format_creator()43 mfmhd_image_format_t *mfmhd_image_format_creator()
44 {
45 	return new _FormatClass();
46 }
47 
48 /*
49     Parameters for the track layout
50 */
51 class mfmhd_layout_params
52 {
53 public:
54 	// Geometry params. These are fixed for the device. However, sector sizes
55 	// could be changed, but we do not support this (yet). These are defined
56 	// in the CHD and must match those of the device. They are stored by the GDDD tag.
57 	// The encoding is not stored in the CHD but is also supposed to be immutable.
58 	int     cylinders;
59 	int     heads;
60 	int     sectors_per_track;
61 	int     sector_size;
62 	mfmhd_enc_t     encoding;
63 
64 	// Parameters like interleave, precompensation, write current can be changed
65 	// on every write operation. They are stored by the GDDI tag (first record).
66 	int     interleave;
67 	int     cylskew;
68 	int     headskew;
69 	int     write_precomp_cylinder;     // if -1, no wpcom on the disks
70 	int     reduced_wcurr_cylinder;     // if -1, no rwc on the disks
71 
72 	// Parameters for the track layout that are supposed to be the same for
73 	// all tracks and that do not change (until the next reformat).
74 	// Also, they do not have any influence on the CHD file.
75 	// They are stored by the GDDI tag (second record).
76 	int     gap1;
77 	int     gap2;
78 	int     gap3;
79 	int     sync;
80 	int     headerlen;
81 	int     ecctype;        // -1 is CRC
82 
sane_rec()83 	bool sane_rec() const
84 	{
85 		return ((interleave > 0 && interleave < 32) && (cylskew >= 0 && cylskew < 32) && (headskew >= 0 && headskew < 32)
86 			&& (write_precomp_cylinder >= -1 && write_precomp_cylinder < 100000)
87 			&& (reduced_wcurr_cylinder >= -1 && reduced_wcurr_cylinder < 100000));
88 	}
89 
reset_rec()90 	void reset_rec()
91 	{
92 		interleave = cylskew = headskew = 0;
93 		write_precomp_cylinder = reduced_wcurr_cylinder = -1;
94 	}
95 
sane_gap()96 	bool sane_gap() const
97 	{
98 		return ((gap1 >= 1 && gap1 < 1000) && (gap2 >= 1 && gap2 < 20) && (gap3 >= 1 && gap3 < 1000)
99 			&& (sync >= 10 && sync < 20)
100 			&& (headerlen >= 4 && headerlen<=5) && (ecctype>=-1 && ecctype < 10));
101 	}
102 
reset_gap()103 	void reset_gap()
104 	{
105 		gap1 = gap2 = gap3 = sync = headerlen = ecctype = 0;
106 	}
107 
equals_rec(mfmhd_layout_params * other)108 	bool equals_rec(mfmhd_layout_params* other) const
109 	{
110 		return ((interleave == other->interleave) &&
111 				(cylskew == other->cylskew) &&
112 				(headskew == other->headskew) &&
113 				(write_precomp_cylinder == other->write_precomp_cylinder) &&
114 				(reduced_wcurr_cylinder == other->reduced_wcurr_cylinder));
115 	}
116 
equals_gap(mfmhd_layout_params * other)117 	bool equals_gap(mfmhd_layout_params* other) const
118 	{
119 		return ((gap1 == other->gap1) &&
120 				(gap2 == other->gap2) &&
121 				(gap3 == other->gap3) &&
122 				(sync == other->sync) &&
123 				(headerlen == other->headerlen) &&
124 				(ecctype == other->ecctype));
125 	}
126 };
127 
128 enum mfmhd_param_t
129 {
130 	MFMHD_IL,
131 	MFMHD_HSKEW,
132 	MFMHD_CSKEW,
133 	MFMHD_WPCOM,
134 	MFMHD_RWC,
135 	MFMHD_GAP1,
136 	MFMHD_GAP2,
137 	MFMHD_GAP3,
138 	MFMHD_SYNC,
139 	MFMHD_HLEN,
140 	MFMHD_ECC
141 };
142 
143 /*
144     Hard disk format
145 */
146 class mfmhd_image_format_t
147 {
148 public:
mfmhd_image_format_t()149 	mfmhd_image_format_t(): m_lastbit(false), m_current_crc(0)
150 		{ m_devtag = std::string("mfmhd_image_format_t"); };
~mfmhd_image_format_t()151 	virtual ~mfmhd_image_format_t() {};
152 
153 	// Load the image.
154 	virtual chd_error load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) = 0;
155 
156 	// Save the image.
157 	virtual chd_error save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) = 0;
158 
159 	// Return the original parameters of the image
get_initial_params()160 	mfmhd_layout_params* get_initial_params() { return &m_param_old; }
161 
162 	// Return the recent parameters of the image
get_current_params()163 	mfmhd_layout_params* get_current_params() { return &m_param; }
164 
165 	// Set the track layout parameters (and reset the skew detection values)
166 	void set_layout_params(mfmhd_layout_params param);
167 
168 	// Concrete format shall decide whether we want to save the retrieved parameters or not.
169 	virtual bool save_param(mfmhd_param_t type) =0;
170 
171 	// Accept a tag for log output, since this is not a device instance
set_tag(std::string tag)172 	void set_tag(std::string tag) { m_devtag = tag; }
173 
174 protected:
175 	bool    m_lastbit;
176 	int     m_current_crc;
177 	int     m_secnumber[4];     // used to determine the skew values
178 	std::string m_devtag;
179 
180 	mfmhd_layout_params m_param, m_param_old;
181 
182 	void    mfm_encode(uint16_t* trackimage, int& position, uint8_t byte, int count=1);
183 	void    mfm_encode_a1(uint16_t* trackimage, int& position);
184 	void    mfm_encode_mask(uint16_t* trackimage, int& position, uint8_t byte, int count, int mask);
185 	uint8_t   mfm_decode(uint16_t raw);
186 
187 	// Deliver defaults.
188 	virtual int get_default(mfmhd_param_t type) =0;
189 
190 	// Debugging
191 	void    showtrack(uint16_t* enctrack, int length);
tag()192 	virtual const char* tag() { return m_devtag.c_str(); }
193 };
194 
195 class mfmhd_generic_format : public mfmhd_image_format_t
196 {
197 public:
mfmhd_generic_format()198 	mfmhd_generic_format() { m_devtag = std::string("mfmhd_generic_format"); };
199 	chd_error load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) override;
200 	chd_error save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) override;
201 
202 	// Yes, we want to save all parameters
save_param(mfmhd_param_t type)203 	virtual bool save_param(mfmhd_param_t type) override { return true; }
204 	virtual int get_default(mfmhd_param_t type) override;
205 
206 protected:
207 	virtual uint8_t   cylinder_to_ident(int cylinder);
208 	virtual int     chs_to_lba(int cylinder, int head, int sector);
209 };
210 
211 extern const mfmhd_format_type MFMHD_GEN_FORMAT;
212 
213 #endif // MAME_FORMATS_MFM_HD_H
214