mame/src/lib/formats/mfm_hd.h
2015-12-06 09:23:23 +01:00

214 lines
6.2 KiB
C++

// 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