mirror of
https://github.com/holub/mame
synced 2025-05-23 06:08:48 +03:00

Use standard uint64_t, uint32_t, uint16_t or uint8_t instead of UINT64, UINT32, UINT16 or UINT8 also use standard int64_t, int32_t, int16_t or int8_t instead of INT64, INT32, INT16 or INT8
692 lines
21 KiB
C++
692 lines
21 KiB
C++
// license:BSD-3-Clause
|
||
// copyright-holders:Michael Zapf
|
||
|
||
/*
|
||
The hfe_format class implements the HFE format that is used for the Lotharek
|
||
floppy emulator.
|
||
|
||
Format definition according to the official document:
|
||
|
||
File header (0x0000 - 0x01FF, 512 bytes)
|
||
----------------------------------------
|
||
|
||
typedef struct picfileformatheader_
|
||
{
|
||
uint8_t HEADERSIGNATURE[8]; // 0: "HXCPICFE"
|
||
uint8_t formatrevision; // 8: Revision 0
|
||
uint8_t number_of_track; // 9: Number of track in the file
|
||
uint8_t number_of_side; // 10: Number of valid side (Not used by the emulator)
|
||
uint8_t track_encoding; // 11: Track Encoding mode
|
||
// (Used for the write support - Please see the list above)
|
||
uint16_t bitRate; // 12: Bitrate in Kbit/s. Ex : 250=250000bits/s
|
||
// Max value : 500
|
||
uint16_t floppyRPM; // 14: Rotation per minute (Not used by the emulator)
|
||
uint8_t floppyinterfacemode; // 16: Floppy interface mode. (Please see the list above.)
|
||
uint8_t dnu; // 17: Free
|
||
uint16_t track_list_offset; // 18: Offset of the track list LUT in block of 512 bytes
|
||
// (Ex: 1=0x200)
|
||
uint8_t write_allowed; // 20: The Floppy image is write protected ?
|
||
uint8_t single_step; // 21: 0xFF : Single Step – 0x00 Double Step mode
|
||
uint8_t track0s0_altencoding; // 22: 0x00 : Use an alternate track_encoding for track 0 Side 0
|
||
uint8_t track0s0_encoding; // 23: alternate track_encoding for track 0 Side 0
|
||
uint8_t track0s1_altencoding; // 24: 0x00 : Use an alternate track_encoding for track 0 Side 1
|
||
uint8_t track0s1_encoding; // 25: alternate track_encoding for track 0 Side 1
|
||
} picfileformatheader;
|
||
|
||
Byte order for uint16_t is little endian.
|
||
|
||
floppyintefacemode values are defined in the header file as floppymode_t,
|
||
track_encodings are defined as encoding_t
|
||
|
||
track0s0_encoding is only valid when track0s0_altencoding==0xff
|
||
track0s1_encoding is only valid when track0s1_altencoding==0xff
|
||
|
||
Track offset lookup table (at 0x0200)
|
||
-------------------------------------
|
||
|
||
typedef struct pictrack_
|
||
{
|
||
uint16_t offset; // Offset of the track data in blocks of 512 bytes (Ex: 2=0x400)
|
||
uint16_t track_len; // Length of the track data in byte.
|
||
} pictrack;
|
||
|
||
This table has a size of number_of_track*4 bytes.
|
||
|
||
Track data
|
||
----------
|
||
|
||
(first possible occurance at 0x0400)
|
||
|
||
Each track is encoded in a sequence of cell levels which are represented
|
||
by bits in the data.
|
||
|
||
+--------+--------+--------+--------+---- ........ ---+--------+--------+
|
||
| Head 0 | Head 1 | Head 0 | Head 1 | Hea ........ 1 | Head 0 | Head 1 |
|
||
+--------+--------+--------+--------+---- ........ ---+--------+--------+
|
||
| Block 0 | Block 1 | | Block n-1 |
|
||
|
||
Each block (Head 0 + Head 1) is 0x200 bytes long, with 0x100 bytes for
|
||
each head. Block n-1 may be partially filled, e.g. with 64 bytes for
|
||
head 0 and 64 bytes for head 1. The contents for head 1 in block n-1
|
||
start at offxet 0x100 nevertheless:
|
||
|
||
+--------+--------+
|
||
|]]]] 0 |]]]] 1 |
|
||
+--------+--------+
|
||
| Block n-1 |
|
||
|
||
|
||
Each byte in the track data is a sequence of cell sample levels
|
||
according to the sample rate. Bit order is little endian:
|
||
|
||
Bits
|
||
7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16
|
||
|
||
0-bits indicate no change, 1-bits indicate flux level change.
|
||
|
||
To encode the byte 0x4e in MFM at 250 kbit/s, the following data bytes
|
||
are used:
|
||
|
||
Byte: 0 1 0 0 1 1 1 0
|
||
MDM encoding: 10 01 00 10 01 01 01 00
|
||
Reversed order: 0010 1010 0100 1001 = 2a 49
|
||
|
||
Interestingly, FM-encoded disks are usually sampled at 250 kbit/s,
|
||
like MFM, although FM only delivers 125 kbit/s. This oversampling leads
|
||
to zero bits (no change) every two positions. See below for details.
|
||
|
||
TODO:
|
||
- Handle double-stepping for medium.tracks=40, drive.tracks=80
|
||
*/
|
||
|
||
#include "hxchfe_dsk.h"
|
||
|
||
#define HEADER_LENGTH 512
|
||
#define TRACK_TABLE_LENGTH 1024
|
||
|
||
hfe_format::hfe_format() : floppy_image_format_t(),
|
||
m_cylinders(0),
|
||
m_heads(0),
|
||
m_track_encoding(UNKNOWN_ENCODING),
|
||
m_bit_rate(0),
|
||
m_floppy_rpm(0),
|
||
m_interface_mode(DISABLE_FLOPPYMODE),
|
||
m_write_allowed(true),
|
||
m_single_step(true),
|
||
m_track0s0_has_altencoding(false),
|
||
m_track0s0_encoding(UNKNOWN_ENCODING),
|
||
m_track0s1_has_altencoding(false),
|
||
m_track0s1_encoding(UNKNOWN_ENCODING),
|
||
m_selected_mode(DISABLE_FLOPPYMODE),
|
||
m_selected_encoding(UNKNOWN_ENCODING)
|
||
{
|
||
}
|
||
|
||
const char *hfe_format::name() const
|
||
{
|
||
return "hfe";
|
||
}
|
||
|
||
const char *hfe_format::description() const
|
||
{
|
||
return "SDCard HxC Floppy Emulator HFE File format";
|
||
}
|
||
|
||
const char *hfe_format::extensions() const
|
||
{
|
||
return "hfe";
|
||
}
|
||
|
||
bool hfe_format::supports_save() const
|
||
{
|
||
return true;
|
||
}
|
||
|
||
int hfe_format::identify(io_generic *io, uint32_t form_factor)
|
||
{
|
||
uint8_t header[8];
|
||
|
||
io_generic_read(io, &header, 0, sizeof(header));
|
||
if ( memcmp( header, HFE_FORMAT_HEADER, 8 ) ==0) {
|
||
return 100;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
bool hfe_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
|
||
{
|
||
uint8_t header[HEADER_LENGTH];
|
||
uint8_t track_table[TRACK_TABLE_LENGTH];
|
||
|
||
int drivecyl, driveheads;
|
||
image->get_maximal_geometry(drivecyl, driveheads);
|
||
|
||
// read header
|
||
io_generic_read(io, header, 0, HEADER_LENGTH);
|
||
|
||
// get values
|
||
// Format revision must be 0
|
||
if (header[8] != 0)
|
||
{
|
||
osd_printf_error("hxchfe: Invalid format revision. Expected 0, got %d.\n", header[8]);
|
||
return false;
|
||
}
|
||
|
||
m_cylinders = header[9] & 0xff;
|
||
m_heads = header[10] & 0xff;
|
||
|
||
if (drivecyl < m_cylinders)
|
||
{
|
||
osd_printf_error("hxchfe: Floppy disk has too many tracks for this drive (floppy tracks=%d, drive tracks=%d).\n", m_cylinders, drivecyl);
|
||
return false;
|
||
}
|
||
|
||
if (m_cylinders <= drivecyl/2)
|
||
{
|
||
osd_printf_error("hxchfe: Double stepping not yet supported (floppy tracks=%d, drive tracks=%d).\n", m_cylinders, drivecyl);
|
||
return false;
|
||
}
|
||
|
||
m_track_encoding = (encoding_t)(header[11] & 0xff);
|
||
|
||
if (m_track_encoding > EMU_FM_ENCODING)
|
||
{
|
||
osd_printf_error("hxchfe: Unknown track encoding %d.\n", m_track_encoding);
|
||
return false;
|
||
}
|
||
|
||
m_bit_rate = (header[12] & 0xff) | ((header[13] & 0xff)<<8);
|
||
|
||
if (m_bit_rate > 500)
|
||
{
|
||
osd_printf_error("hxchfe: Unsupported bit rate %d.\n", m_bit_rate);
|
||
return false;
|
||
}
|
||
int samplelength = 500000 / m_bit_rate;
|
||
|
||
// Not used in the HxC emulator
|
||
m_floppy_rpm = (header[14] & 0xff) | ((header[15] & 0xff)<<8);
|
||
|
||
m_interface_mode = (floppymode_t)(header[16] & 0xff);
|
||
if (m_interface_mode > S950_HD_FLOPPYMODE)
|
||
{
|
||
osd_printf_error("hxchfe: Unknown interface mode %d.\n", m_interface_mode);
|
||
return false;
|
||
}
|
||
|
||
m_write_allowed = (header[20] != 0);
|
||
m_single_step = (header[21] != 0);
|
||
m_track0s0_has_altencoding = (header[22] == 0x00);
|
||
m_track0s0_encoding = (encoding_t)(header[23] & 0xff);
|
||
m_track0s1_has_altencoding = (header[24] == 0x00);
|
||
m_track0s1_encoding = (encoding_t)(header[25] & 0xff);
|
||
|
||
// read track lookup table (multiple of 512)
|
||
int table_offset = (header[18] & 0xff) | ((header[19] & 0xff)<<8);
|
||
|
||
io_generic_read(io, track_table, table_offset<<9, TRACK_TABLE_LENGTH);
|
||
|
||
for (int i=0; i < m_cylinders; i++)
|
||
{
|
||
m_cyl_offset[i] = (track_table[4*i] & 0xff) | ((track_table[4*i+1] & 0xff)<<8);
|
||
m_cyl_length[i] = (track_table[4*i+2] & 0xff) | ((track_table[4*i+3] & 0xff)<<8);
|
||
}
|
||
|
||
// Load the tracks
|
||
std::vector<uint8_t> cylinder_buffer;
|
||
for(int cyl=0; cyl < m_cylinders; cyl++)
|
||
{
|
||
// actual data read
|
||
// The HFE format defines an interleave of the two sides per cylinder
|
||
// at every 256 bytes
|
||
cylinder_buffer.resize(m_cyl_length[cyl]);
|
||
io_generic_read(io, &cylinder_buffer[0], m_cyl_offset[cyl]<<9, m_cyl_length[cyl]);
|
||
|
||
generate_track_from_hfe_bitstream(cyl, 0, samplelength, &cylinder_buffer[0], m_cyl_length[cyl], image);
|
||
if (m_heads == 2)
|
||
generate_track_from_hfe_bitstream(cyl, 1, samplelength, &cylinder_buffer[0], m_cyl_length[cyl], image);
|
||
}
|
||
|
||
bool success = true;
|
||
|
||
// Find variant
|
||
if (m_track_encoding == ISOIBM_FM_ENCODING || m_track_encoding == EMU_FM_ENCODING)
|
||
// FM is for single density
|
||
image->set_variant((m_heads==1)? floppy_image::SSSD : floppy_image::DSSD);
|
||
else
|
||
{
|
||
// MFM encoding is for everything else
|
||
if (m_track_encoding == ISOIBM_MFM_ENCODING || m_track_encoding == AMIGA_MFM_ENCODING)
|
||
{
|
||
// Each cylinder contains the samples of both sides, 8 samples per
|
||
// byte; the bitRate determines how many samples constitute a cell
|
||
|
||
// DSDD: 360 KiB (5.25")= 2*40*18*256; 100000 cells/track, 2 us, bit rate = 250 kbit/s
|
||
// DSDD: 720 KiB (3.5") = 2*80*18*256; 100000 cells/track, 2 us, 250 kbit/s
|
||
// DSHD: 1.4 MiB = 2*80*18*512 bytes; 200000 cells/track, 1 us, 500 kbit/s
|
||
// DSED: 2.8 MiB = 2*80*36*512 bytes; 400000 cells/track, 500 ns, 1 Mbit/s
|
||
|
||
// Use cylinder 1 (cyl 0 may have special encodings)
|
||
int cellcount = (m_cyl_length[1] * 8 / 2) * 250 / m_bit_rate;
|
||
if (cellcount > 300000)
|
||
image->set_variant(floppy_image::DSED);
|
||
else
|
||
{
|
||
if (cellcount > 150000)
|
||
image->set_variant(floppy_image::DSHD);
|
||
else
|
||
{
|
||
if (cellcount > 90000)
|
||
// We cannot distinguish DSDD from DSQD without knowing the size of the floppy disk
|
||
image->set_variant((m_heads==1)? floppy_image::SSDD : floppy_image::DSDD);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
success = false;
|
||
}
|
||
return success;
|
||
}
|
||
|
||
void hfe_format::generate_track_from_hfe_bitstream(int cyl, int head, int samplelength, const uint8_t *trackbuf, int track_end, floppy_image *image)
|
||
{
|
||
// HFE has a minor issue: The track images do not sum up to 200 ms.
|
||
// Tracks are samples at 250 kbit/s for both FM and MFM, which yields
|
||
// 50000 data bits (100000 samples) for MFM, while FM is twice oversampled
|
||
// (4 samples per actual data bit)
|
||
// Hence, for both FM and MFM, we need 100000 samples.
|
||
|
||
// Track length 61B0 (both sides, FM)
|
||
// 100 + 100 + ... + 100 + (B0+50) = 3000 + B0 + 50 (pad)
|
||
// 100 + 100 + .... + 100 + B0 = 3000 + B0 = 99712 samples (-288)
|
||
|
||
// Track length 61C0 (both sides, MFM)
|
||
// 100 + 100 + ... + 100 + (C0+40) = 3000 + C0 + 40 (pad)
|
||
// 100 + 100 + .... + 100 + C0 = 3000 + C0 = 99840 samples (-160)
|
||
|
||
// Solution: Repeat the last byte until we have enough samples
|
||
// Note: We do not call normalize_times here because we're doing the job here
|
||
|
||
// HFE does not define subtracks; set to 0
|
||
|
||
// MG_1 / MG_0 are (logical) levels that indicate transition / no change
|
||
// MG_A / MG_B are physical flux directions
|
||
//
|
||
// Cell: | AAAABBBB | = MG_1 = | BBBBAAAA |
|
||
// | AAAAAAAA | = MG_0 = | BBBBBBBB |
|
||
|
||
std::vector<uint32_t> &dest = image->get_buffer(cyl, head, 0);
|
||
dest.clear();
|
||
|
||
// Start with MG_A
|
||
uint32_t cbit = floppy_image::MG_A;
|
||
|
||
int offset = 0x100;
|
||
|
||
if (head==0)
|
||
{
|
||
offset = 0;
|
||
track_end -= 0x0100;
|
||
}
|
||
|
||
uint8_t current = 0;
|
||
int time = 0;
|
||
|
||
dest.push_back(cbit | time);
|
||
|
||
cbit = floppy_image::MG_B;
|
||
|
||
// Oversampled FM images (250 kbit/s) start with a 0, where a 1 is
|
||
// expected for 125 kbit/s.
|
||
// In order to make an oversampled image look like a normally sampled one,
|
||
// we position the transition at 500 ns before the cell end.
|
||
// The HFE format has a 1 us minimum cell size; this means that a normally
|
||
// sampled FM image with 11111... at the begining means
|
||
// 125 kbit/s: 1 1 1 1 1...
|
||
// 250 kbit/s: 01 01 01 01 01...
|
||
// 500 kbit/s: 00010001000100010001...
|
||
//
|
||
// -500 3500 7500 11500
|
||
// +-|---:---|---:-+ | : | : +-|---:---|---:-+ |
|
||
// | | : | : | | : | : | | : | : | |
|
||
// | | : | : +-|---:---|---:-+ | : | : +-|
|
||
// -500 0 2000 4000 6000 8000 10000 12000
|
||
//
|
||
// 3500 (1) samplelength - 500
|
||
// 7500 (1) +samplelength
|
||
// 11500 (1) +samplelength
|
||
// 15500 (1) +samplelength
|
||
//
|
||
// Double samples
|
||
//
|
||
// 1500 (0) samplelength - 500
|
||
// 3500 (1) +samplelength
|
||
// 5500 (0) +samplelength
|
||
// 7500 (1) +samplelength
|
||
// 9500 (0) +samplelength
|
||
// 11500 (1) +samplelength
|
||
|
||
time = -500;
|
||
|
||
// We are creating a sequence of timestamps with flux info
|
||
// Note that the flux change occurs in the last quarter of a cell
|
||
|
||
while (time < 200000000) // one rotation in nanosec
|
||
{
|
||
current = trackbuf[offset];
|
||
for (int j=0; j < 8; j++)
|
||
{
|
||
time += samplelength;
|
||
if ((current & 1)!=0)
|
||
{
|
||
// Append another transition to the vector
|
||
dest.push_back(cbit | time);
|
||
|
||
// Toggle the cell level
|
||
cbit = (cbit == floppy_image::MG_A)? floppy_image::MG_B : floppy_image::MG_A;
|
||
}
|
||
|
||
// HFE uses little-endian bit order
|
||
current >>= 1;
|
||
}
|
||
offset++;
|
||
if ((offset & 0xff)==0) offset += 0x100;
|
||
|
||
// When we have not reached the track end (after 0.2 sec) but run
|
||
// out of samples, repeat the last value
|
||
if (offset >= track_end) offset = track_end - 1;
|
||
}
|
||
|
||
image->set_write_splice_position(cyl, head, 0, 0);
|
||
}
|
||
|
||
bool hfe_format::save(io_generic *io, floppy_image *image)
|
||
{
|
||
std::vector<uint8_t> cylbuf;
|
||
cylbuf.resize(0x6200);
|
||
|
||
uint8_t header[HEADER_LENGTH];
|
||
uint8_t track_table[TRACK_TABLE_LENGTH];
|
||
|
||
int track_end = 0x61c0;
|
||
int samplelength = 2000;
|
||
|
||
// Set up header
|
||
const char* sig = "HXCPICFE";
|
||
memcpy(header, sig, 8);
|
||
|
||
header[8] = 0;
|
||
// Can we change the number of tracks or heads?
|
||
image->get_actual_geometry(m_cylinders, m_heads);
|
||
|
||
header[9] = m_cylinders;
|
||
header[10] = m_heads;
|
||
// Floppy RPM is not used
|
||
header[14] = 0;
|
||
header[15] = 0;
|
||
|
||
// Bit rate and encoding will be set later, they may have changed by
|
||
// reformatting. The selected encoding is UNKNOWN_ENCODING unless
|
||
// explicitly set
|
||
m_track_encoding = m_selected_encoding;
|
||
|
||
// Take the old mode, unless we have specified a mode
|
||
header[16] = (m_selected_mode != DISABLE_FLOPPYMODE)? m_selected_mode : m_interface_mode;
|
||
header[17] = 0;
|
||
|
||
// The track lookup table is located at offset 0x200 (as 512 multiple)
|
||
header[18] = 1;
|
||
header[19] = 0;
|
||
|
||
header[20] = m_write_allowed? 0xff : 0x00;
|
||
header[21] = m_single_step? 0xff : 0x00;
|
||
|
||
// TODO: Allow for divergent track 0 format
|
||
header[22] = m_track0s0_has_altencoding? 0x00 : 0xff;
|
||
header[23] = m_track0s0_encoding;
|
||
header[24] = m_track0s1_has_altencoding? 0x00 : 0xff;
|
||
header[25] = m_track0s1_encoding;
|
||
|
||
// Fill the remaining bytes with 0xff
|
||
for (int i=26; i < HEADER_LENGTH; i++) header[i] = 0xff;
|
||
|
||
// Don't write yet; we still have to find out the bit rate.
|
||
|
||
// We won't have more than 200000 cells on the track
|
||
for (int cyl=0; cyl < m_cylinders; cyl++)
|
||
{
|
||
// After the call, the encoding will be set to FM or MFM
|
||
generate_hfe_bitstream_from_track(cyl, 0, samplelength, m_track_encoding, &cylbuf[0], track_end, image);
|
||
if (m_heads == 2)
|
||
generate_hfe_bitstream_from_track(cyl, 1, samplelength, m_track_encoding, &cylbuf[0], track_end, image);
|
||
|
||
if (cyl==0)
|
||
{
|
||
// Complete the header and write it
|
||
header[11] = m_track_encoding;
|
||
m_bit_rate = 500000/samplelength;
|
||
header[12] = m_bit_rate & 0xff;
|
||
header[13] = (m_bit_rate >> 8) & 0xff;
|
||
|
||
// Now write the header
|
||
io_generic_write(io, header, 0, HEADER_LENGTH);
|
||
|
||
// Set up the track lookup table
|
||
// We need the encoding value to be sure about the track length
|
||
int len = (m_track_encoding==ISOIBM_FM_ENCODING)? 0x61b0 : 0x61c0;
|
||
int pos = 0x400;
|
||
|
||
for (int i=0; i < m_cylinders; i++)
|
||
{
|
||
m_cyl_offset[i] = (pos >> 9);
|
||
m_cyl_length[i] = len;
|
||
pos += (len + 0x1ff) & 0xfe00;
|
||
track_table[i*4] = m_cyl_offset[i] & 0xff;
|
||
track_table[i*4+1] = (m_cyl_offset[i]>>8) & 0xff;
|
||
track_table[i*4+2] = len & 0xff;
|
||
track_table[i*4+3] = (len>>8) & 0xff;
|
||
}
|
||
// Set the remainder to 0xff
|
||
for (int i=m_cylinders*4; i < TRACK_TABLE_LENGTH; i++)
|
||
track_table[i] = 0xff;
|
||
|
||
io_generic_write(io, track_table, 0x200, TRACK_TABLE_LENGTH);
|
||
}
|
||
// Write the current cylinder
|
||
io_generic_write(io, &cylbuf[0], m_cyl_offset[cyl]<<9, (m_cyl_length[cyl] + 0x1ff) & 0xfe00);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void hfe_format::generate_hfe_bitstream_from_track(int cyl, int head, int& samplelength, encoding_t& encoding, uint8_t *cylinder_buffer, int track_end, floppy_image *image)
|
||
{
|
||
// We are using an own implementation here because the result of the
|
||
// parent class method would require some post-processing that we
|
||
// can easily avoid.
|
||
|
||
// See floppy_image_format_t::generate_bitstream_from_track
|
||
// as the original code
|
||
|
||
// No subtracks definded
|
||
std::vector<uint32_t> &tbuf = image->get_buffer(cyl, head, 0);
|
||
if (tbuf.size() <= 1)
|
||
{
|
||
// Unformatted track
|
||
// TODO must handle that according to HFE
|
||
int track_size = 200000000/samplelength;
|
||
memset(cylinder_buffer, 0, (track_size+7)/8);
|
||
return;
|
||
}
|
||
|
||
// Find out whether we have FM or MFM recording, and determine the bit rate.
|
||
// This is needed for the format header.
|
||
//
|
||
// The encoding may have changed by reformatting; we cannot rely on the
|
||
// header when loading.
|
||
//
|
||
// FM: encoding 1 -> flux length = 4 us (min) ambivalent
|
||
// encoding 10 -> flux length = 8 us (max) ambivalent
|
||
// MFM: encoding 10 -> flux length = 4 us (min, DD) ambivalent
|
||
// encoding 100 -> flux length = 6 us (DD) significant
|
||
// encoding 1000 -> flux length = 8 us (max, DD) ambivalent
|
||
// encoding 10 -> flux length = 2 us (min, HD) significant
|
||
// encoding 100 -> flux length = 3 us (max, HD) significant
|
||
|
||
// If we have MFM, we should very soon detect a flux length of 6 us.
|
||
// But if we have FM, how long should we search to be sure?
|
||
// We assume that after 2000 us we should have reached the first IDAM,
|
||
// which contains a sequence 1001, implying a flux length of 6 us.
|
||
// If there was no such flux in that area, this can safely be assumed to be FM.
|
||
|
||
// Do it only for the first track; the format only supports one encoding.
|
||
if (encoding == UNKNOWN_ENCODING)
|
||
{
|
||
bool mfm_recording = false;
|
||
int time0 = 0;
|
||
int minflux = 4000;
|
||
// Skip the beginning (may have a short cell)
|
||
for (int i=2; (i < tbuf.size()-1) && (time0 < 2000000) && !mfm_recording; i++)
|
||
{
|
||
int time0 = tbuf[i] & floppy_image::TIME_MASK;
|
||
int fluxlen = (tbuf[i+1] & floppy_image::TIME_MASK) - time0;
|
||
if ((fluxlen < 3500) || (fluxlen > 5500 && fluxlen < 6500))
|
||
mfm_recording = true;
|
||
if (fluxlen < minflux) minflux = fluxlen;
|
||
}
|
||
encoding = mfm_recording? ISOIBM_MFM_ENCODING : ISOIBM_FM_ENCODING;
|
||
|
||
// samplelength = 1000ns => 10^6 cells/sec => 500 kbit/s
|
||
// samplelength = 2000ns => 250 kbit/s
|
||
// We stay with double sampling at 250 kbit/s for FM
|
||
if (minflux < 3500) samplelength = 1000;
|
||
else samplelength = 2000;
|
||
}
|
||
|
||
// Start at the write splice
|
||
uint32_t splice = image->get_write_splice_position(cyl, head, 0);
|
||
|
||
int cur_pos = splice;
|
||
int cur_entry = 0;
|
||
|
||
// Fast-forward to the write splice position (always 0 in this format)
|
||
while (cur_entry < int(tbuf.size())-1 && (tbuf[cur_entry+1] & floppy_image::TIME_MASK) < cur_pos)
|
||
cur_entry++;
|
||
|
||
int period = samplelength;
|
||
int period_adjust_base = period * 0.05;
|
||
|
||
int min_period = int(samplelength*0.75);
|
||
int max_period = int(samplelength*1.25);
|
||
int phase_adjust = 0;
|
||
int freq_hist = 0;
|
||
uint32_t next = 0;
|
||
|
||
int offset = 0x100;
|
||
|
||
// Prepare offset for the format storage
|
||
if (head==0)
|
||
{
|
||
offset = 0;
|
||
track_end -= 0x0100;
|
||
}
|
||
|
||
uint8_t bit = 0x01;
|
||
uint8_t current = 0;
|
||
|
||
while (next < 200000000) {
|
||
int edge = tbuf[cur_entry] & floppy_image::TIME_MASK;
|
||
|
||
// Start of track? Use next entry.
|
||
if (edge==0)
|
||
{
|
||
cur_pos = 0;
|
||
edge = tbuf[++cur_entry] & floppy_image::TIME_MASK;
|
||
}
|
||
|
||
// Wrapped over end?
|
||
if (edge < cur_pos) edge += 200000000;
|
||
|
||
// End of cell
|
||
next = cur_pos + period + phase_adjust;
|
||
|
||
// End of the window is at next; edge is the actual transition
|
||
if (edge >= next)
|
||
{
|
||
// No transition in the window -> 0
|
||
phase_adjust = 0;
|
||
}
|
||
else
|
||
{
|
||
// Transition in the window -> 1
|
||
current |= bit;
|
||
int delta = edge - (next - period/2);
|
||
|
||
phase_adjust = 0.65*delta;
|
||
|
||
if (delta < 0)
|
||
{
|
||
if (freq_hist < 0) freq_hist--;
|
||
else freq_hist = -1;
|
||
}
|
||
else
|
||
{
|
||
if (delta > 0)
|
||
{
|
||
if(freq_hist > 0) freq_hist++;
|
||
else freq_hist = 1;
|
||
}
|
||
else freq_hist = 0;
|
||
}
|
||
|
||
if (freq_hist)
|
||
{
|
||
int afh = freq_hist < 0 ? -freq_hist : freq_hist;
|
||
if (afh > 1)
|
||
{
|
||
int aper = period_adjust_base*delta/period;
|
||
if (!aper)
|
||
aper = freq_hist < 0 ? -1 : 1;
|
||
period += aper;
|
||
|
||
if (period < min_period) period = min_period;
|
||
else if (period > max_period) period = max_period;
|
||
}
|
||
}
|
||
}
|
||
|
||
cur_pos = next;
|
||
if(cur_pos >= 200000000) {
|
||
cur_pos -= 200000000;
|
||
cur_entry = 0;
|
||
}
|
||
|
||
bit = (bit << 1) & 0xff;
|
||
if (bit == 0)
|
||
{
|
||
bit = 0x01;
|
||
cylinder_buffer[offset++] = current;
|
||
if ((offset & 0xff)==0) offset += 0x100;
|
||
current = 0;
|
||
}
|
||
|
||
// Fast-forward to next cell
|
||
while (cur_entry < int(tbuf.size())-1 && (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos)
|
||
cur_entry++;
|
||
|
||
// Reaching the end of the track
|
||
if (cur_entry == int(tbuf.size())-1 && (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos)
|
||
{
|
||
// Wrap to index 0 or 1 depending on whether there is a transition exactly at the index hole
|
||
cur_entry = (tbuf[int(tbuf.size())-1] & floppy_image::MG_MASK) != (tbuf[0] & floppy_image::MG_MASK) ?
|
||
0 : 1;
|
||
}
|
||
}
|
||
// Write the current byte when not done
|
||
if (bit != 0x01)
|
||
cylinder_buffer[offset] = current;
|
||
}
|
||
|
||
const floppy_format_type FLOPPY_HFE_FORMAT = &floppy_image_format_creator<hfe_format>;
|
||
|
||
|