Files
86Box/src/disc_86f.c

3290 lines
84 KiB
C
Raw Normal View History

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// #include "crcspeed/crc64speed.h"
// #include "zlib.h"
#include "lzf/lzf.h"
#include "config.h"
#include "disc.h"
#include "disc_86f.h"
#include "disc_random.h"
#include "fdc.h"
#include "fdd.h"
#include "ibm.h"
#define D86FVER 0x020B
#define CHUNK 16384
uint64_t poly = 0x42F0E1EBA9EA3693; /* ECMA normal */
uint64_t table[256];
/* Let's give this some more logic:
Bits 4,3 = Read/write (0 = read, 1 = write, 2 = scan, 3 = verify)
Bits 6,5 = Sector/track (0 = ID, 1 = sector, 2 = deleted sector, 3 = track)
Bit 7 = State type (0 = idle states, 1 = active states)
*/
enum
{
/* 0 ?? ?? ??? */
STATE_IDLE = 0x00,
STATE_SECTOR_NOT_FOUND,
/* 1 00 00 ??? */
STATE_0A_FIND_ID = 0x80, /* READ SECTOR ID */
STATE_0A_READ_ID,
/* 1 01 00 ??? */
STATE_06_FIND_ID = 0xA0, /* READ DATA */
STATE_06_READ_ID,
STATE_06_FIND_DATA,
STATE_06_READ_DATA,
/* 1 01 01 ??? */
STATE_05_FIND_ID = 0xA8, /* WRITE DATA */
STATE_05_READ_ID,
STATE_05_FIND_DATA,
STATE_05_WRITE_DATA,
/* 1 01 10 ??? */
STATE_11_FIND_ID = 0xB0, /* SCAN EQUAL, SCAN LOW OR EQUAL, SCAN HIGH OR EQUAL */
STATE_11_READ_ID,
STATE_11_FIND_DATA,
STATE_11_SCAN_DATA,
/* 1 01 11 ??? */
STATE_16_FIND_ID = 0xB8, /* VERIFY */
STATE_16_READ_ID,
STATE_16_FIND_DATA,
STATE_16_VERIFY_DATA,
/* 1 10 00 ??? */
STATE_0C_FIND_ID = 0xC0, /* READ DELETED DATA */
STATE_0C_READ_ID,
STATE_0C_FIND_DATA,
STATE_0C_READ_DATA,
/* 1 10 01 ??? */
STATE_09_FIND_ID = 0xC8, /* WRITE DELETED DATA */
STATE_09_READ_ID,
STATE_09_FIND_DATA,
STATE_09_WRITE_DATA,
/* 1 11 00 ??? */
STATE_02_SPIN_TO_INDEX = 0xE0, /* READ TRACK */
STATE_02_FIND_ID,
STATE_02_READ_ID,
STATE_02_FIND_DATA,
STATE_02_READ_DATA,
/* 1 11 01 ??? */
STATE_0D_SPIN_TO_INDEX = 0xE8, /* FORMAT TRACK */
STATE_0D_FORMAT_TRACK
};
static uint16_t CRCTable[256];
typedef struct
{
uint8_t c;
uint8_t h;
uint8_t r;
uint8_t n;
} sector_id_fields_t;
typedef union
{
uint32_t dword;
uint8_t byte_array[4];
sector_id_fields_t id;
} sector_id_t;
typedef struct __attribute__((packed))
{
uint8_t buffer[10];
uint32_t pos;
uint32_t len;
} sliding_buffer_t;
typedef struct __attribute__((packed))
{
uint32_t sync_marks;
uint32_t bits_obtained;
uint32_t bytes_obtained;
uint32_t sync_pos;
} find_t;
uint8_t encoded_fm[64] = { 0xAA, 0xAB, 0xAE, 0xAF, 0xBA, 0xBB, 0xBE, 0xBF, 0xEA, 0xEB, 0xEE, 0xEF, 0xFA, 0xFB, 0xFE, 0xFF,
0xAA, 0xAB, 0xAE, 0xAF, 0xBA, 0xBB, 0xBE, 0xBF, 0xEA, 0xEB, 0xEE, 0xEF, 0xFA, 0xFB, 0xFE, 0xFF,
0xAA, 0xAB, 0xAE, 0xAF, 0xBA, 0xBB, 0xBE, 0xBF, 0xEA, 0xEB, 0xEE, 0xEF, 0xFA, 0xFB, 0xFE, 0xFF,
0xAA, 0xAB, 0xAE, 0xAF, 0xBA, 0xBB, 0xBE, 0xBF, 0xEA, 0xEB, 0xEE, 0xEF, 0xFA, 0xFB, 0xFE, 0xFF };
uint8_t encoded_mfm[64] = { 0xAA, 0xA9, 0xA4, 0xA5, 0x92, 0x91, 0x94, 0x95, 0x4A, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55,
0x2A, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, 0x4A, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55,
0xAA, 0xA9, 0xA4, 0xA5, 0x92, 0x91, 0x94, 0x95, 0x4A, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55,
0x2A, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, 0x4A, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 };
enum
{
FMT_PRETRK_GAP0,
FMT_PRETRK_SYNC,
FMT_PRETRK_IAM,
FMT_PRETRK_GAP1,
FMT_SECTOR_ID_SYNC,
FMT_SECTOR_IDAM,
FMT_SECTOR_ID,
FMT_SECTOR_ID_CRC,
FMT_SECTOR_GAP2,
FMT_SECTOR_DATA_SYNC,
FMT_SECTOR_DATAAM,
FMT_SECTOR_DATA,
FMT_SECTOR_DATA_CRC,
FMT_SECTOR_GAP3,
FMT_POSTTRK_CHECK,
FMT_POSTTRK_GAP4,
};
typedef struct __attribute__((packed))
{
unsigned nibble0 :4;
unsigned nibble1 :4;
} split_byte_t;
typedef union {
uint8_t byte;
split_byte_t nibbles;
} decoded_t;
/* Disk flags: Bit 0 Has surface data (1 = yes, 0 = no)
Bits 2, 1 Hole (3 = ED + 2000 kbps, 2 = ED, 1 = HD, 0 = DD)
Bit 3 Sides (1 = 2 sides, 0 = 1 side)
Bit 4 Write protect (1 = yes, 0 = no)
Bits 6, 5 RPM slowdown (3 = 2%, 2 = 1.5%, 1 = 1%, 0 = 0%)
Bit 7 Bitcell mode (1 = Extra bitcells count specified after disk flags, 0 = No extra bitcells)
The maximum number of extra bitcells is 1024 (which after decoding translates to 64 bytes)
Bit 8 Disk type (1 = Zoned, 0 = Fixed RPM)
Bits 10, 9 Zone type (3 = Commodore 64 zoned, 2 = Apple zoned, 1 = Pre-Apple zoned #2, 0 = Pre-Apple zoned #1)
Bit 11 Data and surface bits are stored in reverse byte endianness */
static struct __attribute__((packed))
{
FILE *f;
uint16_t version;
uint16_t disk_flags;
int32_t extra_bit_cells[2];
uint16_t track_encoded_data[2][53048];
uint16_t track_surface_data[2][53048];
uint16_t thin_track_encoded_data[2][2][53048];
uint16_t thin_track_surface_data[2][2][53048];
uint16_t side_flags[2];
uint32_t index_hole_pos[2];
uint32_t track_offset[512];
uint32_t file_size;
sector_id_t format_sector_id;
sector_id_t last_sector;
sector_id_t req_sector;
uint32_t index_count;
uint8_t state;
uint8_t fill;
uint32_t track_pos;
uint32_t datac;
uint32_t id_pos;
uint16_t last_word[2];
find_t id_find;
find_t data_find;
crc_t calc_crc;
crc_t track_crc;
uint8_t sector_count;
uint8_t format_state;
uint16_t satisfying_bytes;
uint16_t preceding_bit[2];
uint16_t current_byte[2];
uint16_t current_bit[2];
int cur_track;
uint32_t error_condition;
int is_compressed;
uint8_t original_file_name[2048];
uint8_t *filebuf;
uint8_t *outbuf;
} d86f[2];
#ifdef OLD_COMPRESS
/* Compress from file source to file dest until EOF on source.
def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_STREAM_ERROR if an invalid compression
level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
version of the library linked do not match, or Z_ERRNO if there is
an error reading or writing the files. */
int def(FILE *source, FILE *dest, int level)
{
int ret, flush;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, level);
if (ret != Z_OK)
return ret;
/* compress until end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = in;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, flush); /* no bad return value */
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /* all input will be used */
/* done when last data in file processed */
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END); /* stream will be complete */
/* clean up and return */
(void)deflateEnd(&strm);
return Z_OK;
}
/* Decompress from file source to file dest until stream ends or EOF.
inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_DATA_ERROR if the deflate data is
invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
the version of the library linked do not match, or Z_ERRNO if there
is an error reading or writing the files. */
int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
if (strm.avail_in == 0)
break;
strm.next_in = in;
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
/* compress or decompress */
int d86f_zlib(FILE *dst, FILE *src, int dir)
{
int ret;
/* do compression if no arguments */
if (!dir) {
ret = def(src, dst, Z_DEFAULT_COMPRESSION);
if (ret != Z_OK)
return 0;
return 1;
}
/* do decompression if -d specified */
else if (dir) {
ret = inf(src, dst);
if (ret != Z_OK)
return 0;
return 1;
}
}
#endif
#ifdef OLD_CRC
void d86f_generate_table64()
{
for(int i=0; i<256; ++i)
{
uint64_t crc = i;
for(unsigned int j=0; j<8; ++j)
{
// is current coefficient set?
if(crc & 1)
{
// yes, then assume it gets zero'd (by implied x^64 coefficient of dividend)
crc >>= 1;
// and add rest of the divisor
crc ^= poly;
}
else
{
// no? then move to next coefficient
crc >>= 1;
}
}
table[i] = crc;
}
}
void d86f_calccrc64(uint8_t b, uint64_t *crc)
{
uint8_t index = b ^ *crc;
uint64_t lookup = table[index];
*crc >>= 8;
*crc ^= lookup;
}
#endif
static void d86f_setupcrc(uint16_t poly)
{
int c = 256, bc;
uint16_t crctemp;
while(c--)
{
crctemp = c << 8;
bc = 8;
while(bc--)
{
if(crctemp & 0x8000)
{
crctemp = (crctemp << 1) ^ poly;
}
else
{
crctemp <<= 1;
}
}
CRCTable[c] = crctemp;
}
}
static int d86f_has_surface_desc(int drive)
{
return (d86f_handler[drive].disk_flags(drive) & 1);
}
int d86f_get_sides(int drive)
{
return ((d86f_handler[drive].disk_flags(drive) >> 3) & 1) + 1;
}
int d86f_get_rpm_mode(int drive)
{
return (d86f_handler[drive].disk_flags(drive) & 0x60) >> 5;
}
int d86f_reverse_bytes(int drive)
{
return (d86f_handler[drive].disk_flags(drive) & 0x800) >> 11;
}
2016-09-26 21:03:23 +02:00
uint16_t d86f_side_flags(int drive);
int d86f_is_mfm(int drive);
void d86f_writeback(int drive);
uint8_t d86f_poll_read_data(int drive, int side, uint16_t pos);
void d86f_poll_write_data(int drive, int side, uint16_t pos, uint8_t data);
int d86f_format_conditions(int drive);
2016-09-26 21:03:23 +02:00
uint16_t d86f_disk_flags(int drive)
{
return d86f[drive].disk_flags;
}
uint32_t d86f_index_hole_pos(int drive, int side)
{
return d86f[drive].index_hole_pos[side];
}
uint32_t null_index_hole_pos(int drive, int side)
{
return 0;
}
2016-09-26 21:03:23 +02:00
uint16_t null_disk_flags(int drive)
{
return 0x09;
}
2016-09-26 21:03:23 +02:00
uint16_t null_side_flags(int drive)
{
return 0x0A;
}
void null_writeback(int drive)
{
return;
}
void null_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n)
{
return;
}
void null_write_data(int drive, int side, uint16_t pos, uint8_t data)
{
return;
}
int null_format_conditions(int drive)
{
return 0;
}
int32_t d86f_extra_bit_cells(int drive, int side)
{
return d86f[drive].extra_bit_cells[side];
}
int32_t null_extra_bit_cells(int drive, int side)
{
return 0;
}
uint16_t* common_encoded_data(int drive, int side)
{
return d86f[drive].track_encoded_data[side];
}
void common_read_revolution(int drive)
{
return;
}
uint16_t d86f_side_flags(int drive)
{
int side = 0;
side = fdd_get_head(drive);
return d86f[drive].side_flags[side];
}
uint16_t d86f_track_flags(int drive)
{
uint16_t tf = 0;
uint16_t rr = 0;
uint16_t dr = 0;
tf = d86f_handler[drive].side_flags(drive);
rr = tf & 0x67;
dr = fdd_get_flags(drive) & 7;
tf &= ~0x67;
switch (rr)
{
case 0x02:
case 0x21:
/* 1 MB unformatted medium, treat these two as equivalent. */
switch (dr)
{
case 0x06:
/* 5.25" Single-RPM HD drive, treat as 300 kbps, 360 rpm. */
tf |= 0x21;
break;
default:
/* Any other drive, treat as 250 kbps, 300 rpm. */
tf |= 0x02;
break;
}
break;
default:
tf |= rr;
break;
}
return tf;
}
uint32_t common_get_raw_size(int drive, int side)
{
double rate = 0.0;
int mfm = 0;
double rpm;
double rpm_diff = 0.0;
double size = 100000.0;
mfm = d86f_is_mfm(drive);
rpm = ((d86f_track_flags(drive) & 0xE0) == 0x20) ? 360.0 : 300.0;
rpm_diff = 1.0;
switch (d86f_get_rpm_mode(drive))
{
case 1:
rpm_diff = 1.01;
break;
case 2:
rpm_diff = 1.015;
break;
case 3:
rpm_diff = 1.02;
break;
default:
rpm_diff = 1.0;
break;
}
switch (d86f_track_flags(drive) & 7)
{
case 0:
rate = 500.0;
break;
case 1:
rate = 300.0;
break;
case 2:
rate = 250.0;
break;
case 3:
rate = 1000.0;
break;
case 5:
rate = 2000.0;
break;
default:
rate = 250.0;
break;
}
if (!mfm) rate /= 2.0;
size = (size / 250.0) * rate;
size = (size * 300.0) / rpm;
size *= rpm_diff;
/* Round down to a multiple of 16 and add the extra bit cells, then return. */
return ((((uint32_t) size) >> 4) << 4) + d86f_handler[drive].extra_bit_cells(drive, side);
}
void d86f_unregister(int drive)
{
d86f_handler[drive].disk_flags = null_disk_flags;
d86f_handler[drive].side_flags = null_side_flags;
d86f_handler[drive].writeback = null_writeback;
d86f_handler[drive].set_sector = null_set_sector;
d86f_handler[drive].write_data = null_write_data;
d86f_handler[drive].format_conditions = null_format_conditions;
d86f_handler[drive].extra_bit_cells = null_extra_bit_cells;
d86f_handler[drive].encoded_data = common_encoded_data;
d86f_handler[drive].read_revolution = common_read_revolution;
d86f_handler[drive].index_hole_pos = null_index_hole_pos;
d86f_handler[drive].get_raw_size = common_get_raw_size;
d86f_handler[drive].check_crc = 0;
d86f[drive].version = 0x0063; /* Proxied formats report as version 0.99. */
}
void d86f_register_86f(int drive)
{
d86f_handler[drive].disk_flags = d86f_disk_flags;
d86f_handler[drive].side_flags = d86f_side_flags;
d86f_handler[drive].writeback = d86f_writeback;
d86f_handler[drive].set_sector = null_set_sector;
d86f_handler[drive].write_data = null_write_data;
d86f_handler[drive].format_conditions = d86f_format_conditions;
d86f_handler[drive].extra_bit_cells = d86f_extra_bit_cells;
d86f_handler[drive].encoded_data = common_encoded_data;
d86f_handler[drive].read_revolution = common_read_revolution;
d86f_handler[drive].index_hole_pos = d86f_index_hole_pos;
d86f_handler[drive].get_raw_size = common_get_raw_size;
d86f_handler[drive].check_crc = 1;
}
int d86f_get_array_size(int drive, int side)
{
int array_size = 0;
int rm = 0;
int hole = 0;
int extra_bytes = 0;
rm = d86f_get_rpm_mode(drive);
hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1;
switch (hole)
{
case 0:
case 1:
default:
array_size = 12500;
switch (rm)
{
case 1:
array_size = 12625;
break;
case 2:
array_size = 12687;
break;
case 3:
array_size = 12750;
break;
default:
array_size = 12500;
break;
}
break;
case 2:
array_size = 25000;
switch (rm)
{
case 1:
array_size = 25250;
break;
case 2:
array_size = 25375;
break;
case 3:
array_size = 25500;
break;
default:
array_size = 25000;
break;
}
break;
case 3:
array_size = 50000;
switch (rm)
{
case 1:
array_size = 50500;
break;
case 2:
array_size = 50750;
break;
case 3:
array_size = 51000;
break;
default:
array_size = 50000;
break;
}
break;
}
array_size <<= 4;
array_size += d86f_handler[drive].extra_bit_cells(drive, side);
array_size >>= 4;
if (d86f_handler[drive].extra_bit_cells(drive, side) & 15)
{
array_size++;
}
return array_size;
}
int d86f_valid_bit_rate(int drive)
{
int rate = 0;
int hole = 0;
rate = fdc_get_bit_rate();
hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1;
switch (hole)
{
case 0: /* DD */
if (!rate && (fdd_get_flags(drive) & 0x10)) return 1;
if ((rate < 1) || (rate > 2)) return 0;
return 1;
case 1: /* HD */
if (rate != 0) return 0;
return 1;
case 2: /* ED */
if (rate != 3) return 0;
return 1;
case 3: /* ED with 2000 kbps support */
if (rate < 3) return 0;
return 1;
}
return 1;
}
int d86f_hole(int drive)
{
if (((d86f_handler[drive].disk_flags(drive) >> 1) & 3) == 3) return 2;
return (d86f_handler[drive].disk_flags(drive) >> 1) & 3;
}
uint8_t d86f_get_encoding(int drive)
{
return (d86f_track_flags(drive) & 0x18) >> 3;
}
double d86f_byteperiod(int drive)
{
switch (d86f_track_flags(drive) & 0x0f)
{
case 0x02: /* 125 kbps, FM */
return 4.0;
case 0x01: /* 150 kbps, FM */
return 20.0 / 6.0;
case 0x0A: /* 250 kbps, MFM */
case 0x00: /* 250 kbps, FM */
return 2.0;
case 0x09: /* 300 kbps, MFM */
return 10.0 / 6.0;
case 0x08: /* 500 kbps, MFM */
return 1.0;
case 0x0B: /* 1000 kbps, MFM */
return 0.5;
case 0x0D: /* 2000 kbps, MFM */
return 0.25;
default:
return 2.0;
}
return 2.0;
}
int d86f_is_mfm(int drive)
{
return (d86f_track_flags(drive) & 8) ? 1 : 0;
}
uint32_t d86f_get_data_len(int drive)
{
if (d86f[drive].req_sector.id.n)
{
if (d86f[drive].req_sector.id.n == 8) return 32768;
return (128 << ((uint32_t) d86f[drive].req_sector.id.n));
}
else
{
if (fdc_get_dtl() < 128)
{
return fdc_get_dtl();
}
else
{
return (128 << ((uint32_t) d86f[drive].req_sector.id.n));
}
}
}
uint32_t d86f_has_extra_bit_cells(int drive)
{
return (d86f_disk_flags(drive) >> 7) & 1;
}
uint32_t d86f_header_size(int drive)
{
return 8;
}
static uint16_t d86f_encode_get_data(uint8_t dat)
{
uint16_t temp;
temp = 0;
if (dat & 0x01) temp |= 1;
if (dat & 0x02) temp |= 4;
if (dat & 0x04) temp |= 16;
if (dat & 0x08) temp |= 64;
if (dat & 0x10) temp |= 256;
if (dat & 0x20) temp |= 1024;
if (dat & 0x40) temp |= 4096;
if (dat & 0x80) temp |= 16384;
return temp;
}
static uint16_t d86f_encode_get_clock(uint8_t dat)
{
uint16_t temp;
temp = 0;
if (dat & 0x01) temp |= 2;
if (dat & 0x02) temp |= 8;
if (dat & 0x40) temp |= 32;
if (dat & 0x08) temp |= 128;
if (dat & 0x10) temp |= 512;
if (dat & 0x20) temp |= 2048;
if (dat & 0x40) temp |= 8192;
if (dat & 0x80) temp |= 32768;
return temp;
}
int d86f_format_conditions(int drive)
{
return d86f_valid_bit_rate(drive);
}
int d86f_can_format(int drive)
{
int temp;
temp = !writeprot[drive];
temp = temp && !swwp;
temp = temp && fdd_can_read_medium(drive ^ fdd_swap);
temp = temp && d86f_handler[drive].format_conditions(drive); /* Allows proxied formats to add their own extra conditions to formatting. */
return temp;
}
uint16_t d86f_encode_byte(int drive, int sync, decoded_t b, decoded_t prev_b)
{
uint8_t encoding = d86f_get_encoding(drive);
uint8_t bits89AB = prev_b.nibbles.nibble0;
uint8_t bits7654 = b.nibbles.nibble1;
uint8_t bits3210 = b.nibbles.nibble0;
uint16_t encoded_7654, encoded_3210, result;
if (encoding > 1) return 0xFF;
if (sync)
{
result = d86f_encode_get_data(b.byte);
if (encoding)
{
switch(b.byte)
{
case 0xA1: return result | d86f_encode_get_clock(0x0A);
case 0xC2: return result | d86f_encode_get_clock(0x14);
case 0xF8: return result | d86f_encode_get_clock(0x03);
case 0xFB: case 0xFE: return result | d86f_encode_get_clock(0x00);
case 0xFC: return result | d86f_encode_get_clock(0x01);
}
}
else
{
switch(b.byte)
{
case 0xF8: case 0xFB: case 0xFE: return result | d86f_encode_get_clock(0xC7);
case 0xFC: return result | d86f_encode_get_clock(0xD7);
}
}
}
bits3210 += ((bits7654 & 3) << 4);
bits7654 += ((bits89AB & 3) << 4);
encoded_3210 = (encoding == 1) ? encoded_mfm[bits3210] : encoded_fm[bits3210];
encoded_7654 = (encoding == 1) ? encoded_mfm[bits7654] : encoded_fm[bits7654];
result = (encoded_7654 << 8) | encoded_3210;
return result;
}
static int d86f_get_bitcell_period(int drive)
{
double rate = 0.0;
int mfm = 0;
int tflags = 0;
double rpm = 0;
double size = 8000.0;
tflags = d86f_track_flags(drive);
mfm = (tflags & 8) ? 1 : 0;
rpm = ((tflags & 0xE0) == 0x20) ? 360.0 : 300.0;
switch (tflags & 7)
{
case 0:
rate = 500.0;
break;
case 1:
rate = 300.0;
break;
case 2:
rate = 250.0;
break;
case 3:
rate = 1000.0;
break;
case 5:
rate = 2000.0;
break;
}
if (!mfm) rate /= 2.0;
size = (size * 250.0) / rate;
size = (size * 300.0) / rpm;
size = (size * fdd_getrpm(drive ^ fdd_swap)) / 300.0;
return (int) size;
}
int d86f_can_read_address(int drive)
{
int temp = 0;
temp = (fdc_get_bitcell_period() == d86f_get_bitcell_period(drive));
temp = temp && fdd_can_read_medium(drive ^ fdd_swap);
temp = temp && (fdc_is_mfm() == d86f_is_mfm(drive));
temp = temp && (d86f_get_encoding(drive) <= 1);
return temp;
}
void d86f_get_bit(int drive, int side)
{
uint32_t track_word;
uint32_t track_bit;
uint16_t encoded_data;
uint16_t surface_data;
uint16_t current_bit;
uint16_t surface_bit;
track_word = d86f[drive].track_pos >> 4;
/* We need to make sure we read the bits from MSB to LSB. */
track_bit = 15 - (d86f[drive].track_pos & 15);
if (d86f_reverse_bytes(drive))
{
/* Image is in reverse endianness, read the data as is. */
encoded_data = d86f_handler[drive].encoded_data(drive, side)[track_word];
}
else
{
/* We store the words as big endian, so we need to convert them to little endian when reading. */
encoded_data = (d86f_handler[drive].encoded_data(drive, side)[track_word] & 0xFF) << 8;
encoded_data |= (d86f_handler[drive].encoded_data(drive, side)[track_word] >> 8);
}
if (d86f_has_surface_desc(drive))
{
if (d86f_reverse_bytes(drive))
{
surface_data = d86f[drive].track_surface_data[side][track_word] & 0xFF;
}
else
{
surface_data = (d86f[drive].track_surface_data[side][track_word] & 0xFF) << 8;
surface_data |= (d86f[drive].track_surface_data[side][track_word] >> 8);
}
}
current_bit = (encoded_data >> track_bit) & 1;
d86f[drive].last_word[side] <<= 1;
if (d86f_has_surface_desc(drive))
{
surface_bit = (surface_data >> track_bit) & 1;
if (!surface_bit)
2016-09-26 21:03:23 +02:00
{
if (!current_bit)
{
/* Bit is 0 and is not set to fuzzy, we add it as read. */
d86f[drive].last_word[side] |= 1;
}
else
{
/* Bit is 1 and is not set to fuzzy, we add it as read. */
d86f[drive].last_word[side] |= 1;
}
2016-09-26 21:03:23 +02:00
}
else
{
if (current_bit)
{
/* Bit is 1 and is set to fuzzy, we randomly generate it. */
d86f[drive].last_word[side] |= (disc_random_generate() & 1);
}
2016-09-26 21:03:23 +02:00
}
}
else
{
d86f[drive].last_word[side] |= current_bit;
}
}
void d86f_put_bit(int drive, int side, int bit)
{
uint32_t track_word;
uint32_t track_bit;
uint16_t encoded_data;
uint16_t surface_data;
uint16_t current_bit;
uint16_t surface_bit;
track_word = d86f[drive].track_pos >> 4;
/* We need to make sure we read the bits from MSB to LSB. */
track_bit = 15 - (d86f[drive].track_pos & 15);
if (d86f_reverse_bytes(drive))
{
/* Image is in reverse endianness, read the data as is. */
encoded_data = d86f_handler[drive].encoded_data(drive, side)[track_word];
}
else
{
/* We store the words as big endian, so we need to convert them to little endian when reading. */
encoded_data = (d86f_handler[drive].encoded_data(drive, side)[track_word] & 0xFF) << 8;
encoded_data |= (d86f_handler[drive].encoded_data(drive, side)[track_word] >> 8);
}
if (d86f_has_surface_desc(drive))
{
if (d86f_reverse_bytes(drive))
{
surface_data = d86f[drive].track_surface_data[side][track_word] & 0xFF;
}
else
{
surface_data = (d86f[drive].track_surface_data[side][track_word] & 0xFF) << 8;
surface_data |= (d86f[drive].track_surface_data[side][track_word] >> 8);
}
}
current_bit = (encoded_data >> track_bit) & 1;
d86f[drive].last_word[side] <<= 1;
if (d86f_has_surface_desc(drive))
{
surface_bit = (surface_data >> track_bit) & 1;
if (!surface_bit)
{
if (!current_bit)
{
/* Bit is 0 and is not set to fuzzy, we overwrite it as is. */
d86f[drive].last_word[side] |= bit;
current_bit = bit;
}
else
{
/* Bit is 1 and is not set to fuzzy, we overwrite it as is. */
d86f[drive].last_word[side] |= bit;
current_bit = bit;
}
}
else
{
if (current_bit)
{
/* Bit is 1 and is set to fuzzy, we overwrite it with a non-fuzzy bit. */
d86f[drive].last_word[side] |= bit;
current_bit = bit;
surface_bit = 0;
}
}
surface_data &= ~(1 << track_bit);
surface_data |= (surface_bit << track_bit);
if (d86f_reverse_bytes(drive))
2016-09-26 21:03:23 +02:00
{
d86f[drive].track_surface_data[side][track_word] = surface_data;
2016-09-26 21:03:23 +02:00
}
else
{
d86f[drive].track_surface_data[side][track_word] = (surface_data & 0xFF) << 8;
d86f[drive].track_surface_data[side][track_word] |= (surface_data >> 8);
2016-09-26 21:03:23 +02:00
}
}
else
{
d86f[drive].last_word[side] |= bit;
current_bit = bit;
}
encoded_data &= ~(1 << track_bit);
encoded_data |= (current_bit << track_bit);
if (d86f_reverse_bytes(drive))
{
d86f_handler[drive].encoded_data(drive, side)[track_word] = encoded_data;
}
else
{
d86f_handler[drive].encoded_data(drive, side)[track_word] = (encoded_data & 0xFF) << 8;
d86f_handler[drive].encoded_data(drive, side)[track_word] |= (encoded_data >> 8);
}
}
static uint8_t decodefm(int drive, uint16_t dat)
{
uint8_t temp = 0;
/* We write the encoded bytes in big endian, so we process the two 8-bit halves swapped here. */
if (dat & 0x0001) temp |= 1;
if (dat & 0x0004) temp |= 2;
if (dat & 0x0010) temp |= 4;
if (dat & 0x0040) temp |= 8;
if (dat & 0x0100) temp |= 16;
if (dat & 0x0400) temp |= 32;
if (dat & 0x1000) temp |= 64;
if (dat & 0x4000) temp |= 128;
return temp;
}
void disc_calccrc(uint8_t byte, crc_t *crc_var)
{
crc_var->word = (crc_var->word << 8) ^ CRCTable[(crc_var->word >> 8)^byte];
}
static void d86f_calccrc(int drive, uint8_t byte)
{
disc_calccrc(byte, &(d86f[drive].calc_crc));
}
int d86f_word_is_aligned(int drive, int side, uint32_t base_pos)
{
int adjusted_track_pos = d86f[drive].track_pos;
if (base_pos == 0xFFFFFFFF)
{
return 0;
}
/* This is very important, it makes sure alignment is detected correctly even across the index hole of a track whose length is not divisible by 16. */
if (adjusted_track_pos < base_pos)
{
adjusted_track_pos += d86f_handler[drive].get_raw_size(drive, side);
}
if ((adjusted_track_pos & 15) == (base_pos & 15))
{
return 1;
}
else
{
return 0;
}
}
/* State 1: Find sector ID */
void d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t ignore_other_am)
{
d86f_get_bit(drive, side);
if (d86f[drive].last_word[side] == req_am)
{
d86f[drive].calc_crc.word = 0xFFFF;
disc_calccrc(decodefm(drive, d86f[drive].last_word[side]), &(d86f[drive].calc_crc));
find->sync_marks = find->bits_obtained = find->bytes_obtained = 0;
find->sync_pos = 0xFFFFFFFF;
d86f[drive].preceding_bit[side] = d86f[drive].last_word[side] & 1;
d86f[drive].state++;
return;
}
if ((ignore_other_am & 2) && (d86f[drive].last_word[side] == other_am))
{
d86f[drive].calc_crc.word = 0xFFFF;
disc_calccrc(decodefm(drive, d86f[drive].last_word[side]), &(d86f[drive].calc_crc));
find->sync_marks = find->bits_obtained = find->bytes_obtained = 0;
find->sync_pos = 0xFFFFFFFF;
if (ignore_other_am & 1)
2016-09-26 21:03:23 +02:00
{
/* Skip mode, let's go back to finding ID. */
d86f[drive].state -= 2;
2016-09-26 21:03:23 +02:00
}
else
{
/* Not skip mode, process the sector anyway. */
fdc_set_wrong_am();
d86f[drive].preceding_bit[side] = d86f[drive].last_word[side] & 1;
d86f[drive].state++;
2016-09-26 21:03:23 +02:00
}
return;
}
}
/* When writing in FM mode, we find the beginning of the address mark by looking for 352 (22 * 16) set bits (gap fill = 0xFF, 0xFFFF FM-encoded). */
void d86f_write_find_address_mark_fm(int drive, int side, find_t *find)
{
d86f_get_bit(drive, side);
if (d86f[drive].last_word[side] & 1)
{
find->sync_marks++;
if (find->sync_marks == 352)
{
d86f[drive].calc_crc.word = 0xFFFF;
d86f[drive].preceding_bit[side] = 1;
find->sync_marks = 0;
d86f[drive].state++;
return;
}
}
/* If we hadn't found enough set bits but have found a clear bit, null the counter of set bits. */
if (!(d86f[drive].last_word[side] & 1))
{
find->sync_marks = find->bits_obtained = find->bytes_obtained = 0;
find->sync_pos = 0xFFFFFFFF;
}
}
void d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t ignore_other_am)
{
d86f_get_bit(drive, side);
if (d86f[drive].last_word[side] == 0x4489)
{
find->sync_marks++;
find->sync_pos = d86f[drive].track_pos;
// pclog("Sync marks: %i\n", find->sync_marks);
return;
}
if ((d86f[drive].last_word[side] == req_am) && (find->sync_marks >= 3))
{
if (d86f_word_is_aligned(drive, side, find->sync_pos))
{
d86f[drive].calc_crc.word = 0xCDB4;
disc_calccrc(decodefm(drive, d86f[drive].last_word[side]), &(d86f[drive].calc_crc));
find->sync_marks = find->bits_obtained = find->bytes_obtained = 0;
find->sync_pos = 0xFFFFFFFF;
// pclog("AM found (%04X) (%02X)\n", req_am, d86f[drive].state);
d86f[drive].preceding_bit[side] = d86f[drive].last_word[side] & 1;
d86f[drive].state++;
return;
}
}
if ((ignore_other_am & 2) && (d86f[drive].last_word[side] == other_am) && (find->sync_marks >= 3))
{
if (d86f_word_is_aligned(drive, side, find->sync_pos))
{
d86f[drive].calc_crc.word = 0xCDB4;
disc_calccrc(decodefm(drive, d86f[drive].last_word[side]), &(d86f[drive].calc_crc));
find->sync_marks = find->bits_obtained = find->bytes_obtained = 0;
find->sync_pos = 0xFFFFFFFF;
if (ignore_other_am & 1)
{
/* Skip mode, let's go back to finding ID. */
d86f[drive].state -= 2;
}
else
{
/* Not skip mode, process the sector anyway. */
fdc_set_wrong_am();
d86f[drive].preceding_bit[side] = d86f[drive].last_word[side] & 1;
d86f[drive].state++;
}
return;
}
}
if (d86f[drive].last_word[side] != 0x4489)
{
if (d86f_word_is_aligned(drive, side, find->sync_pos))
{
find->sync_marks = find->bits_obtained = find->bytes_obtained = 0;
find->sync_pos = 0xFFFFFFFF;
}
}
}
/* When writing in MFM mode, we find the beginning of the address mark by looking for 3 0xA1 sync bytes. */
void d86f_write_find_address_mark_mfm(int drive, int side, find_t *find)
{
d86f_get_bit(drive, side);
if (d86f[drive].last_word[side] == 0x4489)
{
find->sync_marks++;
find->sync_pos = d86f[drive].track_pos;
if (find->sync_marks == 3)
{
d86f[drive].calc_crc.word = 0xCDB4;
d86f[drive].preceding_bit[side] = 1;
find->sync_marks = 0;
d86f[drive].state++;
return;
}
}
/* If we hadn't found enough address mark sync marks, null the counter. */
if (d86f[drive].last_word[side] != 0x4489)
{
if (d86f_word_is_aligned(drive, side, find->sync_pos))
{
find->sync_marks = find->bits_obtained = find->bytes_obtained = 0;
find->sync_pos = 0xFFFFFFFF;
}
}
}
/* State 2: Read sector ID and CRC*/
void d86f_read_sector_id(int drive, int side, int match)
{
uint16_t temp;
if (d86f[drive].id_find.bits_obtained)
{
if (!(d86f[drive].id_find.bits_obtained & 15))
{
/* We've got a byte. */
if (d86f[drive].id_find.bytes_obtained < 4)
{
d86f[drive].last_sector.byte_array[d86f[drive].id_find.bytes_obtained] = decodefm(drive, d86f[drive].last_word[side]);
disc_calccrc(d86f[drive].last_sector.byte_array[d86f[drive].id_find.bytes_obtained], &(d86f[drive].calc_crc));
}
else if ((d86f[drive].id_find.bytes_obtained >= 4) && (d86f[drive].id_find.bytes_obtained < 6))
{
d86f[drive].track_crc.bytes[(d86f[drive].id_find.bytes_obtained & 1) ^ 1] = decodefm(drive, d86f[drive].last_word[side]);
}
d86f[drive].id_find.bytes_obtained++;
if (d86f[drive].id_find.bytes_obtained == 6)
{
/* We've got the ID. */
if (d86f[drive].calc_crc.word != d86f[drive].track_crc.word)
{
d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = 0;
// printf("%04X != %04X (%08X)\n", d86f[drive].track_crc.word, d86f[drive].calc_crc.word, d86f[drive].last_sector.dword);
if ((d86f[drive].state != STATE_02_READ_ID) && (d86f[drive].state != STATE_0A_READ_ID))
{
d86f[drive].error_condition = 0;
d86f[drive].state = STATE_IDLE;
fdc_finishread();
fdc_headercrcerror();
}
else if (d86f[drive].state == STATE_0A_READ_ID)
{
d86f[drive].state--;
}
else
{
d86f[drive].error_condition |= 1; /* Mark that there was an ID CRC error. */
d86f[drive].state++;
}
}
else if ((d86f[drive].calc_crc.word == d86f[drive].track_crc.word) && (d86f[drive].state == STATE_0A_READ_ID))
{
/* CRC is valid and this is a read sector ID command. */
d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = d86f[drive].error_condition = 0;
fdc_sectorid(d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n, 0, 0);
d86f[drive].state = STATE_IDLE;
}
else
{
/* CRC is valid. */
// pclog("Sector ID found: %08X\n", last_sector.dword);
d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = 0;
if ((d86f[drive].last_sector.dword == d86f[drive].req_sector.dword) || !match)
{
// pclog("ID read (%02X)\n", d86f[drive].state);
d86f_handler[drive].set_sector(drive, side, d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n);
d86f[drive].state++;
}
else
{
d86f[drive].state--;
}
}
}
}
}
d86f_get_bit(drive, side);
d86f[drive].id_find.bits_obtained++;
}
uint8_t d86f_get_data(int drive, int base)
{
int data;
2016-09-26 21:03:23 +02:00
if (d86f[drive].data_find.bytes_obtained < (d86f_get_data_len(drive) + base))
{
data = fdc_getdata(d86f[drive].data_find.bytes_obtained == (d86f_get_data_len(drive) + base - 1));
if (data == -1)
{
data = 0;
}
}
else
{
data = 0;
}
return data;
}
void d86f_compare_byte(int drive, uint8_t received_byte, uint8_t disk_byte)
{
switch(fdc_get_compare_condition())
{
case 0: /* SCAN EQUAL */
if ((received_byte == disk_byte) || (received_byte == 0xFF))
{
d86f[drive].satisfying_bytes++;
}
break;
case 1: /* SCAN LOW OR EQUAL */
if ((received_byte <= disk_byte) || (received_byte == 0xFF))
{
d86f[drive].satisfying_bytes++;
}
break;
case 2: /* SCAN HIGH OR EQUAL */
if ((received_byte >= disk_byte) || (received_byte == 0xFF))
{
d86f[drive].satisfying_bytes++;
}
break;
}
}
/* State 4: Read sector data and CRC*/
void d86f_read_sector_data(int drive, int side)
{
int data = 0;
int recv_data = 0;
uint16_t temp;
uint32_t sector_len = d86f[drive].last_sector.id.n;
uint32_t crc_pos = 0;
sector_len = 1 << (7 + sector_len);
crc_pos = sector_len + 2;
if (d86f[drive].data_find.bits_obtained)
{
if (!(d86f[drive].data_find.bits_obtained & 15))
{
/* We've got a byte. */
if (d86f[drive].data_find.bytes_obtained < sector_len)
{
data = decodefm(drive, d86f[drive].last_word[side]);
if (d86f[drive].state == STATE_11_SCAN_DATA)
{
/* Scan/compare command. */
recv_data = d86f_get_data(drive, 0);
d86f_compare_byte(drive, recv_data, data);
}
else
{
if (d86f[drive].data_find.bytes_obtained < d86f_get_data_len(drive))
{
if (d86f[drive].state != STATE_16_VERIFY_DATA)
{
fdc_data(data);
}
}
}
disc_calccrc(data, &(d86f[drive].calc_crc));
}
else if (d86f[drive].data_find.bytes_obtained < crc_pos)
{
d86f[drive].track_crc.bytes[(d86f[drive].data_find.bytes_obtained - sector_len) ^ 1] = decodefm(drive, d86f[drive].last_word[side]);
}
d86f[drive].data_find.bytes_obtained++;
if (d86f[drive].data_find.bytes_obtained == (crc_pos + fdc_get_gap()))
{
/* We've got the data. */
if ((d86f[drive].calc_crc.word != d86f[drive].track_crc.word) && (d86f[drive].state != STATE_02_READ_DATA))
{
// printf("%04X != %04X (%08X)\n", d86f[drive].track_crc.word, d86f[drive].calc_crc.word, d86f[drive].last_sector.dword);
d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0;
d86f[drive].error_condition = 0;
d86f[drive].state = STATE_IDLE;
fdc_finishread();
fdc_datacrcerror();
}
else if ((d86f[drive].calc_crc.word != d86f[drive].track_crc.word) && (d86f[drive].state == STATE_02_READ_DATA))
{
// printf("%04X != %04X (%08X)\n", d86f[drive].track_crc.word, d86f[drive].calc_crc.word, d86f[drive].last_sector.dword);
d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0;
d86f[drive].error_condition |= 2; /* Mark that there was a data error. */
d86f[drive].state = STATE_IDLE;
fdc_track_finishread(d86f[drive].error_condition);
}
else
{
/* CRC is valid. */
d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0;
d86f[drive].error_condition = 0;
if (d86f[drive].state == STATE_11_SCAN_DATA)
{
d86f[drive].state = STATE_IDLE;
fdc_sector_finishcompare((d86f[drive].satisfying_bytes == ((128 << ((uint32_t) d86f[drive].last_sector.id.n)) - 1)) ? 1 : 0);
}
else
{
d86f[drive].state = STATE_IDLE;
fdc_sector_finishread();
}
}
}
}
}
d86f_get_bit(drive, side);
d86f[drive].data_find.bits_obtained++;
}
void d86f_write_sector_data(int drive, int side, int mfm, uint16_t am)
{
uint16_t bit_pos;
uint16_t temp;
uint32_t sector_len = d86f[drive].last_sector.id.n;
uint32_t crc_pos = 0;
sector_len = (1 << (7 + sector_len)) + 1;
crc_pos = sector_len + 2;
if (!(d86f[drive].data_find.bits_obtained & 15))
{
if (d86f[drive].data_find.bytes_obtained < crc_pos)
{
if (!d86f[drive].data_find.bytes_obtained)
{
/* We're writing the address mark. */
d86f[drive].current_byte[side] = am;
}
else if (d86f[drive].data_find.bytes_obtained < sector_len)
{
/* We're in the data field of the sector, read byte from FDC and request new byte. */
d86f[drive].current_byte[side] = d86f_get_data(drive, 1);
d86f_handler[drive].write_data(drive, side, d86f[drive].data_find.bytes_obtained - 1, d86f[drive].current_byte[side]);
}
else
{
/* We're in the data field of the sector, use a CRC byte. */
d86f[drive].current_byte[side] = d86f[drive].calc_crc.bytes[(d86f[drive].data_find.bytes_obtained & 1)];
// pclog("BO: %04X (%02X)\n", d86f[drive].data_find.bytes_obtained, d86f[drive].current_byte[side]);
}
d86f[drive].current_bit[side] = (15 - (d86f[drive].data_find.bits_obtained & 15)) >> 1;
/* Write the bit. */
temp = (d86f[drive].current_byte[side] >> d86f[drive].current_bit[side]) & 1;
if ((!temp && !d86f[drive].preceding_bit[side]) || !mfm)
{
temp |= 2;
}
/* This is an even bit, so write the clock. */
if (!d86f[drive].data_find.bytes_obtained)
{
/* Address mark, write bit directly. */
d86f_put_bit(drive, side, am >> 15);
}
else
{
d86f_put_bit(drive, side, temp >> 1);
}
if (d86f[drive].data_find.bytes_obtained < sector_len)
{
/* This is a data byte, so CRC it. */
if (!d86f[drive].data_find.bytes_obtained)
{
disc_calccrc(decodefm(drive, am), &(d86f[drive].calc_crc));
}
else
{
disc_calccrc(d86f[drive].current_byte[side], &(d86f[drive].calc_crc));
}
}
}
}
else
{
if (d86f[drive].data_find.bytes_obtained < crc_pos)
{
/* Encode the bit. */
bit_pos = 15 - (d86f[drive].data_find.bits_obtained & 15);
d86f[drive].current_bit[side] = bit_pos >> 1;
temp = (d86f[drive].current_byte[side] >> d86f[drive].current_bit[side]) & 1;
if ((!temp && !d86f[drive].preceding_bit[side]) || !mfm)
{
temp |= 2;
}
if (!d86f[drive].data_find.bytes_obtained)
{
/* Address mark, write directly. */
d86f_put_bit(drive, side, am >> bit_pos);
if (!(bit_pos & 1))
{
d86f[drive].preceding_bit[side] = am >> bit_pos;
}
}
else
{
if (bit_pos & 1)
{
/* Clock bit */
d86f_put_bit(drive, side, temp >> 1);
}
else
{
/* Data bit */
d86f_put_bit(drive, side, temp & 1);
d86f[drive].preceding_bit[side] = temp & 1;
}
}
}
if ((d86f[drive].data_find.bits_obtained & 15) == 15)
{
d86f[drive].data_find.bytes_obtained++;
if (d86f[drive].data_find.bytes_obtained == (crc_pos + fdc_get_gap()))
{
/* We've written the data. */
d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0;
d86f[drive].error_condition = 0;
d86f[drive].state = STATE_IDLE;
d86f_handler[drive].writeback(drive);
fdc_sector_finishread();
return;
}
}
}
d86f[drive].data_find.bits_obtained++;
}
void d86f_advance_bit(int drive, int side)
{
d86f[drive].track_pos++;
d86f[drive].track_pos %= d86f_handler[drive].get_raw_size(drive, side);
if (d86f[drive].track_pos == d86f_handler[drive].index_hole_pos(drive, side)) d86f_handler[drive].read_revolution(drive);
if ((d86f[drive].track_pos == d86f_handler[drive].index_hole_pos(drive, side)) && (d86f[drive].state != STATE_IDLE)) d86f[drive].index_count++;
}
void d86f_advance_word(int drive, int side)
{
d86f[drive].track_pos += 16;
d86f[drive].track_pos %= d86f_handler[drive].get_raw_size(drive, side);
}
void d86f_spin_to_index(int drive, int side)
{
d86f_get_bit(drive, side);
d86f_get_bit(drive, side ^ 1);
d86f_advance_bit(drive, side);
if (d86f[drive].track_pos == d86f_handler[drive].index_hole_pos(drive, side))
{
if (d86f[drive].state == STATE_0D_SPIN_TO_INDEX)
{
/* When starting format, reset format state to the beginning. */
d86f[drive].preceding_bit[side] = 1;
d86f[drive].format_state = FMT_PRETRK_GAP0;
}
/* This is to make sure both READ TRACK and FORMAT TRACK command don't end prematurely. */
d86f[drive].index_count = 0;
d86f[drive].state++;
}
}
void d86f_write_direct_common(int drive, int side, uint16_t byte, uint8_t type, uint32_t pos)
{
uint16_t encoded_byte, mask_data, mask_surface, mask_hole, mask_fuzzy;
decoded_t dbyte, dpbyte;
dbyte.byte = byte;
dpbyte.byte = d86f[drive].preceding_bit[side];
d86f[drive].preceding_bit[side] = encoded_byte & 1;
if (type == 0)
{
/* Byte write. */
encoded_byte = d86f_encode_byte(drive, 0, dbyte, dpbyte);
if (!d86f_reverse_bytes(drive))
{
mask_data = encoded_byte >> 8;
encoded_byte &= 0xFF;
encoded_byte <<= 8;
encoded_byte |= mask_data;
}
}
else
{
/* Word write. */
encoded_byte = byte;
if (d86f_reverse_bytes(drive))
{
mask_data = encoded_byte >> 8;
encoded_byte &= 0xFF;
encoded_byte <<= 8;
encoded_byte |= mask_data;
}
}
if (d86f_has_surface_desc(drive))
{
mask_data = d86f[drive].track_encoded_data[side][pos] ^= 0xFFFF;
mask_surface = d86f[drive].track_surface_data[side][pos];
mask_hole = (mask_surface & mask_data) ^ 0xFFFF; /* This will retain bits that are both fuzzy and 0, therefore physical holes. */
encoded_byte &= mask_hole; /* Filter out physical hole bits from the encoded data. */
mask_data ^= 0xFFFF; /* Invert back so bits 1 are 1 again. */
mask_fuzzy = (mask_surface & mask_data) ^ 0xFFFF; /* All fuzzy bits are 0. */
d86f[drive].track_surface_data[side][pos] &= mask_fuzzy; /* Remove fuzzy bits (but not hole bits) from the surface mask, making them regular again. */
}
d86f[drive].track_encoded_data[side][pos] = encoded_byte;
d86f[drive].last_word[side] = encoded_byte;
}
void d86f_write_direct(int drive, int side, uint16_t byte, uint8_t type)
{
d86f_write_direct_common(drive, side, byte, type, d86f[drive].track_pos >> 4);
}
uint16_t endian_swap(uint16_t word)
{
uint16_t temp;
temp = word & 0xff;
temp <<= 8;
temp |= (word >> 8);
return temp;
}
void d86f_format_track(int drive, int side)
{
int data;
uint16_t max_len, temp, temp2;
int mfm;
uint16_t i = 0;
uint16_t j = 0;
uint16_t sc = 0;
uint16_t dtl = 0;
int gap_sizes[4] = { 0, 0, 0, 0 };
int am_len = 0;
int sync_len = 0;
uint16_t iam_mfm[4] = { 0x2452, 0x2452, 0x2452, 0x5255 };
uint16_t idam_mfm[4] = { 0x8944, 0x8944, 0x8944, 0x5455 };
uint16_t dataam_mfm[4] = { 0x8944, 0x8944, 0x8944, 0x4555 };
uint16_t iam_fm = 0xFAF7;
uint16_t idam_fm = 0x7EF5;
uint16_t dataam_fm = 0x6FF5;
uint16_t gap_fill = 0x4E;
int do_write = 0;
mfm = d86f_is_mfm(drive);
am_len = mfm ? 4 : 1;
gap_sizes[0] = mfm ? 80 : 40;
gap_sizes[1] = mfm ? 50 : 26;
gap_sizes[2] = fdc_get_gap2(drive ^ fdd_swap);
gap_sizes[3] = fdc_get_gap();
sync_len = mfm ? 12 : 6;
sc = fdc_get_format_sectors();
dtl = 128 << fdc_get_format_n();
gap_fill = mfm ? 0x4E : 0xFF;
do_write = (d86f[drive].version == D86FVER);
switch(d86f[drive].format_state)
{
case FMT_POSTTRK_GAP4:
max_len = 60000;
if (do_write) d86f_write_direct(drive, side, gap_fill, 0);
break;
case FMT_PRETRK_GAP0:
max_len = gap_sizes[0];
if (do_write) d86f_write_direct(drive, side, gap_fill, 0);
break;
case FMT_SECTOR_ID_SYNC:
if (d86f[drive].datac <= 3)
{
data = fdc_getdata(0);
if ((data == -1) && (d86f[drive].datac < 3))
{
data = 0;
}
d86f[drive].format_sector_id.byte_array[d86f[drive].datac] = data & 0xff;
// pclog("format_sector_id[%i] = %i\n", d86f[drive].datac, d86f[drive].format_sector_id.byte_array[d86f[drive].datac]);
if (d86f[drive].datac == 3)
{
fdc_stop_id_request();
// pclog("Formatting sector: %08X...\n", d86f[drive].format_sector_id.dword);
}
}
case FMT_PRETRK_SYNC:
case FMT_SECTOR_DATA_SYNC:
max_len = sync_len;
if (do_write) d86f_write_direct(drive, side, 0x00, 0);
break;
case FMT_PRETRK_IAM:
max_len = am_len;
if (do_write)
{
if (mfm)
{
d86f_write_direct(drive, side, iam_mfm[d86f[drive].datac], 1);
}
else
{
d86f_write_direct(drive, side, iam_fm, 1);
}
}
break;
case FMT_PRETRK_GAP1:
max_len = gap_sizes[1];
if (do_write) d86f_write_direct(drive, side, gap_fill, 0);
break;
case FMT_SECTOR_IDAM:
max_len = am_len;
if (mfm)
{
if (do_write) d86f_write_direct(drive, side, idam_mfm[d86f[drive].datac], 1);
d86f_calccrc(drive, (d86f[drive].datac < 3) ? 0xA1 : 0xFE);
}
else
{
if (do_write) d86f_write_direct(drive, side, idam_fm, 1);
d86f_calccrc(drive, 0xFE);
}
break;
case FMT_SECTOR_ID:
max_len = 4;
if (do_write)
{
d86f_write_direct(drive, side, d86f[drive].format_sector_id.byte_array[d86f[drive].datac], 0);
d86f_calccrc(drive, d86f[drive].format_sector_id.byte_array[d86f[drive].datac]);
}
else
{
if (d86f[drive].datac == 3)
{
d86f_handler[drive].set_sector(drive, side, d86f[drive].format_sector_id.id.c, d86f[drive].format_sector_id.id.h, d86f[drive].format_sector_id.id.r, d86f[drive].format_sector_id.id.n);
}
}
break;
case FMT_SECTOR_ID_CRC:
case FMT_SECTOR_DATA_CRC:
max_len = 2;
if (do_write) d86f_write_direct(drive, side, d86f[drive].calc_crc.bytes[d86f[drive].datac ^ 1], 0);
break;
case FMT_SECTOR_GAP2:
max_len = gap_sizes[2];
if (do_write) d86f_write_direct(drive, side, gap_fill, 0);
break;
case FMT_SECTOR_DATAAM:
max_len = am_len;
if (mfm)
{
if (do_write) d86f_write_direct(drive, side, dataam_mfm[d86f[drive].datac], 1);
d86f_calccrc(drive, (d86f[drive].datac < 3) ? 0xA1 : 0xFB);
}
else
{
if (do_write) d86f_write_direct(drive, side, dataam_fm, 1);
d86f_calccrc(drive, 0xFB);
}
break;
case FMT_SECTOR_DATA:
max_len = dtl;
if (do_write) d86f_write_direct(drive, side, d86f[drive].fill, 0);
d86f_calccrc(drive, d86f[drive].fill);
break;
case FMT_SECTOR_GAP3:
max_len = gap_sizes[3];
if (do_write) d86f_write_direct(drive, side, gap_fill, 0);
break;
}
d86f[drive].datac++;
d86f_advance_word(drive, side);
if (d86f[drive].track_pos == d86f_handler[drive].index_hole_pos(drive, side))
{
/* Before we return, if the encoding is MFM, we have to make sure the clock bit of the first bit in the track is correct. */
if (mfm && do_write)
{
if (do_write) d86f_write_direct_common(drive, side, gap_fill, 0, 0);
}
d86f[drive].state = STATE_IDLE;
d86f_handler[drive].writeback(drive);
// pclog("Format finished!\n");
d86f[drive].error_condition = 0;
d86f[drive].datac = 0;
fdc_sector_finishread();
return;
}
if (d86f[drive].datac >= max_len)
{
d86f[drive].datac = 0;
d86f[drive].format_state++;
switch (d86f[drive].format_state)
{
case FMT_SECTOR_ID_SYNC:
fdc_request_next_sector_id();
break;
case FMT_SECTOR_IDAM:
case FMT_SECTOR_DATAAM:
d86f[drive].calc_crc.word = 0xffff;
break;
case FMT_POSTTRK_CHECK:
d86f[drive].sector_count++;
if (d86f[drive].sector_count < sc)
{
/* Sector within allotted amount, change state to SECTOR_ID_SYNC. */
d86f[drive].format_state = FMT_SECTOR_ID_SYNC;
fdc_request_next_sector_id();
break;
}
else
{
d86f[drive].format_state = FMT_POSTTRK_GAP4;
d86f[drive].sector_count = 0;
break;
}
}
}
}
void d86f_poll(int drive)
{
int side = 0;
int mfm = 1;
side = fdd_get_head(drive);
mfm = fdc_is_mfm();
if ((d86f[drive].state & 0xF8) == 0xE8)
2016-09-26 21:03:23 +02:00
{
if (!d86f_can_format(drive))
{
d86f[drive].state = STATE_SECTOR_NOT_FOUND;
}
2016-09-26 21:03:23 +02:00
}
if ((d86f[drive].state != STATE_IDLE) && (d86f[drive].state != STATE_SECTOR_NOT_FOUND) && ((d86f[drive].state & 0xF8) != 0xE8))
{
if (!d86f_can_read_address(drive))
{
/* if (fdc_get_bitcell_period() != d86f_get_bitcell_period(drive)) pclog("Bitcell period mismatch\n");
if (!fdd_can_read_medium(drive ^ fdd_swap)) pclog("Drive can not read medium (hole = %01X)\n", d86f_hole(drive));
if (fdc_is_mfm() != d86f_is_mfm(drive)) pclog("Encoding mismatch\n");
if (d86f_get_encoding(drive) > 1) pclog("Image encoding (%s) not FM or MFM\n", (d86f_get_encoding(drive) == 2) ? "M2FM" : "GCR"); */
d86f[drive].state = STATE_SECTOR_NOT_FOUND;
}
}
d86f_get_bit(drive, side ^ 1);
switch(d86f[drive].state)
{
case STATE_02_SPIN_TO_INDEX:
case STATE_0D_SPIN_TO_INDEX:
d86f_spin_to_index(drive, side);
return;
case STATE_02_FIND_ID:
case STATE_05_FIND_ID:
case STATE_09_FIND_ID:
case STATE_06_FIND_ID:
case STATE_0A_FIND_ID:
case STATE_0C_FIND_ID:
case STATE_11_FIND_ID:
case STATE_16_FIND_ID:
if (mfm)
{
d86f_find_address_mark_mfm(drive, side, &(d86f[drive].id_find), 0x5554, 0, 0);
}
else
{
d86f_find_address_mark_fm(drive, side, &(d86f[drive].id_find), 0xF57E, 0, 0);
}
break;
case STATE_0A_READ_ID:
case STATE_02_READ_ID:
d86f_read_sector_id(drive, side, 0);
break;
case STATE_05_READ_ID:
case STATE_09_READ_ID:
case STATE_06_READ_ID:
case STATE_0C_READ_ID:
case STATE_11_READ_ID:
case STATE_16_READ_ID:
d86f_read_sector_id(drive, side, 1);
break;
case STATE_02_FIND_DATA:
if (mfm)
{
d86f_find_address_mark_mfm(drive, side, &(d86f[drive].data_find), 0x5545, 0x554A, 2);
}
else
{
d86f_find_address_mark_fm(drive, side, &(d86f[drive].data_find), 0xF56F, 0xF56A, 2);
}
break;
case STATE_06_FIND_DATA:
case STATE_11_FIND_DATA:
case STATE_16_FIND_DATA:
if (mfm)
{
d86f_find_address_mark_mfm(drive, side, &(d86f[drive].data_find), 0x5545, 0x554A, fdc_is_sk() | 2);
}
else
{
d86f_find_address_mark_fm(drive, side, &(d86f[drive].data_find), 0xF56F, 0xF56A, fdc_is_sk() | 2);
}
break;
case STATE_05_FIND_DATA:
case STATE_09_FIND_DATA:
if (mfm)
{
d86f_write_find_address_mark_mfm(drive, side, &(d86f[drive].data_find));
}
else
{
d86f_write_find_address_mark_fm(drive, side, &(d86f[drive].data_find));
}
break;
case STATE_0C_FIND_DATA:
if (mfm)
{
d86f_find_address_mark_mfm(drive, side, &(d86f[drive].data_find), 0x554A, 0x5545, fdc_is_sk() | 2);
}
else
{
d86f_find_address_mark_fm(drive, side, &(d86f[drive].data_find), 0xF56A, 0xF56F, fdc_is_sk() | 2);
}
break;
case STATE_02_READ_DATA:
case STATE_06_READ_DATA:
case STATE_0C_READ_DATA:
case STATE_11_SCAN_DATA:
case STATE_16_VERIFY_DATA:
d86f_read_sector_data(drive, side);
break;
case STATE_05_WRITE_DATA:
if (mfm)
{
d86f_write_sector_data(drive, side, mfm, 0x5545);
}
else
{
d86f_write_sector_data(drive, side, mfm, 0xF56F);
}
break;
case STATE_09_WRITE_DATA:
if (mfm)
{
d86f_write_sector_data(drive, side, mfm, 0x554A);
}
else
{
d86f_write_sector_data(drive, side, mfm, 0xF56A);
}
break;
case STATE_0D_FORMAT_TRACK:
if (!(d86f[drive].track_pos & 15))
{
d86f_format_track(drive, side);
}
return;
case STATE_IDLE:
case STATE_SECTOR_NOT_FOUND:
default:
d86f_get_bit(drive, side);
break;
}
d86f_advance_bit(drive, side);
if ((d86f[drive].index_count == 2) && (d86f[drive].state != STATE_IDLE))
{
// pclog("[State: %02X] [Side %i] Sector not found (%i != %i?) (%02X) (%08X) (%i)\n", d86f[drive].state, side, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), d86f_handler[drive].side_flags(drive), d86f[drive].req_sector.dword, d86f_handler[drive].get_raw_size(drive, side));
d86f[drive].state = STATE_IDLE;
fdc_notfound();
}
}
#if 0
void d86f_poll(int drive)
{
int i = 0;
for (i = 0; i < 16; i++)
{
d86f_bit_poll(drive);
}
}
void d86f_poll()
{
int drive = 0;
drive = fdc_get_drive();
d86f_poll_per_drive(drive);
}
#endif
void d86f_reset_index_hole_pos(int drive, int side)
{
d86f[drive].index_hole_pos[side] = 0;
}
uint16_t d86f_prepare_pretrack(int drive, int side, int iso)
{
uint16_t i, pos;
int mfm = 0;
int real_gap0_len = 0;
int sync_len = 0;
int real_gap1_len = 0;
uint16_t gap_fill = 0;
uint32_t raw_size = 0;
uint16_t iam_fm = 0xFAF7;
uint16_t iam_mfm = 0x5255;
mfm = d86f_is_mfm(drive);
real_gap0_len = mfm ? 80 : 40;
sync_len = mfm ? 12 : 6;
real_gap1_len = mfm ? 50 : 26;
gap_fill = mfm ? 0x4E : 0xFF;
raw_size = d86f_handler[drive].get_raw_size(drive, side) >> 4;
d86f[drive].index_hole_pos[side] = 0;
for (i = 0; i < raw_size; i++)
{
d86f_write_direct_common(drive, side, gap_fill, 0, i);
}
pos = 0;
if (!iso)
{
for (i = 0; i < real_gap0_len; i++)
{
d86f_write_direct_common(drive, side, gap_fill, 0, pos);
pos = (pos + 1) % raw_size;
}
for (i = 0; i < sync_len; i++)
{
d86f_write_direct_common(drive, side, 0, 0, pos);
pos = (pos + 1) % raw_size;
}
if (mfm)
{
for (i = 0; i < 3; i++)
{
d86f_write_direct_common(drive, side, 0x2452, 1, pos);
pos = (pos + 1) % raw_size;
}
}
d86f_write_direct_common(drive, side, mfm ? iam_mfm : iam_fm, 1, pos);
pos = (pos + 1) % raw_size;
}
for (i = 0; i < real_gap0_len; i++)
{
d86f_write_direct_common(drive, side, gap_fill, 0, pos);
pos = (pos + 1) % raw_size;
}
return pos;
}
uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t *data_buf, int data_len, int gap2, int gap3, int deleted, int bad_crc)
{
uint16_t pos;
int i;
int real_gap2_len = gap2;
int real_gap3_len = gap3;
int mfm = 0;
int sync_len = 0;
uint16_t gap_fill = 0;
uint32_t raw_size = 0;
uint16_t idam_fm = 0x7EF5;
uint16_t dataam_fm = 0x6FF5;
uint16_t datadam_fm = 0x6AF5;
uint16_t idam_mfm = 0x5455;
uint16_t dataam_mfm = 0x4555;
uint16_t datadam_mfm = 0x4A55;
mfm = d86f_is_mfm(drive);
gap_fill = mfm ? 0x4E : 0xFF;
raw_size = d86f_handler[drive].get_raw_size(drive, side) >> 4;
pos = prev_pos;
sync_len = mfm ? 12 : 6;
for (i = 0; i < sync_len; i++)
{
d86f_write_direct_common(drive, side, 0, 0, pos);
pos = (pos + 1) % raw_size;
}
d86f[drive].calc_crc.word = 0xffff;
if (mfm)
{
for (i = 0; i < 3; i++)
{
d86f_write_direct_common(drive, side, 0x8944, 1, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(drive, 0xA1);
}
}
d86f_write_direct_common(drive, side, mfm ? idam_mfm : idam_fm, 1, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(drive, 0xFE);
for (i = 0; i < 4; i++)
{
d86f_write_direct_common(drive, side, id_buf[i], 0, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(drive, id_buf[i]);
}
for (i = 1; i >= 0; i--)
{
d86f_write_direct_common(drive, side, d86f[drive].calc_crc.bytes[i], 0, pos);
pos = (pos + 1) % raw_size;
}
for (i = 0; i < real_gap2_len; i++)
{
d86f_write_direct_common(drive, side, gap_fill, 0, pos);
pos = (pos + 1) % raw_size;
}
for (i = 0; i < sync_len; i++)
{
d86f_write_direct_common(drive, side, 0, 0, pos);
pos = (pos + 1) % raw_size;
}
d86f[drive].calc_crc.word = 0xffff;
if (mfm)
{
for (i = 0; i < 3; i++)
{
d86f_write_direct_common(drive, side, 0x8944, 1, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(drive, 0xA1);
}
}
d86f_write_direct_common(drive, side, mfm ? (deleted ? datadam_mfm : dataam_mfm) : (deleted ? datadam_fm : dataam_fm), 1, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(drive, deleted ? 0xF8 : 0xFB);
for (i = 0; i < data_len; i++)
{
d86f_write_direct_common(drive, side, data_buf[i], 0, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(drive, data_buf[i]);
}
if (bad_crc)
{
d86f[drive].calc_crc.word ^= 0xffff;
}
for (i = 1; i >= 0; i--)
{
d86f_write_direct_common(drive, side, d86f[drive].calc_crc.bytes[i], 0, pos);
pos = (pos + 1) % raw_size;
}
for (i = 0; i < real_gap3_len; i++)
{
d86f_write_direct_common(drive, side, gap_fill, 0, pos);
pos = (pos + 1) % raw_size;
}
return pos;
}
/* Note on handling of tracks on thick track drives:
- On seek, encoded data is constructed from both (track << 1) and ((track << 1) + 1);
- Any bits that differ are treated as thus:
- Both are regular but contents differ -> Output is fuzzy;
- One is regular and one is fuzzy -> Output is fuzzy;
- Both are fuzzy -> Output is fuzzy;
- Both are physical holes -> Output is a physical hole;
- One is regular and one is a physical hole -> Output is puzzy, the hole half is handled appropriately on writeback;
- One is fuzzy and one is a physical hole -> Output is puzzy, the hole half is handled appropriately on writeback;
- On write back, apart from the above notes, the final two tracks are written;
- Destination ALWAYS has surface data even if the image does not.
In case of a thin track drive, tracks are handled normally. */
void d86f_construct_encoded_buffer(int drive, int side)
{
int i = 0;
/* *_fuzm are fuzzy bit masks, *_holm are hole masks, dst_neim are masks is mask for bits that are neither fuzzy nor holes in both,
and src1_d and src2_d are filtered source data. */
uint16_t src1_fuzm, src2_fuzm, dst_fuzm, src1_holm, src2_holm, dst_holm, dst_neim, src1_d, src2_d;
uint32_t len;
uint16_t *dst = d86f[drive].track_encoded_data[side];
uint16_t *dst_s = d86f[drive].track_surface_data[side];
uint16_t *src1 = d86f[drive].thin_track_encoded_data[0][side];
uint16_t *src1_s = d86f[drive].thin_track_surface_data[0][side];
uint16_t *src2 = d86f[drive].thin_track_encoded_data[1][side];
uint16_t *src2_s = d86f[drive].thin_track_surface_data[1][side];
len = d86f_get_array_size(drive, side);
for (i = 0; i < len; i++)
{
/* The two bits differ. */
if (d86f_has_surface_desc(drive))
{
/* Source image has surface description data, so we have some more handling to do. */
src1_fuzm = src1[i] & src1_s[i];
src2_fuzm = src2[i] & src2_s[i];
dst_fuzm = src1_fuzm | src2_fuzm; /* The bits that remain set are fuzzy in either one or
the other or both. */
src1_holm = src1[i] | (src1_s[i] ^ 0xffff);
src2_holm = src2[i] | (src2_s[i] ^ 0xffff);
dst_holm = (src1_holm & src2_holm) ^ 0xffff; /* The bits that remain set are holes in both. */
dst_neim = (dst_fuzm | dst_holm) ^ 0xffff; /* The bits that remain set are those that are neither
fuzzy nor are holes in both. */
src1_d = src1[i] & dst_neim;
src2_d = src2[i] & dst_neim;
dst_s[i] = (dst_neim ^ 0xffff); /* The set bits are those that are either fuzzy or are
holes in both. */
dst[i] = (src1_d | src2_d); /* Initial data is remaining data from Source 1 and
Source 2. */
dst[i] |= dst_fuzm; /* Add to it the fuzzy bytes (holes have surface bit set
but data bit clear). */
}
else
{
/* No surface data, the handling is much simpler - a simple OR. */
dst[i] = src1[i] | src2[i];
dst_s[i] = 0;
}
}
}
/* Decomposition is easier since we at most have to care about the holes. */
void d86f_decompose_encoded_buffer(int drive, int side)
{
int i = 0;
uint16_t temp, temp2;
uint32_t len;
uint16_t *dst = d86f[drive].track_encoded_data[side];
uint16_t *dst_s = d86f[drive].track_surface_data[side];
uint16_t *src1 = d86f[drive].thin_track_encoded_data[0][side];
uint16_t *src1_s = d86f[drive].thin_track_surface_data[0][side];
uint16_t *src2 = d86f[drive].thin_track_encoded_data[1][side];
uint16_t *src2_s = d86f[drive].thin_track_surface_data[1][side];
len = d86f_get_array_size(drive, side);
for (i = 0; i < len; i++)
{
if (d86f_has_surface_desc(drive))
{
/* Source image has surface description data, so we have some more handling to do.
We need hole masks for both buffers. Holes have data bit clear and surface bit set. */
temp = src1[i] & (src1_s[i] ^ 0xffff);
temp2 = src2[i] & (src2_s[i] ^ 0xffff);
src1[i] = dst[i] & temp;
src1_s[i] = temp ^ 0xffff;
src2[i] = dst[i] & temp2;
src2_s[i] = temp2 ^ 0xffff;
}
else
{
src1[i] = src2[i] = dst[i];
}
}
}
int d86f_track_header_size(int drive)
{
int temp = 6;
if (d86f_has_extra_bit_cells(drive))
{
temp += 4;
}
return temp;
}
void d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, uint16_t *sa)
{
int logical_track = 0;
int array_size = 0;
if (d86f_get_sides(drive) == 2)
{
logical_track = ((track + thin_track) << 1) + side;
}
else
{
logical_track = track + thin_track;
}
if (d86f[drive].track_offset[logical_track])
{
if (!thin_track)
{
fseek(d86f[drive].f, d86f[drive].track_offset[logical_track], SEEK_SET);
fread(&(d86f[drive].side_flags[side]), 2, 1, d86f[drive].f);
if (d86f_has_extra_bit_cells(drive))
{
fread(&(d86f[drive].extra_bit_cells[side]), 4, 1, d86f[drive].f);
if (d86f[drive].extra_bit_cells[side] < -32768)
{
d86f[drive].extra_bit_cells[side] = -32768;
}
if (d86f[drive].extra_bit_cells[side] > 32768)
{
d86f[drive].extra_bit_cells[side] = 32768;
}
}
else
{
d86f[drive].extra_bit_cells[side] = 0;
}
fread(&(d86f[drive].index_hole_pos[side]), 4, 1, d86f[drive].f);
}
else
{
fseek(d86f[drive].f, d86f[drive].track_offset[logical_track] + d86f_track_header_size(drive), SEEK_SET);
}
array_size = d86f_get_array_size(drive, side) << 1;
if (d86f_has_surface_desc(drive))
{
fread(sa, 1, array_size, d86f[drive].f);
}
fread(da, 1, array_size, d86f[drive].f);
}
else
{
if (!thin_track)
{
switch((d86f[drive].disk_flags >> 1) & 3)
{
case 0:
default:
d86f[drive].side_flags[side] = 0x0A;
break;
case 1:
d86f[drive].side_flags[side] = 0x00;
break;
case 2:
case 3:
d86f[drive].side_flags[side] = 0x03;
break;
}
d86f[drive].extra_bit_cells[side] = 0;
}
}
}
void d86f_seek(int drive, int track)
{
uint8_t track_id = track;
int sides;
int side, thin_track;
sides = d86f_get_sides(drive);
/* If the drive has thick tracks, shift the track number by 1. */
if (!fdd_doublestep_40(drive))
{
track <<= 1;
for (thin_track = 0; thin_track < sides; thin_track++)
{
for (side = 0; side < sides; side++)
{
if (d86f_has_surface_desc(drive))
{
memset(d86f[drive].thin_track_surface_data[thin_track][side], 0, 106096);
}
memset(d86f[drive].thin_track_encoded_data[thin_track][side], 0, 106096);
}
}
}
for (side = 0; side < sides; side++)
{
if (d86f_has_surface_desc(drive))
{
memset(d86f[drive].track_surface_data[side], 0, 106096);
}
memset(d86f[drive].track_encoded_data[side], 0, 106096);
}
d86f[drive].cur_track = track;
if (!fdd_doublestep_40(drive))
{
for (side = 0; side < sides; side++)
{
for (thin_track = 0; thin_track < 2; thin_track++)
{
d86f_read_track(drive, track, thin_track, side, d86f[drive].thin_track_encoded_data[thin_track][side], d86f[drive].thin_track_surface_data[thin_track][side]);
}
d86f_construct_encoded_buffer(drive, side);
}
}
else
{
for (side = 0; side < sides; side++)
{
d86f_read_track(drive, track, 0, side, d86f[drive].track_encoded_data[side], d86f[drive].track_surface_data[side]);
}
}
d86f[drive].state = STATE_IDLE;
}
void d86f_write_track(int drive, int side, uint16_t *da0, uint16_t *sa0)
{
// pclog("Pos: %08X\n", ftell(d86f[drive].f));
fwrite(&(d86f[drive].side_flags[side]), 1, 2, d86f[drive].f);
if (d86f_has_extra_bit_cells(drive))
{
fwrite(&(d86f[drive].extra_bit_cells[side]), 1, 4, d86f[drive].f);
}
fwrite(&(d86f[drive].index_hole_pos[side]), 1, 4, d86f[drive].f);
if (d86f_has_surface_desc(drive))
{
fwrite(sa0, 1, d86f_get_array_size(drive, side) << 1, d86f[drive].f);
}
fwrite(da0, 1, d86f_get_array_size(drive, side) << 1, d86f[drive].f);
// pclog("Pos: %08X\n", ftell(d86f[drive].f));
}
int d86f_get_track_table_size(int drive)
{
int temp = 2048;
if (d86f_get_sides(drive) == 1)
{
temp >>= 1;
}
return temp;
}
void d86f_writeback(int drive)
{
uint8_t track_id = d86f[drive].cur_track;
uint8_t header[32];
int sides, header_size;
int side, thin_track;
// uint64_t crc64;
uint32_t len;
int i = 0;
int ret = 0;
int logical_track = 0;
uint8_t tempb;
FILE *cf;
sides = d86f_get_sides(drive);
header_size = d86f_header_size(drive);
if (!d86f[drive].f)
{
return;
}
/* First write the track offsets table. */
fseek(d86f[drive].f, 0, SEEK_SET);
fread(header, 1, header_size, d86f[drive].f);
fseek(d86f[drive].f, 8, SEEK_SET);
// pclog("PosEx: %08X\n", ftell(d86f[drive].f));
fwrite(d86f[drive].track_offset, 1, d86f_get_track_table_size(drive), d86f[drive].f);
// pclog("PosEx: %08X\n", ftell(d86f[drive].f));
if (!fdd_doublestep_40(drive))
{
for (side = 0; side < sides; side++)
{
d86f_decompose_encoded_buffer(drive, side);
for (thin_track = 0; thin_track < 2; thin_track++)
{
if (d86f_get_sides(drive) == 2)
{
logical_track = ((d86f[drive].cur_track + thin_track) << 1) + side;
}
else
{
logical_track = d86f[drive].cur_track + thin_track;
}
if (d86f[drive].track_offset[((d86f[drive].cur_track + thin_track) << 1) + side])
{
fseek(d86f[drive].f, d86f[drive].track_offset[logical_track], SEEK_SET);
d86f_write_track(drive, side, d86f[drive].thin_track_encoded_data[thin_track][side], d86f[drive].thin_track_surface_data[thin_track][side]);
}
}
}
}
else
{
for (side = 0; side < sides; side++)
{
if (d86f_get_sides(drive) == 2)
{
logical_track = (d86f[drive].cur_track << 1) + side;
}
else
{
logical_track = d86f[drive].cur_track;
}
if (d86f[drive].track_offset[(d86f[drive].cur_track << 1) + side])
{
// pclog("Writing track...\n");
fseek(d86f[drive].f, d86f[drive].track_offset[logical_track], SEEK_SET);
d86f_write_track(drive, side, d86f[drive].track_encoded_data[side], d86f[drive].track_surface_data[side]);
}
}
}
// pclog("Position: %08X\n", ftell(d86f[drive].f));
if (d86f[drive].is_compressed)
{
/* The image is compressed. */
/* Open the original, compressed file. */
cf = fopen(d86f[drive].original_file_name, "wb");
/* Write the header to the original file. */
fwrite(header, 1, header_size, cf);
fseek(d86f[drive].f, 0, SEEK_END);
len = ftell(d86f[drive].f);
len -= header_size;
fseek(d86f[drive].f, header_size, SEEK_SET);
/* Compress data from the temporary uncompressed file to the original, compressed file. */
d86f[drive].filebuf = (uint8_t *) malloc(len);
d86f[drive].outbuf = (uint8_t *) malloc(len - 1);
fread(d86f[drive].filebuf, 1, len, d86f[drive].f);
ret = lzf_compress(d86f[drive].filebuf, len, d86f[drive].outbuf, len - 1);
// ret = d86f_zlib(cf, d86f[drive].f, 0);
if (!ret)
{
pclog("86F: Error compressing file\n");
}
fwrite(d86f[drive].outbuf, 1, ret, cf);
free(d86f[drive].outbuf);
free(d86f[drive].filebuf);
#ifdef DO_CRC64
len = ftell(cf);
fclose(cf);
cf = fopen(d86f[drive].original_file_name, "rb+");
crc64 = 0xffffffffffffffff;
fseek(cf, 8, SEEK_SET);
fwrite(&crc64, 1, 8, cf);
fseek(cf, 0, SEEK_SET);
d86f[drive].filebuf = (uint8_t *) malloc(len);
fread(d86f[drive].filebuf, 1, len, cf);
*(uint64_t *) &(d86f[drive].filebuf[8]) = 0xffffffffffffffff;
crc64 = (uint64_t) crc64speed(0, d86f[drive].filebuf, len);
free(d86f[drive].filebuf);
fseek(cf, 8, SEEK_SET);
fwrite(&crc64, 1, 8, cf);
/* Close the original file. */
fclose(cf);
#endif
}
#ifdef DO_CRC64
else
{
fseek(d86f[drive].f, 0, SEEK_END);
len = ftell(d86f[drive].f);
fseek(d86f[drive].f, 0, SEEK_SET);
crc64 = 0xffffffffffffffff;
fseek(d86f[drive].f, 8, SEEK_SET);
fwrite(&crc64, 1, 8, d86f[drive].f);
fseek(d86f[drive].f, 0, SEEK_SET);
d86f[drive].filebuf = (uint8_t *) malloc(len);
fread(d86f[drive].filebuf, 1, len, d86f[drive].f);
*(uint64_t *) &(d86f[drive].filebuf[8]) = 0xffffffffffffffff;
crc64 = (uint64_t) crc64speed(0, d86f[drive].filebuf, len);
free(d86f[drive].filebuf);
fseek(d86f[drive].f, 8, SEEK_SET);
fwrite(&crc64, 1, 8, d86f[drive].f);
}
#endif
// pclog("d86f_writeback(): %08X\n", d86f[drive].track_offset[track]);
}
void d86f_stop(int drive)
{
d86f[drive].state = STATE_IDLE;
}
int d86f_common_command(int drive, int sector, int track, int side, int rate, int sector_size)
{
// pclog("d86f_common_command: fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), rate, sector, track, side);
d86f[drive].req_sector.id.c = track;
d86f[drive].req_sector.id.h = side;
d86f[drive].req_sector.id.r = sector;
d86f[drive].req_sector.id.n = sector_size;
if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1))
{
fdc_notfound();
d86f[drive].state = STATE_IDLE;
d86f[drive].index_count = 0;
return 0;
}
d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = 0;
d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0;
d86f[drive].index_count = d86f[drive].error_condition = d86f[drive].satisfying_bytes = 0;
return 1;
}
void d86f_readsector(int drive, int sector, int track, int side, int rate, int sector_size)
{
int ret = 0;
ret = d86f_common_command(drive, sector, track, side, rate, sector_size);
if (!ret) return;
if (sector == SECTOR_FIRST)
d86f[drive].state = STATE_02_SPIN_TO_INDEX;
else if (sector == SECTOR_NEXT)
d86f[drive].state = STATE_02_FIND_ID;
else
d86f[drive].state = fdc_is_deleted() ? STATE_0C_FIND_ID : (fdc_is_verify() ? STATE_16_FIND_ID : STATE_06_FIND_ID);
}
void d86f_writesector(int drive, int sector, int track, int side, int rate, int sector_size)
{
int ret = 0;
if (writeprot[drive])
{
fdc_writeprotect();
d86f[drive].state = STATE_IDLE;
d86f[drive].index_count = 0;
return;
}
ret = d86f_common_command(drive, sector, track, side, rate, sector_size);
if (!ret) return;
d86f[drive].state = fdc_is_deleted() ? STATE_09_FIND_ID : STATE_05_FIND_ID;
}
void d86f_comparesector(int drive, int sector, int track, int side, int rate, int sector_size)
{
int ret = 0;
ret = d86f_common_command(drive, sector, track, side, rate, sector_size);
if (!ret) return;
d86f[drive].state = STATE_11_FIND_ID;
}
void d86f_readaddress(int drive, int track, int side, int rate)
{
if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1))
{
pclog("Trying to access the second side of a single-sided disk\n");
fdc_notfound();
d86f[drive].state = STATE_IDLE;
d86f[drive].index_count = 0;
return;
}
d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = 0;
d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0;
d86f[drive].index_count = d86f[drive].error_condition = d86f[drive].satisfying_bytes = 0;
d86f[drive].state = STATE_0A_FIND_ID;
}
void d86f_add_track(int drive, int track, int side)
{
uint32_t array_size;
int logical_track = 0;
array_size = d86f_get_array_size(drive, side);
array_size <<= 1;
if (d86f_get_sides(drive) == 2)
{
logical_track = (track << 1) + side;
}
else
{
if (side)
{
return;
}
logical_track = track;
}
if (!d86f[drive].track_offset[logical_track])
{
/* Track is absent from the file, let's add it. */
d86f[drive].track_offset[logical_track] = d86f[drive].file_size;
d86f[drive].file_size += (array_size + 6);
if (d86f_has_extra_bit_cells(drive))
{
d86f[drive].file_size += 4;
}
if (d86f_has_surface_desc(drive))
{
d86f[drive].file_size += array_size;
}
}
}
void d86f_common_format(int drive, int track, int side, int rate, uint8_t fill, int proxy)
{
int i = 0;
uint16_t temp, temp2;
uint32_t array_size;
if (writeprot[drive])
{
fdc_writeprotect();
d86f[drive].state = STATE_IDLE;
d86f[drive].index_count = 0;
return;
}
if ((side && (d86f_get_sides(drive) == 1)) || !(d86f_can_format(drive)))
{
fdc_notfound();
d86f[drive].state = STATE_IDLE;
d86f[drive].index_count = 0;
return;
}
if (!proxy)
{
d86f_reset_index_hole_pos(drive, side);
if (d86f[drive].cur_track > 256)
{
// pclog("Track above 256\n");
fdc_writeprotect();
d86f[drive].state = STATE_IDLE;
d86f[drive].index_count = 0;
return;
}
array_size = d86f_get_array_size(drive, side);
if (d86f_has_surface_desc(drive))
{
/* Preserve the physical holes but get rid of the fuzzy bytes. */
for (i = 0; i < array_size; i++)
{
temp = d86f[drive].track_encoded_data[side][i] ^ 0xffff;
temp2 = d86f[drive].track_surface_data[side][i];
temp &= temp2;
d86f[drive].track_surface_data[side][i] = temp;
}
}
/* Zero the data buffer. */
memset(d86f[drive].track_encoded_data[side], 0, array_size << 1);
d86f_add_track(drive, d86f[drive].cur_track, side);
if (!fdd_doublestep_40(drive))
{
d86f_add_track(drive, d86f[drive].cur_track + 1, side);
}
}
// pclog("Formatting track %i side %i\n", track, side);
d86f[drive].fill = fill;
if (!proxy)
{
// d86f[drive].side_flags[side] &= 0xc0;
d86f[drive].side_flags[side] = 0;
d86f[drive].side_flags[side] |= (fdd_getrpm(drive ^ fdd_swap) == 360) ? 0x20 : 0;
d86f[drive].side_flags[side] |= fdc_get_bit_rate();
d86f[drive].side_flags[side] |= fdc_is_mfm() ? 8 : 0;
d86f[drive].index_hole_pos[side] = 0;
}
d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = 0;
d86f[drive].data_find.sync_marks = d86f[drive].data_find.bits_obtained = d86f[drive].data_find.bytes_obtained = 0;
d86f[drive].index_count = d86f[drive].error_condition = d86f[drive].satisfying_bytes = d86f[drive].sector_count = 0;
d86f[drive].state = STATE_0D_SPIN_TO_INDEX;
}
void d86f_proxy_format(int drive, int track, int side, int rate, uint8_t fill)
{
d86f_common_format(drive, track, side, rate, fill, 1);
}
void d86f_format(int drive, int track, int side, int rate, uint8_t fill)
{
d86f_common_format(drive, track, side, rate, fill, 0);
}
void d86f_common_handlers(int drive)
{
drives[drive].readsector = d86f_readsector;
drives[drive].writesector = d86f_writesector;
drives[drive].comparesector=d86f_comparesector;
drives[drive].readaddress = d86f_readaddress;
drives[drive].hole = d86f_hole;
drives[drive].byteperiod = d86f_byteperiod;
drives[drive].poll = d86f_poll;
drives[drive].format = d86f_proxy_format;
drives[drive].stop = d86f_stop;
}
void d86f_load(int drive, char *fn)
{
uint32_t magic = 0;
uint32_t len = 0;
uint32_t len2 = 0;
uint8_t temp_file_name[2048];
uint16_t temp = 0;
uint8_t tempb = 0;
// uint64_t crc64 = 0;
// uint64_t read_crc64 = 0;
int i = 0;
FILE *tf;
d86f_unregister(drive);
writeprot[drive] = 0;
d86f[drive].f = fopen(fn, "rb+");
if (!d86f[drive].f)
{
d86f[drive].f = fopen(fn, "rb");
if (!d86f[drive].f)
return;
writeprot[drive] = 1;
}
if (ui_writeprot[drive])
{
writeprot[drive] = 1;
}
fwriteprot[drive] = writeprot[drive];
fseek(d86f[drive].f, 0, SEEK_END);
len = ftell(d86f[drive].f);
fseek(d86f[drive].f, 0, SEEK_SET);
fread(&magic, 4, 1, d86f[drive].f);
if (len < 16)
{
/* File is WAY too small, abort. */
fclose(d86f[drive].f);
return;
}
if ((magic != 0x46423638) && (magic != 0x66623638))
{
/* File is not of the valid format, abort. */
pclog("86F: Unrecognized magic bytes: %08X\n", magic);
fclose(d86f[drive].f);
return;
}
fread(&(d86f[drive].version), 2, 1, d86f[drive].f);
if (d86f[drive].version != D86FVER)
{
/* File is not of a recognized format version, abort. */
if (d86f[drive].version == 0x0063)
{
pclog("86F: File has emulator-internal version 0.99, this version is not valid in a file\n");
}
else if ((d86f[drive].version >= 0x0100) && (d86f[drive].version < D86FVER))
{
pclog("86F: No longer supported development file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF);
}
else
{
pclog("86F: Unrecognized file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF);
}
fclose(d86f[drive].f);
return;
}
else
{
pclog("86F: Recognized file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF);
}
fread(&(d86f[drive].disk_flags), 2, 1, d86f[drive].f);
d86f[drive].is_compressed = (magic == 0x66623638) ? 1 : 0;
if ((len < 51052) && !d86f[drive].is_compressed)
{
/* File too small, abort. */
fclose(d86f[drive].f);
return;
}
#ifdef DO_CRC64
fseek(d86f[drive].f, 8, SEEK_SET);
fread(&read_crc64, 1, 8, d86f[drive].f);
fseek(d86f[drive].f, 0, SEEK_SET);
crc64 = 0xffffffffffffffff;
d86f[drive].filebuf = malloc(len);
fread(d86f[drive].filebuf, 1, len, d86f[drive].f);
*(uint64_t *) &(d86f[drive].filebuf[8]) = 0xffffffffffffffff;
crc64 = (uint64_t) crc64speed(0, d86f[drive].filebuf, len);
free(d86f[drive].filebuf);
if (crc64 != read_crc64)
{
pclog("86F: CRC64 error\n");
fclose(d86f[drive].f);
return;
}
#endif
if (d86f[drive].is_compressed)
{
append_filename(temp_file_name, pcempath, drive ? "TEMP$$$1.$$$" : "TEMP$$$0.$$$", 511);
memcpy(temp_file_name, drive ? "TEMP$$$1.$$$" : "TEMP$$$0.$$$", 13);
memcpy(d86f[drive].original_file_name, fn, strlen(fn) + 1);
fclose(d86f[drive].f);
d86f[drive].f = fopen(temp_file_name, "wb");
if (!d86f[drive].f)
{
pclog("86F: Unable to create temporary decompressed file\n");
return;
}
tf = fopen(fn, "rb");
for (i = 0; i < 8; i++)
{
fread(&temp, 1, 2, tf);
fwrite(&temp, 1, 2, d86f[drive].f);
}
// temp = d86f_zlib(d86f[drive].f, tf, 1);
d86f[drive].filebuf = (uint8_t *) malloc(len);
d86f[drive].outbuf = (uint8_t *) malloc(67108864);
fread(d86f[drive].filebuf, 1, len, tf);
temp = lzf_decompress(d86f[drive].filebuf, len, d86f[drive].outbuf, 67108864);
if (temp)
{
fwrite(d86f[drive].outbuf, 1, temp, d86f[drive].f);
}
free(d86f[drive].outbuf);
free(d86f[drive].filebuf);
fclose(tf);
fclose(d86f[drive].f);
if (!temp)
{
pclog("86F: Error decompressing file\n");
remove(temp_file_name);
return;
}
d86f[drive].f = fopen(temp_file_name, "rb+");
}
if (d86f[drive].disk_flags & 0x100)
{
/* Zoned disk. */
pclog("86F: Disk is zoned (Apple or Sony)\n");
fclose(d86f[drive].f);
if (d86f[drive].is_compressed)
{
remove(temp_file_name);
}
return;
}
if (d86f[drive].disk_flags & 0x600)
{
/* Zone type is not 0 but the disk is fixed-RPM. */
pclog("86F: Disk is fixed-RPM but zone type is not 0\n");
fclose(d86f[drive].f);
if (d86f[drive].is_compressed)
{
remove(temp_file_name);
}
return;
}
if (!writeprot[drive])
{
writeprot[drive] = (d86f[drive].disk_flags & 0x10) ? 1 : 0;
fwriteprot[drive] = writeprot[drive];
}
if (writeprot[drive])
{
fclose(d86f[drive].f);
if (d86f[drive].is_compressed)
{
d86f[drive].f = fopen(temp_file_name, "rb");
}
else
{
d86f[drive].f = fopen(fn, "rb");
}
}
fseek(d86f[drive].f, 8, SEEK_SET);
fread(d86f[drive].track_offset, 1, d86f_get_track_table_size(drive), d86f[drive].f);
if (!(d86f[drive].track_offset[0]))
{
/* File has no track 0 side 0, abort. */
pclog("86F: No Track 0 side 0\n");
fclose(d86f[drive].f);
return;
}
if ((d86f_get_sides(drive) == 2) && !(d86f[drive].track_offset[1]))
{
/* File is 2-sided but has no track 0 side 1, abort. */
pclog("86F: No Track 0 side 0\n");
fclose(d86f[drive].f);
return;
}
/* Load track 0 flags as default. */
fseek(d86f[drive].f, d86f[drive].track_offset[0], SEEK_SET);
fread(&(d86f[drive].side_flags[0]), 2, 1, d86f[drive].f);
if (d86f[drive].disk_flags & 0x80)
{
fread(&(d86f[drive].extra_bit_cells[0]), 4, 1, d86f[drive].f);
if (d86f[drive].extra_bit_cells[0] < -32768) d86f[drive].extra_bit_cells[0] = -32768;
if (d86f[drive].extra_bit_cells[0] > 32768) d86f[drive].extra_bit_cells[0] = 32768;
}
else
{
d86f[drive].extra_bit_cells[0] = 0;
}
if (d86f_get_sides(drive) == 2)
{
fseek(d86f[drive].f, d86f[drive].track_offset[1], SEEK_SET);
fread(&(d86f[drive].side_flags[1]), 2, 1, d86f[drive].f);
if (d86f[drive].disk_flags & 0x80)
{
fread(&(d86f[drive].extra_bit_cells[1]), 4, 1, d86f[drive].f);
if (d86f[drive].extra_bit_cells[1] < -32768) d86f[drive].extra_bit_cells[1] = -32768;
if (d86f[drive].extra_bit_cells[1] > 32768) d86f[drive].extra_bit_cells[1] = 32768;
}
else
{
d86f[drive].extra_bit_cells[0] = 0;
}
}
else
{
switch ((d86f[drive].disk_flags >> 1) >> 3)
{
case 0:
default:
d86f[drive].side_flags[1] = 0x0A;
break;
case 1:
d86f[drive].side_flags[1] = 0x00;
break;
case 2:
case 3:
d86f[drive].side_flags[1] = 0x03;
break;
}
d86f[drive].extra_bit_cells[1] = 0;
}
fseek(d86f[drive].f, 0, SEEK_END);
d86f[drive].file_size = ftell(d86f[drive].f);
fseek(d86f[drive].f, 0, SEEK_SET);
d86f_register_86f(drive);
drives[drive].seek = d86f_seek;
d86f_common_handlers(drive);
drives[drive].format = d86f_format;
pclog("86F: Disk is %scompressed and %s surface description data\n", d86f[drive].is_compressed ? "" : "not ", d86f_has_surface_desc(drive) ? "has" : "does not have");
}
void d86f_init()
{
disc_random_init();
memset(d86f, 0, sizeof(d86f));
d86f_setupcrc(0x1021);
// crc64speed_init();
d86f[0].state = d86f[1].state = STATE_IDLE;
}
void d86f_close(int drive)
{
uint8_t temp_file_name[2048];
append_filename(temp_file_name, pcempath, drive ? "TEMP$$$1.$$$" : "TEMP$$$0.$$$", 511);
memcpy(temp_file_name, drive ? "TEMP$$$1.$$$" : "TEMP$$$0.$$$", 13);
if (d86f[drive].f)
fclose(d86f[drive].f);
if (d86f[drive].is_compressed)
remove(temp_file_name);
d86f[drive].f = NULL;
}