mirror of
https://github.com/Oibaf66/uae-wii.git
synced 2025-02-19 20:12:43 +01:00
2196 lines
56 KiB
C
2196 lines
56 KiB
C
/*
|
|
|
|
FDI to raw bit stream converter
|
|
Copyright (c) 2001 by Toni Wilen <twilen@arabuusimiehet.com>
|
|
FDI 2.0 support
|
|
Copyright (c) 2003-2004 by Toni Wilen <twilen@arabuusimiehet.com>
|
|
and Vincent Joguin
|
|
|
|
FDI format created by Vincent "ApH" Joguin
|
|
|
|
Tiny changes - function type fixes, multiple drives, addition of
|
|
get_last_head and C++ callability - by Thomas Harte, 2001,
|
|
T.Harte@excite.co.uk
|
|
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
#ifdef FDI2RAW
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* IF UAE */
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
#include "zfile.h"
|
|
/* ELSE */
|
|
//#include "types.h"
|
|
|
|
#include "fdi2raw.h"
|
|
|
|
#undef DEBUG
|
|
#define VERBOSE
|
|
#undef VERBOSE
|
|
|
|
#include <assert.h>
|
|
|
|
#ifdef DEBUG
|
|
static const char *datalog (const uae_u8 *src, unsigned int len)
|
|
{
|
|
static char buf[1000];
|
|
static int offset;
|
|
int i = 0, offset2;
|
|
|
|
offset2 = offset;
|
|
buf[offset++]='\'';
|
|
while (len--) {
|
|
sprintf (buf + offset, "%02.2X", src[i]);
|
|
offset += 2;
|
|
i++;
|
|
if (i > 10) break;
|
|
}
|
|
buf[offset++]='\'';
|
|
buf[offset++] = 0;
|
|
if (offset >= 900) offset = 0;
|
|
return buf + offset2;
|
|
}
|
|
#else
|
|
static const char *datalog (const uae_u8 *src, unsigned int len) { return ""; }
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#define debuglog write_log
|
|
#else
|
|
#define debuglog(...) do { ; } while (0)
|
|
#endif
|
|
#ifdef VERBOSE
|
|
#define outlog write_log
|
|
#else
|
|
#define outlog(...) do { ; } while (0)
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
static int fdi_allocated;
|
|
static void fdi_free (void *p)
|
|
{
|
|
int size;
|
|
if (!p)
|
|
return;
|
|
size = ((int*)p)[-1];
|
|
fdi_allocated -= size;
|
|
write_log ("%d freed (%d)\n", size, fdi_allocated);
|
|
free ((int*)p - 1);
|
|
}
|
|
static void *fdi_malloc (int size)
|
|
{
|
|
void *p = xmalloc (size + sizeof (int));
|
|
((int*)p)[0] = size;
|
|
fdi_allocated += size;
|
|
write_log ("%d allocated (%d)\n", size, fdi_allocated);
|
|
return (int*)p + 1;
|
|
}
|
|
#else
|
|
#define fdi_free free
|
|
#define fdi_malloc xmalloc
|
|
#endif
|
|
|
|
#define MAX_SRC_BUFFER 4194304
|
|
#define MAX_DST_BUFFER 40000
|
|
#define MAX_MFM_SYNC_BUFFER 60000
|
|
#define MAX_TIMING_BUFFER 400000
|
|
#define MAX_TRACKS 166
|
|
|
|
struct fdi_cache {
|
|
uae_u32 *avgp, *minp, *maxp;
|
|
uae_u8 *idxp;
|
|
unsigned int avg_free, idx_free, min_free, max_free;
|
|
uae_u32 totalavg, pulses, maxidx, indexoffset;
|
|
unsigned int weakbits;
|
|
int lowlevel;
|
|
};
|
|
|
|
struct fdi {
|
|
uae_u8 *track_src_buffer;
|
|
uae_u8 *track_src;
|
|
int track_src_len;
|
|
uae_u8 *track_dst_buffer;
|
|
uae_u8 *track_dst;
|
|
uae_u16 *track_dst_buffer_timing;
|
|
uae_u8 track_len;
|
|
uae_u8 track_type;
|
|
unsigned int current_track;
|
|
unsigned int last_track;
|
|
unsigned int last_head;
|
|
unsigned int rotation_speed;
|
|
unsigned int bit_rate;
|
|
int disk_type;
|
|
int write_protect;
|
|
int err;
|
|
uae_u8 header[2048];
|
|
unsigned int track_offsets[MAX_TRACKS];
|
|
struct zfile *file;
|
|
int out;
|
|
int mfmsync_offset;
|
|
int *mfmsync_buffer;
|
|
/* sector described only */
|
|
int index_offset;
|
|
int encoding_type;
|
|
/* bit handling */
|
|
int nextdrop;
|
|
struct fdi_cache cache[MAX_TRACKS];
|
|
};
|
|
|
|
#define get_u32(x) ((((x)[0])<<24)|(((x)[1])<<16)|(((x)[2])<<8)|((x)[3]))
|
|
#define get_u24(x) ((((x)[0])<<16)|(((x)[1])<<8)|((x)[2]))
|
|
STATIC_INLINE void put_u32 (uae_u8 *d, uae_u32 v)
|
|
{
|
|
d[0] = v >> 24;
|
|
d[1] = v >> 16;
|
|
d[2] = v >> 8;
|
|
d[3] = v;
|
|
}
|
|
|
|
struct node {
|
|
uae_u16 v;
|
|
struct node *left;
|
|
struct node *right;
|
|
};
|
|
typedef struct node NODE;
|
|
|
|
static uae_u8 temp, temp2;
|
|
|
|
static const uae_u8 *expand_tree (const uae_u8 *stream, NODE *node)
|
|
{
|
|
if (temp & temp2) {
|
|
fdi_free (node->left);
|
|
node->left = 0;
|
|
fdi_free (node->right);
|
|
node->right = 0;
|
|
temp2 >>= 1;
|
|
if (!temp2) {
|
|
temp = *stream++;
|
|
temp2 = 0x80;
|
|
}
|
|
return stream;
|
|
} else {
|
|
const uae_u8 *stream_temp;
|
|
temp2 >>= 1;
|
|
if (!temp2) {
|
|
temp = *stream++;
|
|
temp2 = 0x80;
|
|
}
|
|
node->left = fdi_malloc (sizeof (NODE));
|
|
memset (node->left, 0, sizeof (NODE));
|
|
stream_temp = expand_tree (stream, node->left);
|
|
node->right = fdi_malloc (sizeof (NODE));
|
|
memset (node->right, 0, sizeof (NODE));
|
|
return expand_tree (stream_temp, node->right);
|
|
}
|
|
}
|
|
|
|
static const uae_u8 *values_tree8 (const uae_u8 *stream, NODE *node)
|
|
{
|
|
if (node->left == 0) {
|
|
node->v = *stream++;
|
|
return stream;
|
|
} else {
|
|
const uae_u8 *stream_temp = values_tree8 (stream, node->left);
|
|
return values_tree8 (stream_temp, node->right);
|
|
}
|
|
}
|
|
|
|
static const uae_u8 *values_tree16 (const uae_u8 *stream, NODE *node)
|
|
{
|
|
if (node->left == 0) {
|
|
uae_u16 high_8_bits = (*stream++) << 8;
|
|
node->v = high_8_bits | (*stream++);
|
|
return stream;
|
|
} else {
|
|
const uae_u8 *stream_temp = values_tree16 (stream, node->left);
|
|
return values_tree16 (stream_temp, node->right);
|
|
}
|
|
}
|
|
|
|
static void free_nodes (NODE *node)
|
|
{
|
|
if (node) {
|
|
free_nodes (node->left);
|
|
free_nodes (node->right);
|
|
fdi_free (node);
|
|
}
|
|
}
|
|
|
|
STATIC_INLINE uae_u32 sign_extend16 (uae_u32 v)
|
|
{
|
|
if (v & 0x8000)
|
|
v |= 0xffff0000;
|
|
return v;
|
|
}
|
|
|
|
STATIC_INLINE uae_u32 sign_extend8 (uae_u32 v)
|
|
{
|
|
if (v & 0x80)
|
|
v |= 0xffffff00;
|
|
return v;
|
|
}
|
|
|
|
static void fdi_decode (const uae_u8 *stream, unsigned int size, uae_u8 *out)
|
|
{
|
|
uae_u8 sign_extend, sixteen_bit, sub_stream_shift;
|
|
NODE root;
|
|
NODE *current_node;
|
|
|
|
memset (out, 0, size * 4);
|
|
sub_stream_shift = 1;
|
|
while (sub_stream_shift) {
|
|
unsigned int i;
|
|
|
|
//sub-stream header decode
|
|
sign_extend = *stream++;
|
|
sub_stream_shift = sign_extend & 0x7f;
|
|
sign_extend &= 0x80;
|
|
sixteen_bit = (*stream++) & 0x80;
|
|
|
|
//huffman tree architecture decode
|
|
temp = *stream++;
|
|
temp2 = 0x80;
|
|
stream = expand_tree (stream, &root);
|
|
if (temp2 == 0x80)
|
|
stream--;
|
|
|
|
//huffman output values decode
|
|
if (sixteen_bit)
|
|
stream = values_tree16 (stream, &root);
|
|
else
|
|
stream = values_tree8 (stream, &root);
|
|
|
|
//sub-stream data decode
|
|
temp2 = 0;
|
|
for (i = 0; i < size; i++) {
|
|
uae_u32 v;
|
|
uae_u8 decode = 1;
|
|
current_node = &root;
|
|
while (decode) {
|
|
if (current_node->left == 0) {
|
|
decode = 0;
|
|
} else {
|
|
temp2 >>= 1;
|
|
if (!temp2) {
|
|
temp2 = 0x80;
|
|
temp = *stream++;
|
|
}
|
|
if (temp & temp2)
|
|
current_node = current_node->right;
|
|
else
|
|
current_node = current_node->left;
|
|
}
|
|
}
|
|
v = ((uae_u32*)out)[i];
|
|
if (sign_extend) {
|
|
if (sixteen_bit)
|
|
v |= sign_extend16 (current_node->v) << sub_stream_shift;
|
|
else
|
|
v |= sign_extend8 (current_node->v) << sub_stream_shift;
|
|
} else {
|
|
v |= current_node->v << sub_stream_shift;
|
|
}
|
|
((uae_u32*)out)[i] = v;
|
|
}
|
|
free_nodes (root.left);
|
|
free_nodes (root.right);
|
|
}
|
|
}
|
|
|
|
|
|
static unsigned int decode_raw_track (FDI *fdi)
|
|
{
|
|
unsigned int size = get_u32(fdi->track_src);
|
|
memcpy (fdi->track_dst, fdi->track_src, (size + 7) >> 3);
|
|
fdi->track_src += (size + 7) >> 3;
|
|
return size;
|
|
}
|
|
|
|
/* unknown track */
|
|
static void zxx (FDI *fdi)
|
|
{
|
|
outlog ("track %d: unknown track type 0x%02.2X\n", fdi->current_track, fdi->track_type);
|
|
// return -1;
|
|
}
|
|
/* unsupported track */
|
|
static void zyy (FDI *fdi)
|
|
{
|
|
outlog ("track %d: unsupported track type 0x%02.2X\n", fdi->current_track, fdi->track_type);
|
|
// return -1;
|
|
}
|
|
/* empty track */
|
|
static void track_empty (FDI *fdi)
|
|
{
|
|
// return 0;
|
|
}
|
|
|
|
/* unknown sector described type */
|
|
static void dxx (FDI *fdi)
|
|
{
|
|
outlog ("\ntrack %d: unknown sector described type 0x%02.2X\n", fdi->current_track, fdi->track_type);
|
|
fdi->err = 1;
|
|
}
|
|
/* unsupported sector described type */
|
|
static void dyy (FDI *fdi)
|
|
{
|
|
outlog ("\ntrack %d: unsupported sector described 0x%02.2X\n", fdi->current_track, fdi->track_type);
|
|
fdi->err = 1;
|
|
}
|
|
/* add position of mfm sync bit */
|
|
static void add_mfm_sync_bit (FDI *fdi)
|
|
{
|
|
if (fdi->nextdrop) {
|
|
fdi->nextdrop = 0;
|
|
return;
|
|
}
|
|
fdi->mfmsync_buffer[fdi->mfmsync_offset++] = fdi->out;
|
|
if (fdi->out == 0) {
|
|
outlog ("illegal position for mfm sync bit, offset=%d\n",fdi->out);
|
|
fdi->err = 1;
|
|
}
|
|
if (fdi->mfmsync_offset >= MAX_MFM_SYNC_BUFFER) {
|
|
fdi->mfmsync_offset = 0;
|
|
outlog ("mfmsync buffer overflow\n");
|
|
fdi->err = 1;
|
|
}
|
|
fdi->out++;
|
|
}
|
|
|
|
#define BIT_BYTEOFFSET ((fdi->out) >> 3)
|
|
#define BIT_BITOFFSET (7-((fdi->out)&7))
|
|
|
|
/* add one bit */
|
|
static void bit_add (FDI *fdi, int bit)
|
|
{
|
|
if (fdi->nextdrop) {
|
|
fdi->nextdrop = 0;
|
|
return;
|
|
}
|
|
fdi->track_dst[BIT_BYTEOFFSET] &= ~(1 << BIT_BITOFFSET);
|
|
if (bit)
|
|
fdi->track_dst[BIT_BYTEOFFSET] |= (1 << BIT_BITOFFSET);
|
|
fdi->out++;
|
|
if (fdi->out >= MAX_DST_BUFFER * 8) {
|
|
outlog ("destination buffer overflow\n");
|
|
fdi->err = 1;
|
|
fdi->out = 1;
|
|
}
|
|
}
|
|
/* add bit and mfm sync bit */
|
|
static void bit_mfm_add (FDI *fdi, int bit)
|
|
{
|
|
add_mfm_sync_bit (fdi);
|
|
bit_add (fdi, bit);
|
|
}
|
|
/* remove following bit */
|
|
static void bit_drop_next (FDI *fdi)
|
|
{
|
|
if (fdi->nextdrop > 0) {
|
|
outlog ("multiple bit_drop_next() called");
|
|
} else if (fdi->nextdrop < 0) {
|
|
fdi->nextdrop = 0;
|
|
debuglog (":DNN:");
|
|
return;
|
|
}
|
|
debuglog (":DN:");
|
|
fdi->nextdrop = 1;
|
|
}
|
|
|
|
/* ignore next bit_drop_next() */
|
|
static void bit_dedrop (FDI *fdi)
|
|
{
|
|
if (fdi->nextdrop) {
|
|
outlog ("bit_drop_next called before bit_dedrop");
|
|
}
|
|
fdi->nextdrop = -1;
|
|
debuglog (":BDD:");
|
|
}
|
|
|
|
/* add one byte */
|
|
static void byte_add (FDI *fdi, uae_u8 v)
|
|
{
|
|
int i;
|
|
for (i = 7; i >= 0; i--)
|
|
bit_add (fdi, v & (1 << i));
|
|
}
|
|
/* add one word */
|
|
static void word_add (FDI *fdi, uae_u16 v)
|
|
{
|
|
byte_add (fdi, (uae_u8)(v >> 8));
|
|
byte_add (fdi, (uae_u8)v);
|
|
}
|
|
/* add one byte and mfm encode it */
|
|
static void byte_mfm_add (FDI *fdi, uae_u8 v)
|
|
{
|
|
int i;
|
|
for (i = 7; i >= 0; i--)
|
|
bit_mfm_add (fdi, v & (1 << i));
|
|
}
|
|
/* add multiple bytes and mfm encode them */
|
|
static void bytes_mfm_add (FDI *fdi, uae_u8 v, unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < len; i++) byte_mfm_add (fdi, v);
|
|
}
|
|
/* add one mfm encoded word and re-mfm encode it */
|
|
static void word_post_mfm_add (FDI *fdi, uae_u16 v)
|
|
{
|
|
int i;
|
|
for (i = 14; i >= 0; i -= 2)
|
|
bit_mfm_add (fdi, v & (1 << i));
|
|
}
|
|
|
|
/* bit 0 */
|
|
static void s00(FDI *fdi) { bit_add (fdi, 0); }
|
|
/* bit 1*/
|
|
static void s01(FDI *fdi) { bit_add (fdi, 1); }
|
|
/* 4489 */
|
|
static void s02(FDI *fdi) { word_add (fdi, 0x4489); }
|
|
/* 5224 */
|
|
static void s03(FDI *fdi) { word_add (fdi, 0x5224); }
|
|
/* mfm sync bit */
|
|
static void s04(FDI *fdi) { add_mfm_sync_bit (fdi); }
|
|
/* RLE MFM-encoded data */
|
|
static void s08(FDI *fdi)
|
|
{
|
|
unsigned int bytes = *fdi->track_src++;
|
|
uae_u8 byte = *fdi->track_src++;
|
|
if (bytes == 0) bytes = 256;
|
|
debuglog ("s08:len=%d,data=%02.2X",bytes,byte);
|
|
while(bytes--) byte_add (fdi, byte);
|
|
}
|
|
/* RLE MFM-decoded data */
|
|
static void s09(FDI *fdi)
|
|
{
|
|
unsigned int bytes = *fdi->track_src++;
|
|
uae_u8 byte = *fdi->track_src++;
|
|
if (bytes == 0) bytes = 256;
|
|
bit_drop_next (fdi);
|
|
debuglog ("s09:len=%d,data=%02.2X",bytes,byte);
|
|
while(bytes--) byte_mfm_add (fdi, byte);
|
|
}
|
|
/* MFM-encoded data */
|
|
static void s0a(FDI *fdi)
|
|
{
|
|
int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1];
|
|
uae_u8 b;
|
|
fdi->track_src += 2;
|
|
debuglog ("s0a:bits=%d,data=%s", bits, datalog (fdi->track_src, (bits + 7) / 8));
|
|
while (bits >= 8) {
|
|
byte_add (fdi, *fdi->track_src++);
|
|
bits -= 8;
|
|
}
|
|
if (bits > 0) {
|
|
i = 7;
|
|
b = *fdi->track_src++;
|
|
while (bits--) {
|
|
bit_add (fdi, b & (1 << i));
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
/* MFM-encoded data */
|
|
static void s0b(FDI *fdi)
|
|
{
|
|
int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536;
|
|
uae_u8 b;
|
|
fdi->track_src += 2;
|
|
debuglog ("s0b:bits=%d,data=%s", bits, datalog (fdi->track_src, (bits + 7) / 8));
|
|
while (bits >= 8) {
|
|
byte_add (fdi, *fdi->track_src++);
|
|
bits -= 8;
|
|
}
|
|
if (bits > 0) {
|
|
i = 7;
|
|
b = *fdi->track_src++;
|
|
while (bits--) {
|
|
bit_add (fdi, b & (1 << i));
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
/* MFM-decoded data */
|
|
static void s0c(FDI *fdi)
|
|
{
|
|
int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1];
|
|
uae_u8 b;
|
|
fdi->track_src += 2;
|
|
bit_drop_next (fdi);
|
|
debuglog ("s0c:bits=%d,data=%s", bits, datalog (fdi->track_src, (bits + 7) / 8));
|
|
while (bits >= 8) {
|
|
byte_mfm_add (fdi, *fdi->track_src++);
|
|
bits -= 8;
|
|
}
|
|
if (bits > 0) {
|
|
i = 7;
|
|
b = *fdi->track_src++;
|
|
while(bits--) {
|
|
bit_mfm_add (fdi, b & (1 << i));
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
/* MFM-decoded data */
|
|
static void s0d(FDI *fdi)
|
|
{
|
|
int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536;
|
|
uae_u8 b;
|
|
fdi->track_src += 2;
|
|
bit_drop_next (fdi);
|
|
debuglog ("s0d:bits=%d,data=%s", bits, datalog (fdi->track_src, (bits + 7) / 8));
|
|
while (bits >= 8) {
|
|
byte_mfm_add (fdi, *fdi->track_src++);
|
|
bits -= 8;
|
|
}
|
|
if (bits > 0) {
|
|
i = 7;
|
|
b = *fdi->track_src++;
|
|
while(bits--) {
|
|
bit_mfm_add (fdi, b & (1 << i));
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ***** */
|
|
/* AMIGA */
|
|
/* ***** */
|
|
|
|
/* just for testing integrity of Amiga sectors */
|
|
|
|
static void rotateonebit (uae_u8 *start, uae_u8 *end, unsigned int shift)
|
|
{
|
|
if (shift == 0)
|
|
return;
|
|
while (start <= end) {
|
|
start[0] <<= shift;
|
|
start[0] |= start[1] >> (8 - shift);
|
|
start++;
|
|
}
|
|
}
|
|
|
|
static int check_offset;
|
|
static uae_u16 getmfmword (const uae_u8 *mbuf)
|
|
{
|
|
uae_u32 v;
|
|
|
|
v = (mbuf[0] << 8) | (mbuf[1] << 0);
|
|
if (check_offset == 0)
|
|
return v;
|
|
v <<= 8;
|
|
v |= mbuf[2];
|
|
v >>= check_offset;
|
|
return v;
|
|
}
|
|
|
|
#define MFMMASK 0x55555555
|
|
static uae_u32 getmfmlong (const uae_u8 *mbuf)
|
|
{
|
|
return ((getmfmword (mbuf) << 16) | getmfmword (mbuf + 2)) & MFMMASK;
|
|
}
|
|
|
|
static int amiga_check_track (FDI *fdi)
|
|
{
|
|
int i, j, secwritten = 0;
|
|
int fwlen = fdi->out / 8;
|
|
int length = 2 * fwlen;
|
|
int drvsec = 11;
|
|
uae_u32 odd, even, chksum, id, dlong;
|
|
uae_u8 *secdata;
|
|
uae_u8 secbuf[544];
|
|
uae_u8 bigmfmbuf[60000];
|
|
uae_u8 *mbuf, *mbuf2, *mend;
|
|
char sectable[22];
|
|
uae_u8 *raw = fdi->track_dst_buffer;
|
|
int slabel, off;
|
|
int ok = 1;
|
|
|
|
memset (bigmfmbuf, 0, sizeof (bigmfmbuf));
|
|
mbuf = bigmfmbuf;
|
|
check_offset = 0;
|
|
for (i = 0; i < (fdi->out + 7) / 8; i++)
|
|
*mbuf++ = raw[i];
|
|
off = fdi->out & 7;
|
|
#if 1
|
|
if (off > 0) {
|
|
mbuf--;
|
|
*mbuf &= ~((1 << (8 - off)) - 1);
|
|
}
|
|
j = 0;
|
|
while (i < (fdi->out + 7) / 8 + 600) {
|
|
*mbuf++ |= (raw[j] >> off) | ((raw[j + 1]) << (8 - off));
|
|
j++;
|
|
i++;
|
|
}
|
|
#endif
|
|
mbuf = bigmfmbuf;
|
|
|
|
memset (sectable, 0, sizeof (sectable));
|
|
//memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16));
|
|
mend = bigmfmbuf + length;
|
|
mend -= (4 + 16 + 8 + 512);
|
|
|
|
while (secwritten < drvsec) {
|
|
int trackoffs;
|
|
|
|
for (;;) {
|
|
rotateonebit (bigmfmbuf, mend, 1);
|
|
if (getmfmword (mbuf) == 0)
|
|
break;
|
|
if (secwritten == 10) {
|
|
mbuf[0] = 0x44;
|
|
mbuf[1] = 0x89;
|
|
}
|
|
// check_offset++;
|
|
if (check_offset > 7) {
|
|
check_offset = 0;
|
|
mbuf++;
|
|
if (mbuf >= mend || *mbuf == 0)
|
|
break;
|
|
}
|
|
if (getmfmword (mbuf) == 0x4489)
|
|
break;
|
|
}
|
|
if (mbuf >= mend || *mbuf == 0)
|
|
break;
|
|
|
|
rotateonebit (bigmfmbuf, mend, check_offset);
|
|
check_offset = 0;
|
|
|
|
while (getmfmword (mbuf) == 0x4489)
|
|
mbuf+= 1 * 2;
|
|
mbuf2 = mbuf + 8;
|
|
|
|
odd = getmfmlong (mbuf);
|
|
even = getmfmlong (mbuf + 2 * 2);
|
|
mbuf += 4 * 2;
|
|
id = (odd << 1) | even;
|
|
|
|
trackoffs = (id & 0xff00) >> 8;
|
|
if (trackoffs + 1 > drvsec) {
|
|
outlog ("illegal sector offset %d\n",trackoffs);
|
|
ok = 0;
|
|
mbuf = mbuf2;
|
|
continue;
|
|
}
|
|
if ((id >> 24) != 0xff) {
|
|
outlog ("sector %d format type %02.2X?\n", trackoffs, id >> 24);
|
|
ok = 0;
|
|
}
|
|
chksum = odd ^ even;
|
|
slabel = 0;
|
|
for (i = 0; i < 4; i++) {
|
|
odd = getmfmlong (mbuf);
|
|
even = getmfmlong (mbuf + 8 * 2);
|
|
mbuf += 2* 2;
|
|
|
|
dlong = (odd << 1) | even;
|
|
if (dlong) slabel = 1;
|
|
chksum ^= odd ^ even;
|
|
}
|
|
mbuf += 8 * 2;
|
|
odd = getmfmlong (mbuf);
|
|
even = getmfmlong (mbuf + 2 * 2);
|
|
mbuf += 4 * 2;
|
|
if (((odd << 1) | even) != chksum) {
|
|
outlog ("sector %d header crc error\n", trackoffs);
|
|
ok = 0;
|
|
mbuf = mbuf2;
|
|
continue;
|
|
}
|
|
outlog ("sector %d header crc ok\n", trackoffs);
|
|
if (((id & 0x00ff0000) >> 16) != (uae_u32)fdi->current_track) {
|
|
outlog ("illegal track number %d <> %d\n", fdi->current_track, (id & 0x00ff0000) >> 16);
|
|
ok++;
|
|
mbuf = mbuf2;
|
|
continue;
|
|
}
|
|
odd = getmfmlong (mbuf);
|
|
even = getmfmlong (mbuf + 2 * 2);
|
|
mbuf += 4 * 2;
|
|
chksum = (odd << 1) | even;
|
|
secdata = secbuf + 32;
|
|
for (i = 0; i < 128; i++) {
|
|
odd = getmfmlong (mbuf);
|
|
even = getmfmlong (mbuf + 256 * 2);
|
|
mbuf += 2 * 2;
|
|
dlong = (odd << 1) | even;
|
|
*secdata++ = (uae_u8) (dlong >> 24);
|
|
*secdata++ = (uae_u8) (dlong >> 16);
|
|
*secdata++ = (uae_u8) (dlong >> 8);
|
|
*secdata++ = (uae_u8) dlong;
|
|
chksum ^= odd ^ even;
|
|
}
|
|
mbuf += 256 * 2;
|
|
if (chksum) {
|
|
outlog ("sector %d data checksum error\n",trackoffs);
|
|
ok = 0;
|
|
} else if (sectable[trackoffs]) {
|
|
outlog ("sector %d already found?\n", trackoffs);
|
|
mbuf = mbuf2;
|
|
} else {
|
|
outlog ("sector %d ok\n",trackoffs);
|
|
if (slabel) outlog ("(non-empty sector header)\n");
|
|
sectable[trackoffs] = 1;
|
|
secwritten++;
|
|
if (trackoffs == 9)
|
|
mbuf += 0x228;
|
|
}
|
|
}
|
|
for (i = 0; i < drvsec; i++) {
|
|
if (!sectable[i]) {
|
|
outlog ("sector %d missing\n", i);
|
|
ok = 0;
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
static void amiga_data_raw (FDI *fdi, uae_u8 *secbuf, uae_u8 *crc, unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
uae_u8 crcbuf[4];
|
|
|
|
if (!crc) {
|
|
memset (crcbuf, 0, 4);
|
|
} else {
|
|
memcpy (crcbuf, crc ,4);
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
byte_mfm_add (fdi, crcbuf[i]);
|
|
for (i = 0; i < len; i++)
|
|
byte_mfm_add (fdi, secbuf[i]);
|
|
}
|
|
|
|
static void amiga_data (FDI *fdi, const uae_u8 *secbuf)
|
|
{
|
|
uae_u16 mfmbuf[4 + 512];
|
|
uae_u32 dodd, deven, dck;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 512; i += 4) {
|
|
deven = ((secbuf[i + 0] << 24) | (secbuf[i + 1] << 16)
|
|
| (secbuf[i + 2] << 8) | (secbuf[i + 3]));
|
|
dodd = deven >> 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
mfmbuf[(i >> 1) + 4] = (uae_u16) (dodd >> 16);
|
|
mfmbuf[(i >> 1) + 5] = (uae_u16) dodd;
|
|
mfmbuf[(i >> 1) + 256 + 4] = (uae_u16) (deven >> 16);
|
|
mfmbuf[(i >> 1) + 256 + 5] = (uae_u16) deven;
|
|
}
|
|
dck = 0;
|
|
for (i = 4; i < 4 + 512; i += 2)
|
|
dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
|
|
deven = dodd = dck;
|
|
dodd >>= 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
mfmbuf[0] = (uae_u16) (dodd >> 16);
|
|
mfmbuf[1] = (uae_u16) dodd;
|
|
mfmbuf[2] = (uae_u16) (deven >> 16);
|
|
mfmbuf[3] = (uae_u16) deven;
|
|
|
|
for (i = 0; i < 4 + 512; i ++)
|
|
word_post_mfm_add (fdi, mfmbuf[i]);
|
|
}
|
|
|
|
static void amiga_sector_header (FDI *fdi, const uae_u8 *header, const uae_u8 *data, unsigned int sector, unsigned int untilgap)
|
|
{
|
|
uae_u8 headerbuf[4], databuf[16];
|
|
uae_u32 deven, dodd, hck;
|
|
uae_u16 mfmbuf[24];
|
|
unsigned int i;
|
|
|
|
byte_mfm_add (fdi, 0);
|
|
byte_mfm_add (fdi, 0);
|
|
word_add (fdi, 0x4489);
|
|
word_add (fdi, 0x4489);
|
|
if (header) {
|
|
memcpy (headerbuf, header, 4);
|
|
} else {
|
|
headerbuf[0] = 0xff;
|
|
headerbuf[1] = (uae_u8)fdi->current_track;
|
|
headerbuf[2] = (uae_u8)sector;
|
|
headerbuf[3] = (uae_u8)untilgap;
|
|
}
|
|
if (data)
|
|
memcpy (databuf, data, 16);
|
|
else
|
|
memset (databuf, 0, 16);
|
|
|
|
deven = ((headerbuf[0] << 24) | (headerbuf[1] << 16)
|
|
| (headerbuf[2] << 8) | (headerbuf[3]));
|
|
dodd = deven >> 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
mfmbuf[0] = (uae_u16) (dodd >> 16);
|
|
mfmbuf[1] = (uae_u16) dodd;
|
|
mfmbuf[2] = (uae_u16) (deven >> 16);
|
|
mfmbuf[3] = (uae_u16) deven;
|
|
for (i = 0; i < 16; i += 4) {
|
|
deven = ((databuf[i] << 24) | (databuf[i + 1] << 16)
|
|
| (databuf[i + 2] << 8) | (databuf[i + 3]));
|
|
dodd = deven >> 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
mfmbuf[(i >> 1) + 0 + 4] = (uae_u16) (dodd >> 16);
|
|
mfmbuf[(i >> 1) + 0 + 5] = (uae_u16) dodd;
|
|
mfmbuf[(i >> 1) + 8 + 4] = (uae_u16) (deven >> 16);
|
|
mfmbuf[(i >> 1) + 8 + 5] = (uae_u16) deven;
|
|
}
|
|
hck = 0;
|
|
for (i = 0; i < 4 + 16; i += 2)
|
|
hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
|
|
deven = dodd = hck;
|
|
dodd >>= 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
mfmbuf[20] = (uae_u16) (dodd >> 16);
|
|
mfmbuf[21] = (uae_u16) dodd;
|
|
mfmbuf[22] = (uae_u16) (deven >> 16);
|
|
mfmbuf[23] = (uae_u16) deven;
|
|
|
|
for (i = 0; i < 4 + 16 + 4; i ++)
|
|
word_post_mfm_add (fdi, mfmbuf[i]);
|
|
}
|
|
|
|
/* standard super-extended Amiga sector header */
|
|
static void s20(FDI *fdi)
|
|
{
|
|
bit_drop_next (fdi);
|
|
debuglog ("s20:header=%s,data=%s", datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 16));
|
|
amiga_sector_header (fdi, fdi->track_src, fdi->track_src + 4, 0, 0);
|
|
fdi->track_src += 4 + 16;
|
|
}
|
|
/* standard extended Amiga sector header */
|
|
static void s21(FDI *fdi)
|
|
{
|
|
bit_drop_next (fdi);
|
|
debuglog ("s21:header=%s", datalog (fdi->track_src, 4));
|
|
amiga_sector_header (fdi, fdi->track_src, 0, 0, 0);
|
|
fdi->track_src += 4;
|
|
}
|
|
/* standard Amiga sector header */
|
|
static void s22(FDI *fdi)
|
|
{
|
|
bit_drop_next (fdi);
|
|
debuglog ("s22:sector=%d,untilgap=%d", fdi->track_src[0], fdi->track_src[1]);
|
|
amiga_sector_header (fdi, 0, 0, fdi->track_src[0], fdi->track_src[1]);
|
|
fdi->track_src += 2;
|
|
}
|
|
/* standard 512-byte, CRC-correct Amiga data */
|
|
static void s23(FDI *fdi)
|
|
{
|
|
debuglog ("s23:data=%s", datalog (fdi->track_src, 512));
|
|
amiga_data (fdi, fdi->track_src);
|
|
fdi->track_src += 512;
|
|
}
|
|
/* not-decoded, 128*2^x-byte, CRC-correct Amiga data */
|
|
static void s24(FDI *fdi)
|
|
{
|
|
int shift = *fdi->track_src++;
|
|
debuglog ("s24:shift=%d,data=%s", shift, datalog (fdi->track_src, 128 << shift));
|
|
amiga_data_raw (fdi, fdi->track_src, 0, 128 << shift);
|
|
fdi->track_src += 128 << shift;
|
|
}
|
|
/* not-decoded, 128*2^x-byte, CRC-incorrect Amiga data */
|
|
static void s25(FDI *fdi)
|
|
{
|
|
int shift = *fdi->track_src++;
|
|
debuglog ("s25:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 128 << shift));
|
|
amiga_data_raw (fdi, fdi->track_src + 4, fdi->track_src, 128 << shift);
|
|
fdi->track_src += 4 + (128 << shift);
|
|
}
|
|
/* standard extended Amiga sector */
|
|
static void s26(FDI *fdi)
|
|
{
|
|
s21 (fdi);
|
|
debuglog ("s26:data=%s", datalog (fdi->track_src, 512));
|
|
amiga_data (fdi, fdi->track_src);
|
|
fdi->track_src += 512;
|
|
}
|
|
/* standard short Amiga sector */
|
|
static void s27(FDI *fdi)
|
|
{
|
|
s22 (fdi);
|
|
debuglog ("s27:data=%s", datalog (fdi->track_src, 512));
|
|
amiga_data (fdi, fdi->track_src);
|
|
fdi->track_src += 512;
|
|
}
|
|
|
|
/* *** */
|
|
/* IBM */
|
|
/* *** */
|
|
|
|
static uae_u16 ibm_crc (uae_u8 byte, int reset)
|
|
{
|
|
static uae_u16 crc;
|
|
int i;
|
|
|
|
if (reset) crc = 0xcdb4;
|
|
for (i = 0; i < 8; i++) {
|
|
if (crc & 0x8000) {
|
|
crc <<= 1;
|
|
if (!(byte & 0x80)) crc ^= 0x1021;
|
|
} else {
|
|
crc <<= 1;
|
|
if (byte & 0x80) crc ^= 0x1021;
|
|
}
|
|
byte <<= 1;
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
static void ibm_data (FDI *fdi, const uae_u8 *data, uae_u8 *crc, unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
uae_u8 crcbuf[2];
|
|
uae_u16 crcv = 0;
|
|
|
|
word_add (fdi, 0x4489);
|
|
word_add (fdi, 0x4489);
|
|
word_add (fdi, 0x4489);
|
|
byte_mfm_add (fdi, 0xfb);
|
|
ibm_crc (0xfb, 1);
|
|
for (i = 0; i < len; i++) {
|
|
byte_mfm_add (fdi, data[i]);
|
|
crcv = ibm_crc (data[i], 0);
|
|
}
|
|
if (!crc) {
|
|
crc = crcbuf;
|
|
crc[0] = (uae_u8)(crcv >> 8);
|
|
crc[1] = (uae_u8)crcv;
|
|
}
|
|
byte_mfm_add (fdi, crc[0]);
|
|
byte_mfm_add (fdi, crc[1]);
|
|
}
|
|
|
|
static void ibm_sector_header (FDI *fdi, const uae_u8 *data, const uae_u8 *crc, int secnum, int pre)
|
|
{
|
|
uae_u8 secbuf[5];
|
|
uae_u8 crcbuf[2];
|
|
uae_u16 crcv;
|
|
int i;
|
|
|
|
if (pre)
|
|
bytes_mfm_add (fdi, 0, 12);
|
|
word_add (fdi, 0x4489);
|
|
word_add (fdi, 0x4489);
|
|
word_add (fdi, 0x4489);
|
|
secbuf[0] = 0xfe;
|
|
if (secnum >= 0) {
|
|
secbuf[1] = (uae_u8)(fdi->current_track / 2);
|
|
secbuf[2] = (uae_u8)(fdi->current_track % 2);
|
|
secbuf[3] = (uae_u8)secnum;
|
|
secbuf[4] = 2;
|
|
} else {
|
|
memcpy (secbuf + 1, data, 4);
|
|
}
|
|
ibm_crc (secbuf[0], 1);
|
|
ibm_crc (secbuf[1], 0);
|
|
ibm_crc (secbuf[2], 0);
|
|
ibm_crc (secbuf[3], 0);
|
|
crcv = ibm_crc (secbuf[4], 0);
|
|
if (crc) {
|
|
memcpy (crcbuf, crc, 2);
|
|
} else {
|
|
crcbuf[0] = (uae_u8)(crcv >> 8);
|
|
crcbuf[1] = (uae_u8)crcv;
|
|
}
|
|
/* data */
|
|
for (i = 0;i < 5; i++)
|
|
byte_mfm_add (fdi, secbuf[i]);
|
|
/* crc */
|
|
byte_mfm_add (fdi, crcbuf[0]);
|
|
byte_mfm_add (fdi, crcbuf[1]);
|
|
}
|
|
|
|
/* standard IBM index address mark */
|
|
static void s10 (FDI *fdi)
|
|
{
|
|
bit_drop_next (fdi);
|
|
bytes_mfm_add (fdi, 0, 12);
|
|
word_add (fdi, 0x5224);
|
|
word_add (fdi, 0x5224);
|
|
word_add (fdi, 0x5224);
|
|
byte_mfm_add (fdi, 0xfc);
|
|
}
|
|
/* standard IBM pre-gap */
|
|
static void s11 (FDI *fdi)
|
|
{
|
|
bit_drop_next (fdi);
|
|
bytes_mfm_add (fdi, 0x4e, 78);
|
|
bit_dedrop (fdi);
|
|
s10 (fdi);
|
|
bytes_mfm_add (fdi, 0x4e, 50);
|
|
}
|
|
/* standard ST pre-gap */
|
|
static void s12 (FDI *fdi)
|
|
{
|
|
bit_drop_next (fdi);
|
|
bytes_mfm_add (fdi, 0x4e, 78);
|
|
}
|
|
/* standard extended IBM sector header */
|
|
static void s13 (FDI *fdi)
|
|
{
|
|
bit_drop_next (fdi);
|
|
debuglog ("s13:header=%s", datalog (fdi->track_src, 4));
|
|
ibm_sector_header (fdi, fdi->track_src, 0, -1, 1);
|
|
fdi->track_src += 4;
|
|
}
|
|
/* standard mini-extended IBM sector header */
|
|
static void s14 (FDI *fdi)
|
|
{
|
|
debuglog ("s14:header=%s", datalog (fdi->track_src, 4));
|
|
ibm_sector_header (fdi, fdi->track_src, 0, -1, 0);
|
|
fdi->track_src += 4;
|
|
}
|
|
/* standard short IBM sector header */
|
|
static void s15 (FDI *fdi)
|
|
{
|
|
bit_drop_next (fdi);
|
|
debuglog ("s15:sector=%d", *fdi->track_src);
|
|
ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 1);
|
|
}
|
|
/* standard mini-short IBM sector header */
|
|
static void s16 (FDI *fdi)
|
|
{
|
|
debuglog ("s16:track=%d", *fdi->track_src);
|
|
ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 0);
|
|
}
|
|
/* standard CRC-incorrect mini-extended IBM sector header */
|
|
static void s17 (FDI *fdi)
|
|
{
|
|
debuglog ("s17:header=%s,crc=%s", datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 2));
|
|
ibm_sector_header (fdi, fdi->track_src, fdi->track_src + 4, -1, 0);
|
|
fdi->track_src += 4 + 2;
|
|
}
|
|
/* standard CRC-incorrect mini-short IBM sector header */
|
|
static void s18 (FDI *fdi)
|
|
{
|
|
debuglog ("s18:sector=%d,header=%s", *fdi->track_src, datalog (fdi->track_src + 1, 4));
|
|
ibm_sector_header (fdi, 0, fdi->track_src + 1, *fdi->track_src, 0);
|
|
fdi->track_src += 1 + 4;
|
|
}
|
|
/* standard 512-byte CRC-correct IBM data */
|
|
static void s19 (FDI *fdi)
|
|
{
|
|
debuglog ("s19:data=%s", datalog (fdi->track_src , 512));
|
|
ibm_data (fdi, fdi->track_src, 0, 512);
|
|
fdi->track_src += 512;
|
|
}
|
|
/* standard 128*2^x-byte-byte CRC-correct IBM data */
|
|
static void s1a (FDI *fdi)
|
|
{
|
|
int shift = *fdi->track_src++;
|
|
debuglog ("s1a:shift=%d,data=%s", shift, datalog (fdi->track_src , 128 << shift));
|
|
ibm_data (fdi, fdi->track_src, 0, 128 << shift);
|
|
fdi->track_src += 128 << shift;
|
|
}
|
|
/* standard 128*2^x-byte-byte CRC-incorrect IBM data */
|
|
static void s1b (FDI *fdi)
|
|
{
|
|
int shift = *fdi->track_src++;
|
|
debuglog ("s1b:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src + (128 << shift), 2), datalog (fdi->track_src , 128 << shift));
|
|
ibm_data (fdi, fdi->track_src, fdi->track_src + (128 << shift), 128 << shift);
|
|
fdi->track_src += (128 << shift) + 2;
|
|
}
|
|
/* standard extended IBM sector */
|
|
static void s1c (FDI *fdi)
|
|
{
|
|
int shift = fdi->track_src[3];
|
|
s13 (fdi);
|
|
bytes_mfm_add (fdi, 0x4e, 22);
|
|
bytes_mfm_add (fdi, 0x00, 12);
|
|
ibm_data (fdi, fdi->track_src, 0, 128 << shift);
|
|
fdi->track_src += 128 << shift;
|
|
}
|
|
/* standard short IBM sector */
|
|
static void s1d (FDI *fdi)
|
|
{
|
|
s15 (fdi);
|
|
bytes_mfm_add (fdi, 0x4e, 22);
|
|
bytes_mfm_add (fdi, 0x00, 12);
|
|
s19 (fdi);
|
|
}
|
|
|
|
/* end marker */
|
|
static void sff (FDI *fdi)
|
|
{
|
|
}
|
|
|
|
typedef void (*decode_described_track_func)(FDI*);
|
|
|
|
static decode_described_track_func const decode_sectors_described_track[] =
|
|
{
|
|
s00,s01,s02,s03,s04,dxx,dxx,dxx,s08,s09,s0a,s0b,s0c,s0d,dxx,dxx, /* 00-0F */
|
|
s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s1a,s1b,s1c,s1d,dxx,dxx, /* 10-1F */
|
|
s20,s21,s22,s23,s24,s25,s26,s27,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 20-2F */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 30-3F */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 40-4F */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 50-5F */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 60-6F */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 70-7F */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 80-8F */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 90-9F */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* A0-AF */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* B0-BF */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* C0-CF */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* D0-DF */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* E0-EF */
|
|
dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,sff /* F0-FF */
|
|
};
|
|
|
|
static void track_amiga (struct fdi *fdi, unsigned int first_sector, unsigned int max_sector)
|
|
{
|
|
unsigned int i;
|
|
|
|
bit_add (fdi, 0);
|
|
bit_drop_next (fdi);
|
|
for (i = 0; i < max_sector; i++) {
|
|
amiga_sector_header (fdi, 0, 0, first_sector, max_sector - i);
|
|
amiga_data (fdi, fdi->track_src + first_sector * 512);
|
|
first_sector++;
|
|
if (first_sector >= max_sector) first_sector = 0;
|
|
}
|
|
bytes_mfm_add (fdi, 0, 260); /* gap */
|
|
}
|
|
static void track_atari_st (struct fdi *fdi, unsigned int max_sector)
|
|
{
|
|
unsigned int i, gap3 = 0;
|
|
uae_u8 *p = fdi->track_src;
|
|
|
|
switch (max_sector) {
|
|
case 9:
|
|
gap3 = 40;
|
|
break;
|
|
case 10:
|
|
gap3 = 24;
|
|
break;
|
|
}
|
|
s15 (fdi);
|
|
for (i = 0; i < max_sector; i++) {
|
|
byte_mfm_add (fdi, 0x4e);
|
|
byte_mfm_add (fdi, 0x4e);
|
|
ibm_sector_header (fdi, 0, 0, fdi->current_track, 1);
|
|
ibm_data (fdi, p + i * 512, 0, 512);
|
|
bytes_mfm_add (fdi, 0x4e, gap3);
|
|
}
|
|
bytes_mfm_add (fdi, 0x4e, 660 - gap3);
|
|
fdi->track_src += fdi->track_len * 256;
|
|
}
|
|
static void track_pc (struct fdi *fdi, unsigned int max_sector)
|
|
{
|
|
unsigned int i, gap3;
|
|
uae_u8 *p = fdi->track_src;
|
|
|
|
switch (max_sector) {
|
|
case 8:
|
|
gap3 = 116;
|
|
break;
|
|
case 9:
|
|
gap3 = 54;
|
|
break;
|
|
default:
|
|
gap3 = 100; /* fixme */
|
|
break;
|
|
}
|
|
s11 (fdi);
|
|
for (i = 0; i < max_sector; i++) {
|
|
byte_mfm_add (fdi, 0x4e);
|
|
byte_mfm_add (fdi, 0x4e);
|
|
ibm_sector_header (fdi, 0, 0, fdi->current_track, 1);
|
|
ibm_data (fdi, p + i * 512, 0, 512);
|
|
bytes_mfm_add (fdi, 0x4e, gap3);
|
|
}
|
|
bytes_mfm_add (fdi, 0x4e, 600 - gap3);
|
|
fdi->track_src += fdi->track_len * 256;
|
|
}
|
|
|
|
/* amiga dd */
|
|
static void track_amiga_dd (struct fdi *fdi)
|
|
{
|
|
uae_u8 *p = fdi->track_src;
|
|
track_amiga (fdi, fdi->track_len >> 4, 11);
|
|
fdi->track_src = p + (fdi->track_len & 15) * 512;
|
|
}
|
|
/* amiga hd */
|
|
static void track_amiga_hd (struct fdi *fdi)
|
|
{
|
|
uae_u8 *p = fdi->track_src;
|
|
track_amiga (fdi, 0, 22);
|
|
fdi->track_src = p + fdi->track_len * 256;
|
|
}
|
|
/* atari st 9 sector */
|
|
static void track_atari_st_9 (struct fdi *fdi)
|
|
{
|
|
track_atari_st (fdi, 9);
|
|
}
|
|
/* atari st 10 sector */
|
|
static void track_atari_st_10 (struct fdi *fdi)
|
|
{
|
|
track_atari_st (fdi, 10);
|
|
}
|
|
/* pc 8 sector */
|
|
static void track_pc_8 (struct fdi *fdi)
|
|
{
|
|
track_pc (fdi, 8);
|
|
}
|
|
/* pc 9 sector */
|
|
static void track_pc_9 (struct fdi *fdi)
|
|
{
|
|
track_pc (fdi, 9);
|
|
}
|
|
/* pc 15 sector */
|
|
static void track_pc_15 (struct fdi *fdi)
|
|
{
|
|
track_pc (fdi, 15);
|
|
}
|
|
/* pc 18 sector */
|
|
static void track_pc_18 (struct fdi *fdi)
|
|
{
|
|
track_pc (fdi, 18);
|
|
}
|
|
/* pc 36 sector */
|
|
static void track_pc_36 (struct fdi *fdi)
|
|
{
|
|
track_pc (fdi, 36);
|
|
}
|
|
|
|
typedef void (*decode_normal_track_func)(FDI*);
|
|
|
|
static decode_normal_track_func const decode_normal_track[] =
|
|
{
|
|
track_empty, /* 0 */
|
|
track_amiga_dd, track_amiga_hd, /* 1-2 */
|
|
track_atari_st_9, track_atari_st_10, /* 3-4 */
|
|
track_pc_8, track_pc_9, track_pc_15, track_pc_18, track_pc_36, /* 5-9 */
|
|
zxx,zxx,zxx,zxx,zxx /* A-F */
|
|
};
|
|
|
|
static void fix_mfm_sync (FDI *fdi)
|
|
{
|
|
int i, pos, off1, off2, off3, mask1, mask2, mask3;
|
|
|
|
for (i = 0; i < fdi->mfmsync_offset; i++) {
|
|
pos = fdi->mfmsync_buffer[i];
|
|
off1 = (pos - 1) >> 3;
|
|
off2 = (pos + 1) >> 3;
|
|
off3 = pos >> 3;
|
|
mask1 = 1 << (7 - ((pos - 1) & 7));
|
|
mask2 = 1 << (7 - ((pos + 1) & 7));
|
|
mask3 = 1 << (7 - (pos & 7));
|
|
if (!(fdi->track_dst[off1] & mask1) && !(fdi->track_dst[off2] & mask2))
|
|
fdi->track_dst[off3] |= mask3;
|
|
else
|
|
fdi->track_dst[off3] &= ~mask3;
|
|
}
|
|
}
|
|
|
|
static int handle_sectors_described_track (FDI *fdi)
|
|
{
|
|
int oldout;
|
|
uae_u8 *start_src = fdi->track_src ;
|
|
fdi->encoding_type = *fdi->track_src++;
|
|
fdi->index_offset = get_u32(fdi->track_src);
|
|
fdi->index_offset >>= 8;
|
|
fdi->track_src += 3;
|
|
outlog ("sectors_described, index offset: %d\n",fdi->index_offset);
|
|
|
|
do {
|
|
fdi->track_type = *fdi->track_src++;
|
|
outlog ("%06.6X %06.6X %02.2X:",fdi->track_src - start_src + 0x200, fdi->out/8, fdi->track_type);
|
|
oldout = fdi->out;
|
|
decode_sectors_described_track[fdi->track_type](fdi);
|
|
outlog (" %d\n", fdi->out - oldout);
|
|
oldout = fdi->out;
|
|
if (fdi->out < 0 || fdi->err) {
|
|
outlog ("\nin %d bytes, out %d bits\n", fdi->track_src - fdi->track_src_buffer, fdi->out);
|
|
return -1;
|
|
}
|
|
if (fdi->track_src - fdi->track_src_buffer >= fdi->track_src_len) {
|
|
outlog ("source buffer overrun, previous type: %02.2X\n", fdi->track_type);
|
|
return -1;
|
|
}
|
|
} while (fdi->track_type != 0xff);
|
|
outlog ("\n");
|
|
fix_mfm_sync (fdi);
|
|
return fdi->out;
|
|
}
|
|
|
|
static uae_u8 *fdi_decompress (unsigned int pulses, uae_u8 *sizep, const uae_u8 *src, unsigned int *dofree)
|
|
{
|
|
uae_u32 size = get_u24 (sizep);
|
|
uae_u32 *dst2;
|
|
unsigned int len = size & 0x3fffff;
|
|
uae_u8 *dst;
|
|
unsigned int mode = size >> 22, i;
|
|
|
|
*dofree = 0;
|
|
if (mode == 0 && pulses * 2 > len)
|
|
mode = 1;
|
|
if (mode == 0) {
|
|
dst2 = (uae_u32*)src;
|
|
dst = (uae_u8*)src;
|
|
for (i = 0; i < pulses; i++) {
|
|
*dst2++ = get_u32 (src);
|
|
src += 4;
|
|
}
|
|
} else if (mode == 1) {
|
|
dst = fdi_malloc (pulses * 4);
|
|
*dofree = 1;
|
|
fdi_decode (src, pulses, dst);
|
|
} else {
|
|
dst = 0;
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
static void dumpstream(int track, uae_u8 *stream, int len)
|
|
{
|
|
#if 0
|
|
char name[100];
|
|
FILE *f;
|
|
|
|
sprintf (name, "track_%d.raw", track);
|
|
f = fopen(name, "wb");
|
|
fwrite (stream, 1, len * 4, f);
|
|
fclose (f);
|
|
#endif
|
|
}
|
|
|
|
static int bitoffset;
|
|
|
|
STATIC_INLINE void addbit (uae_u8 *p, int bit)
|
|
{
|
|
int off1 = bitoffset / 8;
|
|
int off2 = bitoffset % 8;
|
|
p[off1] |= bit << (7 - off2);
|
|
bitoffset++;
|
|
}
|
|
|
|
|
|
struct pulse_sample {
|
|
unsigned long size;
|
|
int number_of_bits;
|
|
};
|
|
|
|
|
|
#define FDI_MAX_ARRAY 10 /* change this value as you want */
|
|
static const int pulse_limitval = 15; /* tolerance of 15% */
|
|
static struct pulse_sample psarray[FDI_MAX_ARRAY];
|
|
static int array_index;
|
|
static unsigned long total;
|
|
static int totaldiv;
|
|
|
|
static void init_array(unsigned long standard_MFM_2_bit_cell_size, int nb_of_bits)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < FDI_MAX_ARRAY; i++) {
|
|
psarray[i].size = standard_MFM_2_bit_cell_size; // That is (total track length / 50000) for Amiga double density
|
|
total += psarray[i].size;
|
|
psarray[i].number_of_bits = nb_of_bits;
|
|
totaldiv += psarray[i].number_of_bits;
|
|
}
|
|
array_index = 0;
|
|
}
|
|
|
|
#if 0
|
|
|
|
static void fdi2_decode (FDI *fdi, unsigned long totalavg, uae_u32 *avgp, uae_u32 *minp, uae_u32 *maxp, uae_u8 *idx, int maxidx, int *indexoffsetp, int pulses, int mfm)
|
|
{
|
|
unsigned long adjust;
|
|
unsigned long adjusted_pulse;
|
|
unsigned long standard_MFM_2_bit_cell_size = totalavg / 50000;
|
|
unsigned long standard_MFM_8_bit_cell_size = totalavg / 12500;
|
|
int real_size, i, j, eodat, outstep;
|
|
int indexoffset = *indexoffsetp;
|
|
uae_u8 *d = fdi->track_dst_buffer;
|
|
uae_u16 *pt = fdi->track_dst_buffer_timing;
|
|
uae_u32 ref_pulse, pulse;
|
|
|
|
/* detects a long-enough stable pulse coming just after another stable pulse */
|
|
i = 1;
|
|
while ( (i < pulses) && ( (idx[i] < maxidx)
|
|
|| (idx[i - 1] < maxidx)
|
|
|| (avgp[i] < (standard_MFM_2_bit_cell_size - (standard_MFM_2_bit_cell_size / 4))) ) )
|
|
i++;
|
|
if (i == pulses) {
|
|
outlog ("No stable and long-enough pulse in track.\n");
|
|
return;
|
|
}
|
|
i--;
|
|
eodat = i;
|
|
adjust = 0;
|
|
total = 0;
|
|
totaldiv = 0;
|
|
init_array(standard_MFM_2_bit_cell_size, 2);
|
|
bitoffset = 0;
|
|
ref_pulse = 0;
|
|
outstep = 0;
|
|
while (outstep < 2) {
|
|
|
|
/* calculates the current average bitrate from previous decoded data */
|
|
uae_u32 avg_size = (total << 3) / totaldiv; /* this is the new average size for one MFM bit */
|
|
/* uae_u32 avg_size = (uae_u32)((((float)total)*8.0) / ((float)totaldiv)); */
|
|
/* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */
|
|
if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) ||
|
|
(avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) {
|
|
//init_array(standard_MFM_2_bit_cell_size, 2);
|
|
avg_size = standard_MFM_8_bit_cell_size;
|
|
}
|
|
/* this is to prevent the average value from going too far
|
|
* from the theoretical value, otherwise it could progressively go to (2 *
|
|
* real value), or (real value / 2), etc. */
|
|
|
|
/* gets the next long-enough pulse (this may require more than one pulse) */
|
|
pulse = 0;
|
|
while (pulse < ((avg_size / 4) - (avg_size / 16))) {
|
|
int indx;
|
|
i++;
|
|
if (i >= pulses)
|
|
i = 0;
|
|
indx = idx[i];
|
|
if (rand() <= (indx * RAND_MAX) / maxidx) {
|
|
pulse += avgp[i] - ref_pulse;
|
|
if (indx >= maxidx)
|
|
ref_pulse = 0;
|
|
else
|
|
ref_pulse = avgp[i];
|
|
}
|
|
if (i == eodat)
|
|
outstep++;
|
|
if (outstep == 1 && indexoffset == i)
|
|
*indexoffsetp = bitoffset;
|
|
}
|
|
|
|
/* gets the size in bits from the pulse width, considering the current average bitrate */
|
|
adjusted_pulse = pulse;
|
|
real_size = 0;
|
|
while (adjusted_pulse >= avg_size) {
|
|
real_size += 4;
|
|
adjusted_pulse -= avg_size / 2;
|
|
}
|
|
adjusted_pulse <<= 3;
|
|
while (adjusted_pulse >= ((avg_size * 4) + (avg_size / 4))) {
|
|
real_size += 2;
|
|
adjusted_pulse -= avg_size * 2;
|
|
}
|
|
if (adjusted_pulse >= ((avg_size * 3) + (avg_size / 4))) {
|
|
if (adjusted_pulse <= ((avg_size * 4) - (avg_size / 4))) {
|
|
if ((2 * ((adjusted_pulse >> 2) - adjust)) <= ((2 * avg_size) - (avg_size / 4)))
|
|
real_size += 3;
|
|
else
|
|
real_size += 4;
|
|
} else
|
|
real_size += 4;
|
|
} else {
|
|
if (adjusted_pulse > ((avg_size * 3) - (avg_size / 4))) {
|
|
real_size += 3;
|
|
} else {
|
|
if (adjusted_pulse >= ((avg_size * 2) + (avg_size / 4))) {
|
|
if ((2 * ((adjusted_pulse >> 2) - adjust)) < (avg_size + (avg_size / 4)))
|
|
real_size += 2;
|
|
else
|
|
real_size += 3;
|
|
} else
|
|
real_size += 2;
|
|
}
|
|
}
|
|
|
|
if (outstep == 1) {
|
|
for (j = real_size; j > 1; j--)
|
|
addbit (d, 0);
|
|
addbit (d, 1);
|
|
for (j = 0; j < real_size; j++)
|
|
*pt++ = (uae_u16)(pulse / real_size);
|
|
}
|
|
|
|
/* prepares for the next pulse */
|
|
adjust = ((real_size * avg_size)/8) - pulse;
|
|
total -= psarray[array_index].size;
|
|
totaldiv -= psarray[array_index].number_of_bits;
|
|
psarray[array_index].size = pulse;
|
|
psarray[array_index].number_of_bits = real_size;
|
|
total += pulse;
|
|
totaldiv += real_size;
|
|
array_index++;
|
|
if (array_index >= FDI_MAX_ARRAY)
|
|
array_index = 0;
|
|
}
|
|
|
|
fdi->out = bitoffset;
|
|
}
|
|
|
|
#else
|
|
|
|
static void fdi2_decode (FDI *fdi, unsigned long totalavg, uae_u32 *avgp, uae_u32 *minp, uae_u32 *maxp, uae_u8 *idx, unsigned int maxidx, unsigned int *indexoffsetp, unsigned int pulses, int mfm)
|
|
{
|
|
unsigned long adjust;
|
|
unsigned long adjusted_pulse;
|
|
unsigned long standard_MFM_2_bit_cell_size = totalavg / 50000;
|
|
unsigned long standard_MFM_8_bit_cell_size = totalavg / 12500;
|
|
unsigned int real_size, i, nexti, eodat, randval;
|
|
int outstep;
|
|
unsigned int indexoffset = *indexoffsetp;
|
|
uae_u8 *d = fdi->track_dst_buffer;
|
|
uae_u16 *pt = fdi->track_dst_buffer_timing;
|
|
uae_u32 ref_pulse, pulse;
|
|
long jitter;
|
|
|
|
/* detects a long-enough stable pulse coming just after another stable pulse */
|
|
i = 1;
|
|
while ( (i < pulses) && ( (idx[i] < maxidx)
|
|
|| (idx[i - 1] < maxidx)
|
|
|| (minp[i] < (standard_MFM_2_bit_cell_size - (standard_MFM_2_bit_cell_size / 4))) ) )
|
|
i++;
|
|
if (i == pulses) {
|
|
outlog ("FDI: No stable and long-enough pulse in track.\n");
|
|
return;
|
|
}
|
|
nexti = i;
|
|
eodat = i;
|
|
i--;
|
|
adjust = 0;
|
|
total = 0;
|
|
totaldiv = 0;
|
|
init_array(standard_MFM_2_bit_cell_size, 1 + mfm);
|
|
bitoffset = 0;
|
|
ref_pulse = 0;
|
|
jitter = 0;
|
|
outstep = -1;
|
|
while (outstep < 2) {
|
|
|
|
/* calculates the current average bitrate from previous decoded data */
|
|
uae_u32 avg_size = (total << (2 + mfm)) / totaldiv; /* this is the new average size for one MFM bit */
|
|
/* uae_u32 avg_size = (uae_u32)((((float)total)*((float)(mfm+1))*4.0) / ((float)totaldiv)); */
|
|
/* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */
|
|
if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) ||
|
|
(avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) {
|
|
//init_array(standard_MFM_2_bit_cell_size, mfm + 1);
|
|
avg_size = standard_MFM_8_bit_cell_size;
|
|
}
|
|
/* this is to prevent the average value from going too far
|
|
* from the theoretical value, otherwise it could progressively go to (2 *
|
|
* real value), or (real value / 2), etc. */
|
|
|
|
/* gets the next long-enough pulse (this may require more than one pulse) */
|
|
pulse = 0;
|
|
while (pulse < ((avg_size / 4) - (avg_size / 16))) {
|
|
uae_u32 avg_pulse, min_pulse, max_pulse;
|
|
i++;
|
|
if (i >= pulses)
|
|
i = 0;
|
|
if (i == nexti) {
|
|
do {
|
|
nexti++;
|
|
if (nexti >= pulses)
|
|
nexti = 0;
|
|
} while (idx[nexti] < maxidx);
|
|
}
|
|
if (idx[i] >= maxidx) { /* stable pulse */
|
|
avg_pulse = avgp[i] - jitter;
|
|
min_pulse = minp[i];
|
|
max_pulse = maxp[i];
|
|
if (jitter >= 0)
|
|
max_pulse -= jitter;
|
|
else
|
|
min_pulse -= jitter;
|
|
if ((maxp[nexti] - avgp[nexti]) < (avg_pulse - min_pulse))
|
|
min_pulse = avg_pulse - (maxp[nexti] - avgp[nexti]);
|
|
if ((avgp[nexti] - minp[nexti]) < (max_pulse - avg_pulse))
|
|
max_pulse = avg_pulse + (avgp[nexti] - minp[nexti]);
|
|
if (min_pulse < ref_pulse)
|
|
min_pulse = ref_pulse;
|
|
randval = rand();
|
|
if (randval < (RAND_MAX / 2)) {
|
|
if (randval > (RAND_MAX / 4)) {
|
|
if (randval <= (3 * (RAND_MAX / 8)))
|
|
randval = (2 * randval) - (RAND_MAX /4);
|
|
else
|
|
randval = (4 * randval) - RAND_MAX;
|
|
}
|
|
jitter = 0 - (randval * (avg_pulse - min_pulse)) / RAND_MAX;
|
|
} else {
|
|
randval -= RAND_MAX / 2;
|
|
if (randval > (RAND_MAX / 4)) {
|
|
if (randval <= (3 * (RAND_MAX / 8)))
|
|
randval = (2 * randval) - (RAND_MAX /4);
|
|
else
|
|
randval = (4 * randval) - RAND_MAX;
|
|
}
|
|
jitter = (randval * (max_pulse - avg_pulse)) / RAND_MAX;
|
|
}
|
|
avg_pulse += jitter;
|
|
if ((avg_pulse < min_pulse) || (avg_pulse > max_pulse)) {
|
|
outlog ("FDI: avg_pulse outside bounds! avg=%u min=%u max=%u\n", avg_pulse, min_pulse, max_pulse);
|
|
outlog ("FDI: avgp=%u (%u) minp=%u (%u) maxp=%u (%u) jitter=%d i=%d ni=%d\n",
|
|
avgp[i], avgp[nexti], minp[i], minp[nexti], maxp[i], maxp[nexti], jitter, i, nexti);
|
|
}
|
|
if (avg_pulse < ref_pulse)
|
|
outlog ("FDI: avg_pulse < ref_pulse! (%u < %u)\n", avg_pulse, ref_pulse);
|
|
pulse += avg_pulse - ref_pulse;
|
|
ref_pulse = 0;
|
|
if (i == eodat)
|
|
outstep++;
|
|
} else if ((unsigned int)rand () <= ((idx[i] * RAND_MAX) / maxidx)) {
|
|
avg_pulse = avgp[i];
|
|
min_pulse = minp[i];
|
|
max_pulse = maxp[i];
|
|
randval = rand();
|
|
if (randval < (RAND_MAX / 2)) {
|
|
if (randval > (RAND_MAX / 4)) {
|
|
if (randval <= (3 * (RAND_MAX / 8)))
|
|
randval = (2 * randval) - (RAND_MAX /4);
|
|
else
|
|
randval = (4 * randval) - RAND_MAX;
|
|
}
|
|
avg_pulse -= (randval * (avg_pulse - min_pulse)) / RAND_MAX;
|
|
} else {
|
|
randval -= RAND_MAX / 2;
|
|
if (randval > (RAND_MAX / 4)) {
|
|
if (randval <= (3 * (RAND_MAX / 8)))
|
|
randval = (2 * randval) - (RAND_MAX /4);
|
|
else
|
|
randval = (4 * randval) - RAND_MAX;
|
|
}
|
|
avg_pulse += (randval * (max_pulse - avg_pulse)) / RAND_MAX;
|
|
}
|
|
if ((avg_pulse > ref_pulse) && (avg_pulse < (avgp[nexti] - jitter))) {
|
|
pulse += avg_pulse - ref_pulse;
|
|
ref_pulse = avg_pulse;
|
|
}
|
|
}
|
|
if (outstep == 1 && indexoffset == i)
|
|
*indexoffsetp = bitoffset;
|
|
}
|
|
|
|
/* gets the size in bits from the pulse width, considering the current average bitrate */
|
|
adjusted_pulse = pulse;
|
|
real_size = 0;
|
|
if (mfm) {
|
|
while (adjusted_pulse >= avg_size) {
|
|
real_size += 4;
|
|
adjusted_pulse -= avg_size / 2;
|
|
}
|
|
adjusted_pulse <<= 3;
|
|
while (adjusted_pulse >= ((avg_size * 4) + (avg_size / 4))) {
|
|
real_size += 2;
|
|
adjusted_pulse -= avg_size * 2;
|
|
}
|
|
if (adjusted_pulse >= ((avg_size * 3) + (avg_size / 4))) {
|
|
if (adjusted_pulse <= ((avg_size * 4) - (avg_size / 4))) {
|
|
if ((2 * ((adjusted_pulse >> 2) - adjust)) <= ((2 * avg_size) - (avg_size / 4)))
|
|
real_size += 3;
|
|
else
|
|
real_size += 4;
|
|
} else
|
|
real_size += 4;
|
|
} else {
|
|
if (adjusted_pulse > ((avg_size * 3) - (avg_size / 4))) {
|
|
real_size += 3;
|
|
} else {
|
|
if (adjusted_pulse >= ((avg_size * 2) + (avg_size / 4))) {
|
|
if ((2 * ((adjusted_pulse >> 2) - adjust)) < (avg_size + (avg_size / 4)))
|
|
real_size += 2;
|
|
else
|
|
real_size += 3;
|
|
} else
|
|
real_size += 2;
|
|
}
|
|
}
|
|
} else {
|
|
while (adjusted_pulse >= (2*avg_size))
|
|
{
|
|
real_size+=4;
|
|
adjusted_pulse-=avg_size;
|
|
}
|
|
adjusted_pulse<<=2;
|
|
while (adjusted_pulse >= ((avg_size*3)+(avg_size/4)))
|
|
{
|
|
real_size+=2;
|
|
adjusted_pulse-=avg_size*2;
|
|
}
|
|
if (adjusted_pulse >= ((avg_size*2)+(avg_size/4)))
|
|
{
|
|
if (adjusted_pulse <= ((avg_size*3)-(avg_size/4)))
|
|
{
|
|
if (((adjusted_pulse>>1)-adjust) < (avg_size+(avg_size/4)))
|
|
real_size+=2;
|
|
else
|
|
real_size+=3;
|
|
}
|
|
else
|
|
real_size+=3;
|
|
}
|
|
else
|
|
{
|
|
if (adjusted_pulse > ((avg_size*2)-(avg_size/4)))
|
|
real_size+=2;
|
|
else
|
|
{
|
|
if (adjusted_pulse >= (avg_size+(avg_size/4)))
|
|
{
|
|
if (((adjusted_pulse>>1)-adjust) <= (avg_size-(avg_size/4)))
|
|
real_size++;
|
|
else
|
|
real_size+=2;
|
|
}
|
|
else
|
|
real_size++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* after one pass to correctly initialize the average bitrate, outputs the bits */
|
|
if (outstep == 1) {
|
|
unsigned int j;
|
|
for (j = real_size; j > 1; j--)
|
|
addbit (d, 0);
|
|
addbit (d, 1);
|
|
for (j = 0; j < real_size; j++)
|
|
*pt++ = (uae_u16)(pulse / real_size);
|
|
}
|
|
|
|
/* prepares for the next pulse */
|
|
adjust = ((real_size * avg_size) / (4 << mfm)) - pulse;
|
|
total -= psarray[array_index].size;
|
|
totaldiv -= psarray[array_index].number_of_bits;
|
|
psarray[array_index].size = pulse;
|
|
psarray[array_index].number_of_bits = real_size;
|
|
total += pulse;
|
|
totaldiv += real_size;
|
|
array_index++;
|
|
if (array_index >= FDI_MAX_ARRAY)
|
|
array_index = 0;
|
|
}
|
|
|
|
fdi->out = bitoffset;
|
|
}
|
|
|
|
#endif
|
|
|
|
static void fdi2_celltiming (FDI *fdi, unsigned long totalavg, unsigned int bitoffset, uae_u16 *out)
|
|
{
|
|
uae_u16 *pt2, *pt;
|
|
double avg_bit_len;
|
|
unsigned int i;
|
|
|
|
avg_bit_len = (double)totalavg / (double)bitoffset;
|
|
pt2 = fdi->track_dst_buffer_timing;
|
|
pt = out;
|
|
for (i = 0; i < bitoffset / 8; i++) {
|
|
double v = (pt2[0] + pt2[1] + pt2[2] + pt2[3] + pt2[4] + pt2[5] + pt2[6] + pt2[7]) / 8.0;
|
|
v = 1000.0 * v / avg_bit_len;
|
|
*pt++ = (uae_u16)v;
|
|
pt2 += 8;
|
|
}
|
|
*pt++ = out[0];
|
|
*pt = out[0];
|
|
}
|
|
|
|
static int decode_lowlevel_track (FDI *fdi, unsigned int track, struct fdi_cache *cache)
|
|
{
|
|
uae_u8 *p1, *d;
|
|
uae_u32 *p2;
|
|
uae_u32 *avgp, *minp = 0, *maxp = 0;
|
|
uae_u8 *idxp = 0;
|
|
uae_u32 maxidx, totalavg, weakbits;
|
|
unsigned int i, j, len, pulses, indexoffset;
|
|
unsigned int avg_free, min_free = 0, max_free = 0, idx_free;
|
|
unsigned int idx_off1 = 0, idx_off2 = 0, idx_off3 = 0;
|
|
|
|
d = fdi->track_dst;
|
|
p1 = fdi->track_src;
|
|
pulses = get_u32 (p1);
|
|
if (!pulses)
|
|
return -1;
|
|
p1 += 4;
|
|
len = 12;
|
|
avgp = (uae_u32*)fdi_decompress (pulses, p1 + 0, p1 + len, &avg_free);
|
|
dumpstream(track, (uae_u8*)avgp, pulses);
|
|
len += get_u24 (p1 + 0) & 0x3fffff;
|
|
if (!avgp)
|
|
return -1;
|
|
if (get_u24 (p1 + 3) && get_u24 (p1 + 6)) {
|
|
minp = (uae_u32*)fdi_decompress (pulses, p1 + 3, p1 + len, &min_free);
|
|
len += get_u24 (p1 + 3) & 0x3fffff;
|
|
maxp = (uae_u32*)fdi_decompress (pulses, p1 + 6, p1 + len, &max_free);
|
|
len += get_u24 (p1 + 6) & 0x3fffff;
|
|
/* Computes the real min and max values */
|
|
for (i = 0; i < pulses; i++) {
|
|
maxp[i] = avgp[i] + minp[i] - maxp[i];
|
|
minp[i] = avgp[i] - minp[i];
|
|
}
|
|
} else {
|
|
minp = avgp;
|
|
maxp = avgp;
|
|
}
|
|
if (get_u24 (p1 + 9)) {
|
|
idx_off1 = 0;
|
|
idx_off2 = 1;
|
|
idx_off3 = 2;
|
|
idxp = fdi_decompress (pulses, p1 + 9, p1 + len, &idx_free);
|
|
if (idx_free) {
|
|
if (idxp[0] == 0 && idxp[1] == 0) {
|
|
idx_off1 = 2;
|
|
idx_off2 = 3;
|
|
} else {
|
|
idx_off1 = 1;
|
|
idx_off2 = 0;
|
|
}
|
|
idx_off3 = 4;
|
|
}
|
|
} else {
|
|
idxp = fdi_malloc (pulses * 2);
|
|
idx_free = 1;
|
|
for (i = 0; i < pulses; i++) {
|
|
idxp[i * 2 + 0] = 2;
|
|
idxp[i * 2 + 1] = 0;
|
|
}
|
|
idxp[0] = 1;
|
|
idxp[1] = 1;
|
|
}
|
|
|
|
maxidx = 0;
|
|
indexoffset = 0;
|
|
p1 = idxp;
|
|
for (i = 0; i < pulses; i++) {
|
|
if (p1[idx_off1] + p1[idx_off2] > maxidx)
|
|
maxidx = p1[idx_off1] + p1[idx_off2];
|
|
p1 += idx_off3;
|
|
}
|
|
p1 = idxp;
|
|
for (i = 0; (i < pulses) && (p1[idx_off2] != 0); i++) /* falling edge, replace with idx_off1 for rising edge */
|
|
p1 += idx_off3;
|
|
if (i < pulses) {
|
|
j = i;
|
|
do {
|
|
i++;
|
|
p1 += idx_off3;
|
|
if (i >= pulses) {
|
|
i = 0;
|
|
p1 = idxp;
|
|
}
|
|
} while ((i != j) && (p1[idx_off2] == 0)); /* falling edge, replace with idx_off1 for rising edge */
|
|
if (i != j) /* index pulse detected */
|
|
{
|
|
while ((i != j) && (p1[idx_off1] > p1[idx_off2])) { /* falling edge, replace with "<" for rising edge */
|
|
i++;
|
|
p1 += idx_off3;
|
|
if (i >= pulses) {
|
|
i = 0;
|
|
p1 = idxp;
|
|
}
|
|
}
|
|
if (i != j)
|
|
indexoffset = i; /* index position detected */
|
|
}
|
|
}
|
|
p1 = idxp;
|
|
p2 = avgp;
|
|
totalavg = 0;
|
|
weakbits = 0;
|
|
for (i = 0; i < pulses; i++) {
|
|
uae_u32 sum = p1[idx_off1] + p1[idx_off2];
|
|
if (sum >= maxidx) {
|
|
totalavg += *p2;
|
|
} else {
|
|
weakbits++;
|
|
}
|
|
p2++;
|
|
p1 += idx_off3;
|
|
idxp[i] = sum;
|
|
}
|
|
len = totalavg / 100000;
|
|
outlog ("totalavg=%u index=%d (%d) maxidx=%d weakbits=%d len=%d\n",
|
|
totalavg, indexoffset, maxidx, weakbits, len);
|
|
cache->avgp = avgp;
|
|
cache->idxp = idxp;
|
|
cache->minp = minp;
|
|
cache->maxp = maxp;
|
|
cache->avg_free = avg_free;
|
|
cache->idx_free = idx_free;
|
|
cache->min_free = min_free;
|
|
cache->max_free = max_free;
|
|
cache->totalavg = totalavg;
|
|
cache->pulses = pulses;
|
|
cache->maxidx = maxidx;
|
|
cache->indexoffset = indexoffset;
|
|
cache->weakbits = weakbits;
|
|
cache->lowlevel = 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static const char fdiid[] = "Formatted Disk Image file";
|
|
static const unsigned int bit_rate_table[16] = { 125,150,250,300,500,1000 };
|
|
|
|
void fdi2raw_header_free (FDI *fdi)
|
|
{
|
|
int i;
|
|
|
|
fdi_free (fdi->mfmsync_buffer);
|
|
fdi_free (fdi->track_src_buffer);
|
|
fdi_free (fdi->track_dst_buffer);
|
|
fdi_free (fdi->track_dst_buffer_timing);
|
|
for (i = 0; i < MAX_TRACKS; i++) {
|
|
struct fdi_cache *c = &fdi->cache[i];
|
|
if (c->idx_free)
|
|
fdi_free (c->idxp);
|
|
if (c->avg_free)
|
|
fdi_free (c->avgp);
|
|
if (c->min_free)
|
|
fdi_free (c->minp);
|
|
if (c->max_free)
|
|
fdi_free (c->maxp);
|
|
}
|
|
fdi_free (fdi);
|
|
debuglog ("FREE: memory allocated %d\n", fdi_allocated);
|
|
}
|
|
|
|
int fdi2raw_get_last_track (FDI *fdi)
|
|
{
|
|
return fdi->last_track;
|
|
}
|
|
|
|
int fdi2raw_get_num_sector (FDI *fdi)
|
|
{
|
|
if (fdi->header[152] == 0x02)
|
|
return 22;
|
|
return 11;
|
|
}
|
|
|
|
unsigned int fdi2raw_get_last_head (FDI *fdi)
|
|
{
|
|
return fdi->last_head;
|
|
}
|
|
|
|
unsigned int fdi2raw_get_rotation (FDI *fdi)
|
|
{
|
|
return fdi->rotation_speed;
|
|
}
|
|
|
|
unsigned int fdi2raw_get_bit_rate (FDI *fdi)
|
|
{
|
|
return fdi->bit_rate;
|
|
}
|
|
|
|
int fdi2raw_get_type (FDI *fdi)
|
|
{
|
|
return fdi->disk_type;
|
|
}
|
|
|
|
int fdi2raw_get_write_protect (FDI *fdi)
|
|
{
|
|
return fdi->write_protect;
|
|
}
|
|
|
|
FDI *fdi2raw_header(struct zfile *f)
|
|
{
|
|
unsigned int i, offset, oldseek;
|
|
uae_u8 type, size;
|
|
FDI *fdi;
|
|
|
|
debuglog ("ALLOC: memory allocated %d\n", fdi_allocated);
|
|
fdi = fdi_malloc (sizeof(FDI));
|
|
memset (fdi, 0, sizeof (FDI));
|
|
fdi->file = f;
|
|
oldseek = zfile_ftell (fdi->file);
|
|
zfile_fseek (fdi->file, 0, SEEK_SET);
|
|
zfile_fread (fdi->header, 2048, 1, fdi->file);
|
|
zfile_fseek (fdi->file, oldseek, SEEK_SET);
|
|
if (memcmp (fdiid, fdi->header, strlen (fdiid))) {
|
|
fdi_free(fdi);
|
|
return NULL;
|
|
}
|
|
if ((fdi->header[140] != 1 && fdi->header[140] != 2) || fdi->header[141] != 0) {
|
|
fdi_free(fdi);
|
|
return NULL;
|
|
}
|
|
|
|
fdi->mfmsync_buffer = fdi_malloc (MAX_MFM_SYNC_BUFFER * sizeof(int));
|
|
fdi->track_src_buffer = fdi_malloc (MAX_SRC_BUFFER);
|
|
fdi->track_dst_buffer = fdi_malloc (MAX_DST_BUFFER);
|
|
fdi->track_dst_buffer_timing = fdi_malloc (MAX_TIMING_BUFFER);
|
|
|
|
fdi->last_track = ((fdi->header[142] << 8) + fdi->header[143]) + 1;
|
|
fdi->last_track *= fdi->header[144] + 1;
|
|
if (fdi->last_track > MAX_TRACKS)
|
|
fdi->last_track = MAX_TRACKS;
|
|
fdi->last_head = fdi->header[144];
|
|
fdi->disk_type = fdi->header[145];
|
|
fdi->rotation_speed = fdi->header[146] + 128;
|
|
fdi->write_protect = fdi->header[147] & 1;
|
|
outlog ("FDI version %d.%d\n", fdi->header[140], fdi->header[141]);
|
|
outlog ("last_track=%d rotation_speed=%d\n", fdi->last_track, fdi->rotation_speed);
|
|
|
|
offset = 512;
|
|
i = fdi->last_track;
|
|
if (i > 180) {
|
|
offset += 512;
|
|
i -= 180;
|
|
while (i > 256) {
|
|
offset += 512;
|
|
i -= 256;
|
|
}
|
|
}
|
|
for (i = 0; i < fdi->last_track; i++) {
|
|
fdi->track_offsets[i] = offset;
|
|
type = fdi->header[152 + i * 2];
|
|
size = fdi->header[152 + i * 2 + 1];
|
|
if (type == 1)
|
|
offset += (size & 15) * 512;
|
|
else if ((type & 0xc0) == 0x80)
|
|
offset += (((type & 0x3f) << 8) | size) * 256;
|
|
else
|
|
offset += size * 256;
|
|
}
|
|
fdi->track_offsets[i] = offset;
|
|
|
|
return fdi;
|
|
}
|
|
|
|
|
|
static int fdi2raw_loadrevolution_2 (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, unsigned int track, unsigned int *tracklength, unsigned int *indexoffsetp, int *multirev, int mfm)
|
|
{
|
|
struct fdi_cache *cache = &fdi->cache[track];
|
|
unsigned int len, i, idx;
|
|
|
|
memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER);
|
|
idx = cache->indexoffset;
|
|
fdi2_decode (fdi, cache->totalavg,
|
|
cache->avgp, cache->minp, cache->maxp, cache->idxp,
|
|
cache->maxidx, &idx, cache->pulses, mfm);
|
|
//fdi2_gcr_decode (fdi, totalavg, avgp, minp, maxp, idxp, idx_off1, idx_off2, idx_off3, maxidx, pulses);
|
|
outlog ("track %d: nbits=%d avg len=%.2f weakbits=%d idx=%d\n",
|
|
track, bitoffset, (double)cache->totalavg / bitoffset, cache->weakbits, cache->indexoffset);
|
|
len = fdi->out;
|
|
if (cache->weakbits >= 10 && multirev)
|
|
*multirev = 1;
|
|
*tracklength = len;
|
|
|
|
for (i = 0; i < (len + 15) / (2 * 8); i++) {
|
|
uae_u8 *data = fdi->track_dst_buffer + i * 2;
|
|
*mfmbuf++ = 256 * *data + *(data + 1);
|
|
}
|
|
fdi2_celltiming (fdi, cache->totalavg, len, tracktiming);
|
|
if (indexoffsetp)
|
|
*indexoffsetp = idx;
|
|
return 1;
|
|
}
|
|
|
|
int fdi2raw_loadrevolution (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, unsigned int track, unsigned int *tracklength, int mfm)
|
|
{
|
|
return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, 0, 0, mfm);
|
|
}
|
|
|
|
int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, unsigned int track, unsigned int *tracklength, unsigned int *indexoffsetp, int *multirev, int mfm)
|
|
{
|
|
uae_u8 *p;
|
|
int outlen;
|
|
unsigned int indexoffset = 0;
|
|
struct fdi_cache *cache = &fdi->cache[track];
|
|
|
|
if (cache->lowlevel)
|
|
return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, indexoffsetp, multirev, mfm);
|
|
|
|
fdi->err = 0;
|
|
fdi->track_src_len = fdi->track_offsets[track + 1] - fdi->track_offsets[track];
|
|
zfile_fseek (fdi->file, fdi->track_offsets[track], SEEK_SET);
|
|
zfile_fread (fdi->track_src_buffer, fdi->track_src_len, 1, fdi->file);
|
|
memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER);
|
|
fdi->track_dst_buffer_timing[0] = 0;
|
|
|
|
fdi->current_track = track;
|
|
fdi->track_src = fdi->track_src_buffer;
|
|
fdi->track_dst = fdi->track_dst_buffer;
|
|
p = fdi->header + 152 + fdi->current_track * 2;
|
|
fdi->track_type = *p++;
|
|
fdi->track_len = *p++;
|
|
fdi->bit_rate = 0;
|
|
fdi->out = 0;
|
|
fdi->mfmsync_offset = 0;
|
|
|
|
if ((fdi->track_type & 0xf0) == 0xf0 || (fdi->track_type & 0xf0) == 0xe0)
|
|
fdi->bit_rate = bit_rate_table[fdi->track_type & 0x0f];
|
|
else
|
|
fdi->bit_rate = 250;
|
|
|
|
outlog ("track %d: srclen: %d track_type: %02.2X, bitrate: %d\n",
|
|
fdi->current_track, fdi->track_src_len, fdi->track_type, fdi->bit_rate);
|
|
|
|
if ((fdi->track_type & 0xc0) == 0x80) {
|
|
|
|
outlen = decode_lowlevel_track (fdi, track, cache);
|
|
|
|
} else if ((fdi->track_type & 0xf0) == 0xf0) {
|
|
|
|
outlen = decode_raw_track (fdi);
|
|
|
|
} else if ((fdi->track_type & 0xf0) == 0xe0) {
|
|
|
|
outlen = handle_sectors_described_track (fdi);
|
|
|
|
} else if ((fdi->track_type & 0xf0)) {
|
|
|
|
zxx (fdi);
|
|
outlen = -1;
|
|
|
|
} else if (fdi->track_type < 0x10) {
|
|
|
|
decode_normal_track[fdi->track_type](fdi);
|
|
fix_mfm_sync (fdi);
|
|
outlen = fdi->out;
|
|
|
|
} else {
|
|
|
|
zxx (fdi);
|
|
outlen = -1;
|
|
|
|
}
|
|
|
|
// amiga_check_track (fdi);
|
|
|
|
if (fdi->err)
|
|
return 0;
|
|
|
|
if (outlen > 0) {
|
|
unsigned int i;
|
|
|
|
if (cache->lowlevel)
|
|
return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, indexoffsetp, multirev, mfm);
|
|
*tracklength = fdi->out;
|
|
|
|
for (i = 0; i < ((*tracklength) + 15) / (2 * 8); i++) {
|
|
uae_u8 *data = fdi->track_dst_buffer + i * 2;
|
|
*mfmbuf++ = 256 * *data + *(data + 1);
|
|
}
|
|
}
|
|
return outlen;
|
|
}
|
|
|
|
#endif
|