Floppy fixes to handle TD0 and IMD images with some kinds of copy protection, fixes eg. F-19 Stealth Fighter from 1988.

This commit is contained in:
OBattler
2019-12-05 21:36:28 +01:00
parent b6adaff6fd
commit b9a35eb418
20 changed files with 471 additions and 648 deletions

View File

@@ -1,40 +1,22 @@
/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the VARCem Project.
* This file is part of the 86Box distribution.
*
* Implementation of the 86F floppy image format (stores the
* data in the form of FM/MFM-encoded transitions) which also
* forms the core of the emulator's floppy disk emulation.
*
* Version: @(#)fdd_86f.c 1.0.18 2019/11/08
* Version: @(#)fdd_86f.c 1.0.19 2019/12/05
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2016-2019 Miran Grca.
* Copyright 2018,2019 Fred N. van Kempen.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
*/
#include <stdint.h>
#include <stdio.h>
@@ -174,6 +156,7 @@ typedef union {
typedef struct {
uint8_t c, h, r, n;
uint8_t flags, pad, pad0, pad1;
void *prev;
} sector_t;
@@ -1601,14 +1584,17 @@ d86f_read_sector_data(int drive, int side)
/* We've got a byte. */
d86f_log("86F: We've got a byte.\n");
if (dev->data_find.bytes_obtained < sector_len) {
if (d86f_handler[drive].read_data != NULL)
data = d86f_handler[drive].read_data(drive, side, dev->data_find.bytes_obtained);
else {
#ifdef HACK_FOR_DBASE_III
if ((dev->last_sector.id.c == 39) && (dev->last_sector.id.h == 0) &&
(dev->last_sector.id.r == 5) && (dev->data_find.bytes_obtained >= 272)) {
pclog("Randomly generating sector 39,0,5 byte %i...\n", dev->data_find.bytes_obtained);
data = (random_generate() & 0xff);
} else
if ((dev->last_sector.id.c == 39) && (dev->last_sector.id.h == 0) &&
(dev->last_sector.id.r == 5) && (dev->data_find.bytes_obtained >= 272))
data = (random_generate() & 0xff);
else
#endif
data = decodefm(drive, dev->last_word[side]);
data = decodefm(drive, dev->last_word[side]);
}
if (dev->state == STATE_11_SCAN_DATA) {
/* Scan/compare command. */
recv_data = d86f_get_data(drive, 0);
@@ -1643,7 +1629,7 @@ d86f_read_sector_data(int drive, int side)
fdc_track_finishread(d86f_fdc, dev->error_condition);
} else {
/* CRC is valid. */
d86f_log("86F: Data CRC OK: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword);
d86f_log("86F: Data CRC OK: %04X == %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword);
dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0;
dev->error_condition = 0;
dev->state = STATE_IDLE;
@@ -2149,6 +2135,28 @@ d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n)
}
static uint8_t
d86f_sector_flags(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n)
{
d86f_t *dev = d86f[drive];
sector_t *s, *t;
if (dev->last_side_sector[side]) {
s = dev->last_side_sector[side];
while (s) {
if ((s->c == c) && (s->h == h) && (s->r == r) && (s->n == n))
return s->flags;
if (! s->prev)
break;
t = s->prev;
s = t;
}
}
return 0x00;
}
void
d86f_turbo_read(int drive, int side)
{
@@ -2156,8 +2164,12 @@ d86f_turbo_read(int drive, int side)
uint8_t dat = 0;
int recv_data = 0;
int read_status = 0;
uint8_t flags = d86f_sector_flags(drive, side, dev->req_sector.id.c, dev->req_sector.id.h, dev->req_sector.id.r, dev->req_sector.id.n);
dat = d86f_handler[drive].read_data(drive, side, dev->turbo_pos);
if (d86f_handler[drive].read_data != NULL)
dat = d86f_handler[drive].read_data(drive, side, dev->turbo_pos);
else
dat = (random_generate() & 0xff);
dev->turbo_pos++;
if (dev->state == STATE_11_SCAN_DATA) {
@@ -2175,15 +2187,30 @@ d86f_turbo_read(int drive, int side)
}
if (dev->turbo_pos >= (128 << dev->last_sector.id.n)) {
/* CRC is valid. */
dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0;
dev->error_condition = 0;
if (dev->state == STATE_11_SCAN_DATA) {
if ((flags & SECTOR_CRC_ERROR) && (dev->state != STATE_02_READ_DATA)) {
#ifdef ENABLE_D86F_LOG
d86f_log("86F: Data CRC error in turbo mode\n");
#endif
dev->error_condition = 0;
dev->state = STATE_IDLE;
fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0);
fdc_finishread(d86f_fdc);
fdc_datacrcerror(d86f_fdc);
} else if ((dev->calc_crc.word != dev->track_crc.word) && (dev->state == STATE_02_READ_DATA)) {
dev->error_condition |= 2; /* Mark that there was a data error. */
dev->state = STATE_IDLE;
fdc_track_finishread(d86f_fdc, dev->error_condition);
} else {
/* CRC is valid. */
#ifdef ENABLE_D86F_LOG
d86f_log("86F: Data CRC OK error in turbo mode\n");
#endif
dev->error_condition = 0;
dev->state = STATE_IDLE;
fdc_sector_finishread(d86f_fdc);
if (dev->state == STATE_11_SCAN_DATA)
fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0);
else
fdc_sector_finishread(d86f_fdc);
}
}
}
@@ -2307,11 +2334,8 @@ d86f_turbo_poll(int drive, int side)
return;
case STATE_02_FIND_ID:
if (! d86f_sector_is_present(drive, side,
fdc_get_read_track_sector(d86f_fdc).id.c,
fdc_get_read_track_sector(d86f_fdc).id.h,
fdc_get_read_track_sector(d86f_fdc).id.r,
fdc_get_read_track_sector(d86f_fdc).id.n)) {
if (! d86f_sector_is_present(drive, side, fdc_get_read_track_sector(d86f_fdc).id.c, fdc_get_read_track_sector(d86f_fdc).id.h,
fdc_get_read_track_sector(d86f_fdc).id.r, fdc_get_read_track_sector(d86f_fdc).id.n)) {
dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0;
fdc_nosector(d86f_fdc);
dev->state = STATE_IDLE;
@@ -2332,15 +2356,16 @@ d86f_turbo_poll(int drive, int side)
case STATE_0C_FIND_ID:
case STATE_11_FIND_ID:
case STATE_16_FIND_ID:
if (! d86f_sector_is_present(drive, side,
dev->req_sector.id.c,
dev->req_sector.id.h,
dev->req_sector.id.r,
dev->req_sector.id.n)) {
if (! d86f_sector_is_present(drive, side, dev->req_sector.id.c, dev->req_sector.id.h, dev->req_sector.id.r, dev->req_sector.id.n)) {
dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0;
fdc_nosector(d86f_fdc);
dev->state = STATE_IDLE;
return;
} else if (d86f_sector_flags(drive, side, dev->req_sector.id.c, dev->req_sector.id.h, dev->req_sector.id.r, dev->req_sector.id.n) & SECTOR_NO_ID) {
dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0;
fdc_noidam(d86f_fdc);
dev->state = STATE_IDLE;
return;
}
dev->last_sector.id.c = dev->req_sector.id.c;
dev->last_sector.id.h = dev->req_sector.id.h;
@@ -2567,7 +2592,6 @@ d86f_poll(int drive)
case STATE_05_FIND_DATA:
case STATE_09_FIND_DATA:
case STATE_0C_FIND_DATA:
dev->state = STATE_IDLE;
fdc_nodataam(d86f_fdc);
break;
@@ -2597,9 +2621,8 @@ d86f_poll(int drive)
fdc_nosector(d86f_fdc);
} else
fdc_nosector(d86f_fdc);
} else {
} else
fdc_noidam(d86f_fdc);
}
break;
}
}
@@ -2679,7 +2702,7 @@ d86f_prepare_pretrack(int drive, int side, int iso)
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)
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 flags)
{
d86f_t *dev = d86f[drive];
uint16_t pos;
@@ -2706,6 +2729,7 @@ d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t
s->h = id_buf[1];
s->r = id_buf[2];
s->n = id_buf[3];
s->flags = flags;
if (dev->last_side_sector[side])
s->prev = dev->last_side_sector[side];
dev->last_side_sector[side] = s;
@@ -2724,63 +2748,71 @@ d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t
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;
}
dev->calc_crc.word = 0xffff;
if (mfm) {
for (i = 0; i < 3; i++) {
d86f_write_direct_common(drive, side, 0x8944, 1, pos);
if (!(flags & SECTOR_NO_ID)) {
for (i = 0; i < sync_len; i++) {
d86f_write_direct_common(drive, side, 0, 0, pos);
pos = (pos + 1) % raw_size;
}
dev->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(dev, 0xA1);
}
}
d86f_write_direct_common(drive, side, mfm ? idam_mfm : idam_fm, 1, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(dev, 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(dev, id_buf[i]);
}
for (i = 1; i >= 0; i--) {
d86f_write_direct_common(drive, side, dev->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;
d86f_calccrc(dev, 0xA1);
}
}
d86f_write_direct_common(drive, side, mfm ? idam_mfm : idam_fm, 1, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(dev, 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(dev, id_buf[i]);
}
for (i = 1; i >= 0; i--) {
d86f_write_direct_common(drive, side, dev->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;
}
dev->calc_crc.word = 0xffff;
if (mfm) {
for (i = 0; i < 3; i++) {
d86f_write_direct_common(drive, side, 0x8944, 1, pos);
if (!(flags & SECTOR_NO_DATA)) {
for (i = 0; i < sync_len; i++) {
d86f_write_direct_common(drive, side, 0, 0, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(dev, 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(dev, 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(dev, data_buf[i]);
}
if (bad_crc)
dev->calc_crc.word ^= 0xffff;
for (i = 1; i >= 0; i--) {
d86f_write_direct_common(drive, side, dev->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);
dev->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(dev, 0xA1);
}
}
d86f_write_direct_common(drive, side, mfm ? ((flags & SECTOR_DELETED_DATA) ? datadam_mfm : dataam_mfm) : ((flags & SECTOR_DELETED_DATA) ? datadam_fm : dataam_fm), 1, pos);
pos = (pos + 1) % raw_size;
d86f_calccrc(dev, (flags & SECTOR_DELETED_DATA) ? 0xF8 : 0xFB);
if (data_len > 0) {
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(dev, data_buf[i]);
}
if (!(flags & SECTOR_CRC_ERROR)) {
for (i = 1; i >= 0; i--) {
d86f_write_direct_common(drive, side, dev->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;
@@ -2798,9 +2830,9 @@ d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t
* - 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,
* - One is regular and one is a physical hole -> Output is fuzzy,
* the hole half is handled appropriately on writeback;
* - One is fuzzy and one is a physical hole -> Output is puzzy,
* - One is fuzzy and one is a physical hole -> Output is fuzzy,
* the hole half is handled appropriately on writeback;
* - On write back, apart from the above notes, the final two tracks
* are written;
@@ -3199,13 +3231,12 @@ d86f_common_command(int drive, int sector, int track, int side, int rate, int se
dev->req_sector.id.c = track;
dev->req_sector.id.h = side;
if (sector == SECTOR_FIRST) {
if (sector == SECTOR_FIRST)
dev->req_sector.id.r = 1;
} else if (sector == SECTOR_NEXT) {
else if (sector == SECTOR_NEXT)
dev->req_sector.id.r++;
} else {
else
dev->req_sector.id.r = sector;
}
dev->req_sector.id.n = sector_size;
if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) {
@@ -3926,4 +3957,6 @@ d86f_destroy(int drive)
free(d86f[drive]);
d86f[drive] = NULL;
d86f_handler[drive].read_data = NULL;
}