Implemented support for SCP images #555

This commit is contained in:
Dimitris Panokostas 2019-12-14 13:17:13 +01:00
parent 1df2751f13
commit 5d1edbaefa
8 changed files with 338 additions and 8 deletions

View file

@ -293,6 +293,7 @@ OBJS = \
src/rommgr.o \
src/rtc.o \
src/savestate.o \
src/scp.cpp \
src/scsi.o \
src/statusline.o \
src/traps.o \

View file

@ -297,6 +297,7 @@
<ClCompile Include="..\..\src\rommgr.cpp" />
<ClCompile Include="..\..\src\rtc.cpp" />
<ClCompile Include="..\..\src\savestate.cpp" />
<ClCompile Include="..\..\src\scp.cpp" />
<ClCompile Include="..\..\src\scsi.cpp" />
<ClCompile Include="..\..\src\sounddep\sound.cpp" />
<ClCompile Include="..\..\src\statusline.cpp" />
@ -409,6 +410,7 @@
<ClInclude Include="..\..\src\include\rtc.h" />
<ClInclude Include="..\..\src\include\rtgmodes.h" />
<ClInclude Include="..\..\src\include\savestate.h" />
<ClInclude Include="..\..\src\include\scp.h" />
<ClInclude Include="..\..\src\include\scsi.h" />
<ClInclude Include="..\..\src\include\statusline.h" />
<ClInclude Include="..\..\src\include\sysdeps.h" />

View file

