summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/SDL2/src/timer/SDL_timer_c.h
blob: 6ae8170585cf22843918c4f82a13b7521db63f97 (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
/*
  Simple DirectMedia Layer
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
*/
#include "../SDL_internal.h"

/* Useful functions and variables from SDL_timer.c */
#include "SDL_timer.h"

#define ROUND_RESOLUTION(X) \
    (((X+TIMER_RESOLUTION-1)/TIMER_RESOLUTION)*TIMER_RESOLUTION)

extern void SDL_TicksInit(void);
extern void SDL_TicksQuit(void);
extern int SDL_TimerInit(void);
extern void SDL_TimerQuit(void);

/* vi: set ts=4 sw=4 expandtab: */
> 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
// 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 HFE_FORMAT_HEADER   "HXCPICFE"

#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)
	{
		if (m_cylinders - drivecyl > DUMP_THRESHOLD)
		{
			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;
		}
		else
		{
			// Some dumps has a few excess tracks to be safe,
			// lets be nice and just skip those tracks
			osd_printf_warning("hxchfe: Floppy disk has a slight excess of tracks for this drive that will be discarded (floppy tracks=%d, drive tracks=%d).\n", m_cylinders, drivecyl);
			m_cylinders = drivecyl;
		}
	}

	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;

	// Create a buffer that is big enough to handle HD formats. We don't
	// know the track length until we generate the HFE bitstream.
	cylbuf.resize(0x10000);

	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;
		int fluxlen = 0;
		// Skip the beginning (may have a short cell)
		for (int i=2; (i < tbuf.size()-1) && (time0 < 2000000) && !mfm_recording; i++)
		{
			time0 = tbuf[i] & floppy_image::TIME_MASK;
			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)
		{
			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;

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