summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2014-04-12 20:20:11 +0000
committer R. Belmont <rb6502@users.noreply.github.com>2014-04-12 20:20:11 +0000
commit4507757178a357092571e36163824ead06178d56 (patch)
treecba9d64f76d0d47f9e20cf215cdb7011e3efb0b3 /src/lib
parentbef699950a516c3b1f00947f5b3c4ac3dee9e4cb (diff)
(MESS) Apple II: implemented cycle-exact Disk II floppy controller using the modern floppy subsystem. [O. Galibert, R. Belmont]
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/formats/ap2_dsk.c223
-rw-r--r--src/lib/formats/ap2_dsk.h2
2 files changed, 158 insertions, 67 deletions
diff --git a/src/lib/formats/ap2_dsk.c b/src/lib/formats/ap2_dsk.c
index 73f70aa1764..82599ef41cc 100644
--- a/src/lib/formats/ap2_dsk.c
+++ b/src/lib/formats/ap2_dsk.c
@@ -520,6 +520,18 @@ LEGACY_FLOPPY_OPTIONS_END
****************************************************************************/
+static const UINT8 dos_skewing[] =
+{
+ 0x00, 0x07, 0x0E, 0x06, 0x0D, 0x05, 0x0C, 0x04,
+ 0x0B, 0x03, 0x0A, 0x02, 0x09, 0x01, 0x08, 0x0F
+};
+
+static const UINT8 prodos_skewing[] =
+{
+ 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x0B,
+ 0x04, 0x0C, 0x05, 0x0D, 0x06, 0x0E, 0x07, 0x0F
+};
+
a2_16sect_format::a2_16sect_format() : floppy_image_format_t()
{
@@ -537,7 +549,7 @@ const char *a2_16sect_format::description() const
const char *a2_16sect_format::extensions() const
{
- return "dsk";
+ return "dsk,do,po";
}
bool a2_16sect_format::supports_save() const
@@ -582,35 +594,103 @@ const floppy_image_format_t::desc_e a2_16sect_format::mac_gcr[] = {
{ END },
};
-
bool a2_16sect_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
{
-/* TODO: rewrite me properly
- UINT8 sector_data[(256)*16];
- memset(sector_data, 0, sizeof(sector_data));
+ m_prodos_order = false;
- desc_s sectors[16];
- int format = 0;
- int pos_data = 0;
+ int fpos = 0;
+ for(int track=0; track < 35; track++) {
+ UINT32 track_data[51090*2];
+ UINT8 sector_data[256*16];
+ int offset = 0;
- int head_count = 1;
+ io_generic_read(io, sector_data, fpos, 256*16);
- for(int track=0; track < 35; track++) {
- for(int head=0; head < head_count; head++) {
- for(int si=0; si<16; si++) {
- UINT8 *data = sector_data + (256)*si;
- sectors[si].data = data;
- sectors[si].size = 256;
- sectors[si].sector_id = si;
- sectors[si].sector_info = format;
- io_generic_read(io, data, pos_data, 256);
- pos_data += 256;
- }
- generate_track(mac_gcr, track, head, sectors, 16, 3104*16, image);
- }
- }
- return true;*/
- return false; // I hope that throws an error...
+ if (track == 0 && fpos == 0)
+ {
+ // check ProDOS boot block
+ if (!memcmp("PRODOS", &sector_data[0x103], 6))
+ {
+ m_prodos_order = true;
+ } // check SOS boot block
+ else if (!memcmp("SOS BOOT", &sector_data[0x3], 8))
+ {
+ m_prodos_order = true;
+ } // check Apple II Pascal
+ else if (!memcmp("SYSTEM.APPLE", &sector_data[0xd7], 12))
+ {
+ unsigned char pascal_block1[4] = { 0x08, 0xa5, 0x0f, 0x29 };
+
+ // Pascal discs can still be DOS order.
+ // Check for the second half of the boot code at 0x100
+ // (which means ProDOS order)
+ if (!memcmp(pascal_block1, &sector_data[0x100], 4))
+ {
+ m_prodos_order = true;
+ }
+ }
+ }
+
+ fpos += 256*16;
+ for(int i=0; i<51; i++)
+ raw_w(track_data, offset, 10, 0x3fc);
+ for(int i=0; i<16; i++) {
+ int sector;
+
+ if (m_prodos_order)
+ {
+ sector = prodos_skewing[i];
+ }
+ else
+ {
+ sector = dos_skewing[i];
+ }
+
+ const UINT8 *sdata = sector_data + 256 * sector;
+ for(int j=0; j<20; j++)
+ raw_w(track_data, offset, 10, 0x3fc);
+ raw_w(track_data, offset, 8, 0xff);
+ raw_w(track_data, offset, 24, 0xd5aa96);
+ raw_w(track_data, offset, 16, gcr4_encode(0xfe));
+ raw_w(track_data, offset, 16, gcr4_encode(track));
+ raw_w(track_data, offset, 16, gcr4_encode(i));
+ raw_w(track_data, offset, 16, gcr4_encode(0xfe ^ track ^ i));
+ raw_w(track_data, offset, 24, 0xdeaaeb);
+
+ for(int j=0; j<4; j++)
+ raw_w(track_data, offset, 10, 0x3fc);
+
+ raw_w(track_data, offset, 9, 0x01fe);
+ raw_w(track_data, offset, 24, 0xd5aaad);
+
+ UINT8 pval = 0x00;
+ for(int i=0; i<342; i++) {
+ UINT8 nval;
+ if(i >= 0x56)
+ nval = sdata[i - 0x56] >> 2;
+ else {
+ nval =
+ ((sdata[i+0x00] & 0x01) << 1) |
+ ((sdata[i+0x00] & 0x02) >> 1) |
+ ((sdata[i+0x56] & 0x01) << 3) |
+ ((sdata[i+0x56] & 0x02) << 1);
+ if(i < 256-0xac)
+ nval |=
+ ((sdata[i+0xac] & 0x01) << 5) |
+ ((sdata[i+0xac] & 0x02) << 3);
+ }
+ raw_w(track_data, offset, 8, translate6[nval ^ pval]);
+ pval = nval;
+ }
+ raw_w(track_data, offset, 8, translate6[pval]);
+ raw_w(track_data, offset, 24, 0xdeaaeb);
+ }
+ raw_w(track_data, offset, 4, 0xff);
+ assert(offset == 51090);
+
+ generate_track_from_levels(track, 0, track_data, 51090, 0, image);
+ }
+ return true;
}
UINT8 a2_16sect_format::gb(const UINT8 *buf, int ts, int &pos, int &wrap)
@@ -632,18 +712,19 @@ void a2_16sect_format::update_chk(const UINT8 *data, int size, UINT32 &chk)
{
}
+//#define VERBOSE_SAVE
+
bool a2_16sect_format::save(io_generic *io, floppy_image *image)
{
int g_tracks, g_heads;
int visualgrid[16][35]; // visualizer grid, cleared/initialized below
+
// lenient addr check: if unset, only accept an addr mark if the checksum was good
// if set, accept an addr mark if the track and sector values are both sane
#undef LENIENT_ADDR_CHECK
// if set, use the old, not as robust logic for choosing which copy of a decoded sector to write
// to the resulting image if the sector has a bad checksum and/or postamble
#undef USE_OLD_BEST_SECTOR_PRIORITY
-// select a sector order for resulting file: 0 = logical, 1 = dos3.3, 2 = prodos
-#define SECTOR_ORDER 1
// nothing found
#define NOTFOUND 0
// address mark was found
@@ -667,36 +748,43 @@ bool a2_16sect_format::save(io_generic *io, floppy_image *image)
int pos_data = 0;
- for(int track=0; track < 70; track+=2) {
+ for(int track=0; track < 35; track++) {
UINT8 sectdata[(256)*16];
memset(sectdata, 0, sizeof(sectdata));
int nsect = 16;
- UINT8 buf[130000]; // originally 13000, multiread dfi disks need larger
+ UINT8 buf[10000]; // normal is 51090 cells, e.g. 6387 bytes, add 50% and round up for denser than normal disks
int ts;
-//fprintf(stderr,"DEBUG: a2_16sect_format::save() about to generate bitstream from physical track %d (logical %d)...", track, track/2);
- //~332 samples per cell, times 3+8+3 (14) for address mark, 24 for sync, 3+343+3 (349) for data mark, 24 for sync is around 743, near 776 expected
- generate_bitstream_from_track(track, head, 200000000/((3004*nsect*6)/2), buf, ts, image); // 3104 needs tweaking
-//fprintf(stderr,"done.\n");
+ #ifdef VERBOSE_SAVE
+ fprintf(stderr,"DEBUG: a2_16sect_format::save() about to generate bitstream from track %d...", track);
+ #endif
+ generate_bitstream_from_track(track, head, 3915, buf, ts, image);
+ #ifdef VERBOSE_SAVE
+ fprintf(stderr,"done.\n");
+ #endif
int pos = 0;
int wrap = 0;
int hb = 0;
int dosver = 0; // apple dos version; 0 = >=3.3, 1 = <3.3
for(;;) {
UINT8 v = gb(buf, ts, pos, wrap);
- if(v == 0xff)
+ if(v == 0xff) {
hb = 1;
- else if(hb == 1 && v == 0xd5)
+ }
+ else if(hb == 1 && v == 0xd5){
hb = 2;
- else if(hb == 2 && v == 0xaa)
+ }
+ else if(hb == 2 && v == 0xaa) {
hb = 3;
- else if(hb == 3 && ((v == 0x96) || (v == 0xab))) { // 0x96 = dos 3.3/16sec, 0xab = dos 3.21 and below/13sec
+ }
+ else if(hb == 3 && ((v == 0x96) || (v == 0xab))) { // 0x96 = dos 3.3/16sec, 0xab = dos 3.21 and below/13sec
hb = 4;
if (v == 0xab) dosver = 1;
}
- else
+ else
hb = 0;
if(hb == 4) {
+ printf("hb = 4\n");
UINT8 h[11];
for(int i=0; i<11; i++)
h[i] = gb(buf, ts, pos, wrap);
@@ -706,15 +794,17 @@ bool a2_16sect_format::save(io_generic *io, floppy_image *image)
UINT8 se = gcr4_decode(h[4],h[5]);
UINT8 chk = gcr4_decode(h[6],h[7]);
UINT32 post = (h[8]<<16)|(h[9]<<8)|h[10];
+ #ifdef VERBOSE_SAVE
printf("Address Mark:\tVolume %d, Track %d, Sector %2d, Checksum %02X: %s, Postamble %03X: %s\n", vl, tr, se, chk, (chk ^ vl ^ tr ^ se)==0?"OK":"BAD", post, (post&0xFFFF00)==0xDEAA00?"OK":"BAD");
+ #endif
// sanity check
- if (tr == track/2 && se < nsect) {
- visualgrid[se][track/2] |= ADDRFOUND;
- visualgrid[se][track/2] |= ((chk ^ vl ^ tr ^ se)==0)?ADDRGOOD:0;
+ if (tr == track && se < nsect) {
+ visualgrid[se][track] |= ADDRFOUND;
+ visualgrid[se][track] |= ((chk ^ vl ^ tr ^ se)==0)?ADDRGOOD:0;
#ifdef LENIENT_ADDR_CHECK
- if ((visualgrid[se][track/2] & ADDRFOUND) == ADDRFOUND) {
+ if ((visualgrid[se][track] & ADDRFOUND) == ADDRFOUND) {
#else
- if ((visualgrid[se][track/2] & ADDRGOOD) == ADDRGOOD) {
+ if ((visualgrid[se][track] & ADDRGOOD) == ADDRGOOD) {
#endif
int opos = pos;
int owrap = wrap;
@@ -733,26 +823,21 @@ bool a2_16sect_format::save(io_generic *io, floppy_image *image)
hb = 0;
}
if((hb == 4)&&(dosver == 0)) {
- visualgrid[se][track/2] |= DATAFOUND;
- int sector_translate[16] = {
-#if SECTOR_ORDER == 0
- // logical order (0-15)
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
-#elif SECTOR_ORDER == 1
- // DOS order (*.do)
- 0x00, 0x07, 0x0E, 0x06, 0x0D, 0x05, 0x0C, 0x04,
- 0x0B, 0x03, 0x0A, 0x02, 0x09, 0x01, 0x08, 0x0F
-#elif SECTOR_ORDER == 2
- // prodos order (*.po)
- 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x0B,
- 0x04, 0x0C, 0x05, 0x0D, 0x06, 0x0E, 0x07, 0x0F
-#endif
- };
- UINT8 *dest = sectdata+(256)*sector_translate[se];
+ visualgrid[se][track] |= DATAFOUND;
+ UINT8 *dest;
UINT8 data[0x157];
UINT32 dpost = 0;
UINT8 c = 0;
+
+ if (m_prodos_order)
+ {
+ dest = sectdata+(256)*prodos_skewing[se];
+ }
+ else
+ {
+ dest = sectdata+(256)*dos_skewing[se];
+ }
+
// first read in sector and decode to 6bit form
for(int i=0; i<0x156; i++) {
data[i] = gcr6bw_tb[gb(buf, ts, pos, wrap)] ^ c;
@@ -780,16 +865,16 @@ bool a2_16sect_format::save(io_generic *io, floppy_image *image)
// if it is set we don't want to overwrite a guaranteed good read with a bad one
// if past read had a bad checksum or bad postamble...
#ifndef USE_OLD_BEST_SECTOR_PRIORITY
- if (((visualgrid[se][track/2]&DATAGOOD)==0)||((visualgrid[se][track/2]&DATAPOST)==0)) {
+ if (((visualgrid[se][track]&DATAGOOD)==0)||((visualgrid[se][track]&DATAPOST)==0)) {
// if the current read is good, and postamble is good, write it in, no matter what.
// if the current read is good and the current postamble is bad, write it in unless the postamble was good before
// if the current read is bad and the current postamble is good and the previous read had neither good, write it in
// if the current read isn't good and neither is the postamble but nothing better
// has been written before, write it anyway.
if ( ((data[0x156] == c) && (dpost&0xFFFF00)==0xDEAA00) ||
- (((data[0x156] == c) && (dpost&0xFFFF00)!=0xDEAA00) && ((visualgrid[se][track/2]&DATAPOST)==0)) ||
- (((data[0x156] != c) && (dpost&0xFFFF00)==0xDEAA00) && (((visualgrid[se][track/2]&DATAGOOD)==0)&&(visualgrid[se][track/2]&DATAPOST)==0)) ||
- (((data[0x156] != c) && (dpost&0xFFFF00)!=0xDEAA00) && (((visualgrid[se][track/2]&DATAGOOD)==0)&&(visualgrid[se][track/2]&DATAPOST)==0))
+ (((data[0x156] == c) && (dpost&0xFFFF00)!=0xDEAA00) && ((visualgrid[se][track]&DATAPOST)==0)) ||
+ (((data[0x156] != c) && (dpost&0xFFFF00)==0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0)) ||
+ (((data[0x156] != c) && (dpost&0xFFFF00)!=0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0))
) {
for(int i=0x56; i<0x156; i++) {
UINT8 dv = data[i];
@@ -798,7 +883,7 @@ bool a2_16sect_format::save(io_generic *io, floppy_image *image)
}
}
#else
- if ((visualgrid[se][track/2]&DATAGOOD)==0) {
+ if ((visualgrid[se][track]&DATAGOOD)==0) {
for(int i=0x56; i<0x156; i++) {
UINT8 dv = data[i];
*dest++ = dv;
@@ -806,10 +891,12 @@ bool a2_16sect_format::save(io_generic *io, floppy_image *image)
}
#endif
// do some checking
+ #ifdef VERBOSE_SAVE
if ((data[0x156] != c) || (dpost&0xFFFF00)!=0xDEAA00)
fprintf(stderr,"Data Mark:\tChecksum xpctd %d found %d: %s, Postamble %03X: %s\n", data[0x156], c, (data[0x156]==c)?"OK":"BAD", dpost, (dpost&0xFFFF00)==0xDEAA00?"OK":"BAD");
- if (data[0x156] == c) visualgrid[se][track/2] |= DATAGOOD;
- if ((dpost&0xFFFF00)==0xDEAA00) visualgrid[se][track/2] |= DATAPOST;
+ #endif
+ if (data[0x156] == c) visualgrid[se][track] |= DATAGOOD;
+ if ((dpost&0xFFFF00)==0xDEAA00) visualgrid[se][track] |= DATAPOST;
} else if ((hb == 4)&&(dosver == 1)) {
fprintf(stderr,"ERROR: We don't handle dos sectors below 3.3 yet!\n");
} else {
@@ -832,6 +919,7 @@ bool a2_16sect_format::save(io_generic *io, floppy_image *image)
//printf("\n");
}
// display a little table of which sectors decoded ok
+ #ifdef VERBOSE_SAVE
int total_good = 0;
for (int j = 0; j < 35; j++) {
printf("T%2d: ",j);
@@ -848,6 +936,7 @@ bool a2_16sect_format::save(io_generic *io, floppy_image *image)
printf("\n");
}
printf("Total Good Sectors: %d\n", total_good);
+ #endif
return true;
}
diff --git a/src/lib/formats/ap2_dsk.h b/src/lib/formats/ap2_dsk.h
index 821ebbafdbe..79ba4a15754 100644
--- a/src/lib/formats/ap2_dsk.h
+++ b/src/lib/formats/ap2_dsk.h
@@ -51,6 +51,8 @@ private:
UINT8 gb(const UINT8 *buf, int ts, int &pos, int &wrap);
void update_chk(const UINT8 *data, int size, UINT32 &chk);
+
+ bool m_prodos_order;
};
extern const floppy_format_type FLOPPY_A216S_FORMAT;