@ -601,6 +601,9 @@
<ClCompile Include="..\..\src\caps\caps_amiberry.cpp">
<Filter>Source files\caps</Filter>
</ClCompile>
<ClCompile Include="..\..\src\scp.cpp">
<Filter>Source files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\threaddep\thread.h">
@ -990,5 +993,8 @@
<ClInclude Include="..\..\src\include\cputbl.h">
<Filter>Source files\include</Filter>
</ClInclude>
<ClInclude Include="..\..\src\include\scp.h">
<Filter>Source files\include</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -35,6 +35,9 @@
#ifdef CAPS
#include "uae/caps.h"
#endif
#ifdef SCP
#include "scp.h"
#endif
#include "crc32.h"
#include "fsdb.h"
@ -131,7 +134,7 @@ typedef struct {
#define DRIVE_ID_35HD 0xAAAAAAAA
#define DRIVE_ID_525SD 0x55555555 /* 40 track 5.25 drive , kickstart does not recognize this */
typedef enum { ADF_NONE = -1, ADF_NORMAL, ADF_EXT1, ADF_EXT2, ADF_FDI, ADF_IPF, ADF_PCDOS, ADF_KICK, ADF_SKICK } drive_filetype;
typedef enum { ADF_NONE = -1, ADF_NORMAL, ADF_EXT1, ADF_EXT2, ADF_FDI, ADF_IPF, ADF_SCP, ADF_CATWEASEL, ADF_PCDOS, ADF_KICK, ADF_SKICK } drive_filetype;
typedef struct {
struct zfile *diskfile;
struct zfile *writediskfile;
@ -589,6 +592,11 @@ static void drive_image_free(drive *drv)
case ADF_IPF:
#ifdef CAPS
caps_unloadimage(drv - floppy);
#endif
break;
case ADF_SCP:
#ifdef SCP
scp_close(drv - floppy);
#endif
break;
case ADF_FDI:
@ -1094,6 +1102,19 @@ static int drive_insert(drive* drv, struct uae_prefs* p, int dnum, const TCHAR*
drv->num_tracks = num_tracks;
drv->filetype = ADF_IPF;
#endif
#ifdef SCP
}
else if (strncmp((char*)buffer, "SCP", 3) == 0) {
drv->wrprot = true;
if (!scp_open(drv->diskfile, drv - floppy, &num_tracks)) {
zfile_fclose(drv->diskfile);
drv->diskfile = 0;
return 0;
}
drv->num_tracks = num_tracks;
drv->filetype = ADF_SCP;
#endif
#ifdef FDI2RAW
}
else if ((drv->fdi = fdi2raw_header(drv->diskfile))) {
@ -1799,8 +1820,12 @@ static void drive_fill_bigbuf(drive * drv, int force)
#ifdef CAPS
caps_loadtrack(drv->bigmfmbuf, drv->tracktiming, drv - floppy, tr, &drv->tracklen, &drv->multi_revolution, &drv->skipoffset, &drv->lastrev, retrytrack);
#endif
}
else if (drv->filetype == ADF_FDI) {
} else if (drv->filetype == ADF_SCP) {
#ifdef SCP
scp_loadtrack(drv->bigmfmbuf, drv->tracktiming, drv - floppy, tr, &drv->tracklen, &drv->multi_revolution, &drv->skipoffset, &drv->lastrev, retrytrack);
#endif
} else if (drv->filetype == ADF_FDI) {
#ifdef FDI2RAW
fdi2raw_loadtrack(drv->fdi, drv->bigmfmbuf, drv->tracktiming, tr, &drv->tracklen, &drv->indexoffset, &drv->multi_revolution, 1);
@ -1810,17 +1835,14 @@ static void drive_fill_bigbuf(drive * drv, int force)
else if (ti->type == TRACK_PCDOS) {
decode_pcdos(drv);
}
else if (ti->type == TRACK_AMIGADOS) {
decode_amigados(drv);
}
else if (ti->type == TRACK_DISKSPARE) {
decode_diskspare(drv);
}
else if (ti->type == TRACK_NONE) {
@ -2784,6 +2806,11 @@ static void fetchnextrevolution(drive *drv)
case ADF_IPF:
#ifdef CAPS
caps_loadrevolution(drv->bigmfmbuf, drv->tracktiming, drv - floppy, drv->cyl * 2 + side, &drv->tracklen, &drv->lastrev, drv->track_access_done);
#endif
break;
case ADF_SCP:
#ifdef SCP
scp_loadrevolution(drv->bigmfmbuf, drv - floppy, drv->tracktiming, &drv->tracklen);
#endif
break;
case ADF_FDI:

16
src/include/scp.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef UAE_SCP_H
#define UAE_SCP_H
#include "uae/types.h"
int scp_open(struct zfile *zf, int drv, int *num_tracks);
void scp_close(int drv);
int scp_loadtrack(
uae_u16 *mfmbuf, uae_u16 *tracktiming, int drv,
int track, int *tracklength, int *multirev,
int *gapoffset, int *nextrev, bool setrev);
void scp_loadrevolution(
uae_u16 *mfmbuf, int drv, uae_u16 *tracktiming,
int *tracklength);
#endif /* UAE_SCP_H */

View file

@ -62,7 +62,7 @@
#define UAEGFX_INTERNAL /* built-in libs:picasso96/uaegfx.card */
#define BSDSOCKET /* bsdsocket.library emulation */
#define CAPS /* CAPS-image support */
/* #define SCP */ /* SuperCardPro */
#define SCP /* SuperCardPro */
#define FDI2RAW /* FDI 1.0 and 2.x image support */
/* #define AVIOUTPUT */ /* Avioutput support */
/* #define PROWIZARD */ /* Pro-Wizard module ripper */

276
src/scp.cpp Normal file
View file

@ -0,0 +1,276 @@
/*
*
* Support for reading .SCP (Supercard Pro) disk flux dumps.
*
* By Keir Fraser in 2014.
*
* This file is free and unencumbered software released into the public domain.
* For more information, please refer to <http://unlicense.org/>
*/
#include "sysconfig.h"
#include "sysdeps.h"
#include "scp.h"
#include "zfile.h"
#include "gui.h"
#include "uae.h"
//#include "uae/endian.h"
#include <stdint.h>
#define MAX_REVS 5
enum pll_mode {
PLL_fixed_clock, /* Fixed clock, snap phase to flux transitions. */
PLL_variable_clock, /* Variable clock, snap phase to flux transitions. */
PLL_authentic /* Variable clock, do not snap phase to flux transition. */
};
struct scpdrive {
struct zfile *zf;
/* Current track number. */
unsigned int track;
/* Raw track data. */
uint16_t *dat;
unsigned int datsz;
unsigned int revs; /* stored disk revolutions */
unsigned int dat_idx; /* current index into dat[] */
unsigned int index_pos; /* next index offset */
unsigned int nr_index;
unsigned int index_off[MAX_REVS]; /* data offsets of each index */
/* Accumulated read latency in nanosecs. */
uint64_t latency;
/* Flux-based streams: Authentic emulation of FDC PLL behaviour? */
enum pll_mode pll_mode;
/* Flux-based streams. */
int flux; /* Nanoseconds to next flux reversal */
int clock, clock_centre; /* Clock base value in nanoseconds */
unsigned int clocked_zeros;
};
static struct scpdrive drive[4];
#define CLOCK_CENTRE 2000 /* 2000ns = 2us */
#define CLOCK_MAX_ADJ 10 /* +/- 10% adjustment */
#define CLOCK_MIN(_c) (((_c) * (100 - CLOCK_MAX_ADJ)) / 100)
#define CLOCK_MAX(_c) (((_c) * (100 + CLOCK_MAX_ADJ)) / 100)
#define SCK_NS_PER_TICK (25u)
int scp_open(struct zfile *zf, int drv, int *num_tracks)
{
struct scpdrive *d = &drive[drv];
uint8_t header[0x10] = { 0 };
scp_close(drv);
zfile_fread(header, sizeof(header), 1, zf);
if (memcmp(header, "SCP", 3) != 0) {
write_log(_T("SCP file header missing\n"));
return 0;
}
if (header[5] == 0) {
write_log(_T("SCP file has invalid revolution count (%u)\n"), header[5]);
return 0;
}
if (header[9] != 0 && header[9] != 16) {
write_log(_T("SCP file has unsupported bit cell time width (%u)\n"),
header[9]);
return 0;
}
d->zf = zf;
d->revs = min((int)header[5], MAX_REVS);
*num_tracks = header[7] + 1;
return 1;
}
void scp_close(int drv)
{
struct scpdrive *d = &drive[drv];
if (!d->revs)
return;
xfree(d->dat);
memset(d, 0, sizeof(*d));
}
int scp_loadtrack(
uae_u16 *mfmbuf, uae_u16 *tracktiming, int drv,
int track, int *tracklength, int *multirev,
int *gapoffset, int *nextrev, bool setrev)
{
struct scpdrive *d = &drive[drv];
uint8_t trk_header[4];
uint32_t longwords[3];
unsigned int rev, trkoffset[MAX_REVS];
uint32_t hdr_offset, tdh_offset;
*multirev = 1;
*gapoffset = -1;
xfree(d->dat);
d->dat = NULL;
d->datsz = 0;
hdr_offset = 0x10 + track*sizeof(uint32_t);
zfile_fseek(d->zf, hdr_offset, SEEK_SET);
zfile_fread(longwords, sizeof(uint32_t), 1, d->zf);
tdh_offset = le32toh(longwords[0]);
zfile_fseek(d->zf, tdh_offset, SEEK_SET);
zfile_fread(trk_header, sizeof(trk_header), 1, d->zf);
if (memcmp(trk_header, "TRK", 3) != 0)
return 0;
if (trk_header[3] != track)
return 0;
for (rev = 0 ; rev < d->revs ; rev++) {
zfile_fread(longwords, sizeof(longwords), 1, d->zf);
trkoffset[rev] = tdh_offset + le32toh(longwords[2]);
d->index_off[rev] = le32toh(longwords[1]);
d->datsz += d->index_off[rev];
}
d->dat = xmalloc(uint16_t, d->datsz * sizeof(d->dat[0]));
d->datsz = 0;
for (rev = 0 ; rev < d->revs ; rev++) {
zfile_fseek(d->zf, trkoffset[rev], SEEK_SET);
zfile_fread(&d->dat[d->datsz],
d->index_off[rev] * sizeof(d->dat[0]), 1,
d->zf);
d->datsz += d->index_off[rev];
d->index_off[rev] = d->datsz;
}
d->track = track;
d->pll_mode = PLL_authentic;
d->dat_idx = 0;
d->index_pos = d->index_off[0];
d->clock = d->clock_centre = CLOCK_CENTRE;
d->nr_index = 0;
d->flux = 0;
d->clocked_zeros = 0;
scp_loadrevolution(mfmbuf, drv, tracktiming, tracklength);
return 1;
}
static int scp_next_flux(struct scpdrive *d)
{
uint32_t val = 0, flux, t;
for (;;) {
if (d->dat_idx >= d->index_pos) {
uint32_t rev = d->nr_index++ % d->revs;
d->index_pos = d->index_off[rev];
d->dat_idx = rev ? d->index_off[rev-1] : 0;
return -1;
}
t = be16toh(d->dat[d->dat_idx++]);
if (t == 0) { /* overflow */
val += 0x10000;
continue;
}
val += t;
break;
}
flux = val * SCK_NS_PER_TICK;
return (int)flux;
}
static int flux_next_bit(struct scpdrive *d)
{
int new_flux;
while (d->flux < (d->clock/2)) {
if ((new_flux = scp_next_flux(d)) == -1)
return -1;
d->flux += new_flux;
d->clocked_zeros = 0;
}
d->latency += d->clock;
d->flux -= d->clock;
if (d->flux >= (d->clock/2)) {
d->clocked_zeros++;
return 0;
}
if (d->pll_mode != PLL_fixed_clock) {
/* PLL: Adjust clock frequency according to phase mismatch. */
if ((d->clocked_zeros >= 1) && (d->clocked_zeros <= 3)) {
/* In sync: adjust base clock by 10% of phase mismatch. */
int diff = d->flux / (int)(d->clocked_zeros + 1);
d->clock += diff / 10;
} else {
/* Out of sync: adjust base clock towards centre. */
d->clock += (d->clock_centre - d->clock) / 10;
}
/* Clamp the clock's adjustment range. */
d->clock = max(CLOCK_MIN(d->clock_centre),
min(CLOCK_MAX(d->clock_centre), d->clock));
} else {
d->clock = d->clock_centre;
}
/* Authentic PLL: Do not snap the timing window to each flux transition. */
new_flux = (d->pll_mode == PLL_authentic) ? d->flux / 2 : 0;
d->latency += d->flux - new_flux;
d->flux = new_flux;
return 1;
}
void scp_loadrevolution(
uae_u16 *mfmbuf, int drv, uae_u16 *tracktiming,
int *tracklength)
{
struct scpdrive *d = &drive[drv];
uint64_t prev_latency;
uint32_t av_latency;
unsigned int i, j;
int b;
d->latency = prev_latency = 0;
for (i = 0; (b = flux_next_bit(d)) != -1; i++) {
if ((i & 15) == 0)
mfmbuf[i>>4] = 0;
if (b)
mfmbuf[i>>4] |= 0x8000u >> (i&15);
if ((i & 7) == 7) {
tracktiming[i>>3] = d->latency - prev_latency;
prev_latency = d->latency;
}
}
if (i & 7)
tracktiming[i>>3] = ((d->latency - prev_latency) * 8) / (i & 7);
av_latency = prev_latency / (i>>3);
for (j = 0; j < (i+7)>>3; j++)
tracktiming[j] = ((uint32_t)tracktiming[j] * 1000u) / av_latency;
*tracklength = i;
}

View file

@ -250,7 +250,7 @@ static bool checkwrite (struct zfile *zf, int *retcode)
}
static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00};
static const TCHAR *diskimages[] = { _T("adf"), _T("adz"), _T("ipf"), _T("scp"), _T("fdi"), _T("dms"), _T("wrp"), _T("dsq"), _T("pkd"), _T("ima"), 0 };
static const TCHAR* diskimages[] = { _T("adf"), _T("adz"), _T("ipf"), _T("scp"), _T("fdi"), _T("dms"), _T("wrp"), _T("dsq"), _T("pkd"), _T("ima"), 0 };
int zfile_gettype (struct zfile *z)
{
@ -292,6 +292,8 @@ int zfile_gettype (struct zfile *z)
return ZFILE_DISKIMAGE;
if (!memcmp (buf, "CAPS", 4))
return ZFILE_DISKIMAGE;
if (!memcmp(buf, "SCP", 3))
return ZFILE_DISKIMAGE;
if (!memcmp (buf, "UAE--ADF", 8))
return ZFILE_DISKIMAGE;
if (!memcmp (buf, "UAE-1ADF", 8))