Added WOZ 2 support.
It will read/write WOZ 2, though internally it doesn't obey the "optimal bit timing" value yet; support for that is coming. :-) It will also silently upconvert WOZ 1 images, though that will only matter if the disk is writable and is written to.
This commit is contained in:
parent
31d2453ee7
commit
63762cef81
1
Makefile
1
Makefile
|
@ -111,6 +111,7 @@ OBJS = \
|
|||
obj/charset.o \
|
||||
obj/crc32.o \
|
||||
obj/dis65c02.o \
|
||||
obj/fileio.o \
|
||||
obj/firmware.o \
|
||||
obj/floppydrive.o \
|
||||
obj/harddrive.o \
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
//
|
||||
// fileio.cpp: File handling (mainly disk related)
|
||||
//
|
||||
// by James Hammons
|
||||
// (C) 2019 Underground Software
|
||||
//
|
||||
|
||||
#include "fileio.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "crc32.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
uint8_t woz1Header[8] = { 'W', 'O', 'Z', '1', 0xFF, 0x0A, 0x0D, 0x0A };
|
||||
uint8_t woz2Header[8] = { 'W', 'O', 'Z', '2', 0xFF, 0x0A, 0x0D, 0x0A };
|
||||
uint8_t standardTMAP[160] = {
|
||||
0, 0, 0xFF, 1, 1, 1, 0xFF, 2, 2, 2, 0xFF, 3, 3, 3, 0xFF, 4, 4, 4, 0xFF,
|
||||
5, 5, 5, 0xFF, 6, 6, 6, 0xFF, 7, 7, 7, 0xFF, 8, 8, 8, 0xFF, 9, 9, 9, 0xFF,
|
||||
10, 10, 10, 0xFF, 11, 11, 11, 0xFF, 12, 12, 12, 0xFF, 13, 13, 13, 0xFF,
|
||||
14, 14, 14, 0xFF, 15, 15, 15, 0xFF, 16, 16, 16, 0xFF, 17, 17, 17, 0xFF,
|
||||
18, 18, 18, 0xFF, 19, 19, 19, 0xFF, 20, 20, 20, 0xFF, 21, 21, 21, 0xFF,
|
||||
22, 22, 22, 0xFF, 23, 23, 23, 0xFF, 24, 24, 24, 0xFF, 25, 25, 25, 0xFF,
|
||||
26, 26, 26, 0xFF, 27, 27, 27, 0xFF, 28, 28, 28, 0xFF, 29, 29, 29, 0xFF,
|
||||
30, 30, 30, 0xFF, 31, 31, 31, 0xFF, 32, 32, 32, 0xFF, 33, 33, 33, 0xFF,
|
||||
34, 34, 34, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Note that size *must* be a valid pointer, otherwise this will go BOOM
|
||||
//
|
||||
uint8_t * ReadFile(const char * filename, uint32_t * size)
|
||||
{
|
||||
FILE * fp = fopen(filename, "rb");
|
||||
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
*size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
uint8_t * buffer = (uint8_t *)malloc(*size);
|
||||
fread(buffer, 1, *size, fp);
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// This initializes the WOZ type 2 headers
|
||||
//
|
||||
void InitWOZ2Headers(WOZ2 & woz)
|
||||
{
|
||||
// Set up header (leave CRC as 0 for now)
|
||||
memcpy(woz.magic, woz2Header, 8);
|
||||
woz.crc32 = 0;
|
||||
|
||||
// INFO header
|
||||
memcpy(woz.infoTag, "INFO", 4);
|
||||
woz.infoSize = Uint32LE(60);
|
||||
woz.infoVersion = 2;
|
||||
woz.diskType = 1;
|
||||
woz.writeProtected = 0;
|
||||
woz.synchronized = 0;
|
||||
woz.cleaned = 1;
|
||||
memset(woz.creator, ' ', 32);
|
||||
memcpy(woz.creator, "Apple2 emulator v1.0.0", 22);
|
||||
woz.diskSides = 1;
|
||||
woz.bootSectorFmt = 1;
|
||||
woz.optimalBitTmg = 32;
|
||||
woz.largestTrack = Uint16LE(13);
|
||||
|
||||
// TMAP header
|
||||
memcpy(woz.tmapTag, "TMAP", 4);
|
||||
woz.tmapSize = Uint32LE(160);
|
||||
|
||||
// TRKS header
|
||||
memcpy(woz.trksTag, "TRKS", 4);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// This is used mainly to initialize blank disks and upconvert non-WOZ disks
|
||||
//
|
||||
uint8_t * InitWOZ(uint32_t * pSize/*= NULL*/)
|
||||
{
|
||||
uint32_t size = 1536 + (35 * (13 * 512));
|
||||
uint8_t * data = (uint8_t *)malloc(size);
|
||||
WOZ2 & woz = *((WOZ2 *)data);
|
||||
|
||||
// Zero out WOZ image in memory
|
||||
memset(&woz, 0, size);
|
||||
|
||||
// Set up headers
|
||||
InitWOZ2Headers(woz);
|
||||
memcpy(woz.tmap, standardTMAP, 160);
|
||||
woz.trksSize = Uint32LE(35 * (13 * 512));
|
||||
|
||||
for(int i=0; i<35; i++)
|
||||
{
|
||||
woz.track[i].startingBlock = Uint16LE(3 + (i * 13));
|
||||
woz.track[i].blockCount = Uint16LE(13);
|
||||
woz.track[i].bitCount = Uint32LE(51200);
|
||||
}
|
||||
|
||||
// META header (how to handle? prolly with a separate pointer)
|
||||
|
||||
if (pSize)
|
||||
*pSize = size;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
uint8_t * UpconvertWOZ1ToWOZ2(uint8_t * woz1Data, uint32_t woz1Size, uint32_t * newSize)
|
||||
{
|
||||
WOZ1 & woz1 = *((WOZ1 *)woz1Data);
|
||||
|
||||
// First, figure out how large the new structure will be in comparison to
|
||||
// the old one...
|
||||
uint32_t numTracks = woz1.trksSize / sizeof(WOZ1Track);
|
||||
uint32_t metadataSize = woz1Size - (Uint32LE(woz1.trksSize) + 256);
|
||||
|
||||
// N.B.: # of blocks for each track will *always* be <= 13 for WOZ1
|
||||
*newSize = 0x600 + (numTracks * (13 * 512)) + metadataSize;
|
||||
uint8_t * woz2Data = (uint8_t *)malloc(*newSize);
|
||||
memset(woz2Data, 0, *newSize);
|
||||
|
||||
WOZ2 & woz2 = *((WOZ2 *)woz2Data);
|
||||
InitWOZ2Headers(woz2);
|
||||
|
||||
// Copy parts of INFO & TMAP chunks over
|
||||
memcpy(&woz2.diskType, &woz1.diskType, 36);
|
||||
memcpy(woz2.tmap, woz1.tmap, 160);
|
||||
//note: should check the CRC32 integrity 1st before attempting to recreate it here... (the CRC is written out when it's saved anyway, so no need to fuck with this right now)
|
||||
woz2.crc32 = 0;
|
||||
woz2.trksSize = Uint32LE(numTracks * (13 * 512));
|
||||
|
||||
// Finally, copy over the tracks
|
||||
for(uint32_t i=0; i<numTracks; i++)
|
||||
{
|
||||
woz2.track[i].startingBlock = Uint16LE(3 + (i * 13));
|
||||
woz2.track[i].blockCount = Uint16LE(13);
|
||||
woz2.track[i].bitCount = woz1.track[i].bitCount;
|
||||
memcpy(woz2Data + ((3 + (i * 13)) * 512), woz1.track[i].bits, 6646);
|
||||
}
|
||||
|
||||
// Finally, copy over the metadata
|
||||
memcpy(woz2Data + Uint32LE(woz2.trksSize) + 0x600,
|
||||
woz1Data + Uint32LE(woz1.trksSize) + 0x100, metadataSize);
|
||||
|
||||
return woz2Data;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Check WOZ type on the passed in contents (file loaded elsewhere).
|
||||
// Returns type of WOZ if successful, 0 if not.
|
||||
//
|
||||
uint8_t CheckWOZType(const uint8_t * wozData, uint32_t wozSize)
|
||||
{
|
||||
// Basic sanity checking
|
||||
if ((wozData == NULL) || (wozSize < 8))
|
||||
return 0;
|
||||
|
||||
if (memcmp(wozData, woz1Header, 8) == 0)
|
||||
return 1;
|
||||
else if (memcmp(wozData, woz2Header, 8) == 0)
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Do basic sanity checks on the passed in contents (file loaded elsewhere).
|
||||
// Returns true if successful, false on failure.
|
||||
//
|
||||
bool CheckWOZIntegrity(const uint8_t * wozData, uint32_t wozSize)
|
||||
{
|
||||
WOZ2 & woz = *((WOZ2 *)wozData);
|
||||
uint32_t crc = CRC32(&wozData[12], wozSize - 12);
|
||||
uint32_t wozCRC = Uint32LE(woz.crc32);
|
||||
|
||||
if ((wozCRC != 0) && (wozCRC != crc))
|
||||
{
|
||||
WriteLog("FILEIO: Corrupted data found in WOZ. CRC32: %08X, computed: %08X\n", wozCRC, crc);
|
||||
return false;
|
||||
}
|
||||
else if (wozCRC == 0)
|
||||
WriteLog("FILEIO: Warning--WOZ file has no CRC...\n");
|
||||
|
||||
#if 0 // Need to fix this so it works with both 1 & 2 (works with only 1 ATM)
|
||||
WriteLog("Track map:\n");
|
||||
WriteLog(" 1 1 1 1 1 1 1 1\n");
|
||||
WriteLog("0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.\n");
|
||||
WriteLog("------------------------------------------------------------------------\n");
|
||||
|
||||
for(uint8_t j=0; j<2; j++)
|
||||
{
|
||||
for(uint8_t i=0; i<72; i++)
|
||||
{
|
||||
char buf[64] = "..";
|
||||
buf[0] = buf[1] = '.';
|
||||
|
||||
if (woz.tmap[i] != 0xFF)
|
||||
sprintf(buf, "%02d", woz.tmap[i]);
|
||||
|
||||
WriteLog("%c", buf[j]);
|
||||
}
|
||||
|
||||
WriteLog("\n");
|
||||
}
|
||||
|
||||
WriteLog("\n1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3\n");
|
||||
WriteLog("8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5\n");
|
||||
WriteLog("---------------------------------------------------------------------\n");
|
||||
|
||||
for(uint8_t j=0; j<2; j++)
|
||||
{
|
||||
for(uint8_t i=72; i<141; i++)
|
||||
{
|
||||
char buf[64] = "..";
|
||||
|
||||
if (woz.tmap[i] != 0xFF)
|
||||
sprintf(buf, "%02d", woz.tmap[i]);
|
||||
|
||||
WriteLog("%c", buf[j]);
|
||||
}
|
||||
|
||||
WriteLog("\n");
|
||||
}
|
||||
|
||||
WriteLog("\n");
|
||||
|
||||
uint8_t numTracks = woz.trksSize / sizeof(WOZ1Track);
|
||||
|
||||
// N.B.: Need to check the track in tmap[] to have this tell the correct track... Right now, it doesn't
|
||||
for(uint8_t i=0; i<numTracks; i++)
|
||||
{
|
||||
WriteLog("WOZ: Stream %u: %d bits (packed into %d bytes)\n", i, woz.track[i].bitCount, (woz.track[i].bitCount + 7) / 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
WriteLog("FILEIO: Well formed WOZ file found\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SaveWOZ(const char * filename, WOZ2 * woz, uint32_t size)
|
||||
{
|
||||
// Set up CRC32 before writing
|
||||
woz->crc32 = Uint32LE(CRC32(woz->infoTag, size - 12));
|
||||
|
||||
// META header (skip for now) (actually, should be in the disk[] image already)
|
||||
|
||||
// Finally, write the damn image
|
||||
FILE * file = fopen(filename, "wb");
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
WriteLog("FILEIO: Failed to open image file '%s' for writing...\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
fwrite((uint8_t *)woz, 1, size, file);
|
||||
fclose(file);
|
||||
|
||||
WriteLog("FILEIO: Successfully wrote image file '%s'...\n", filename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
#ifndef __FILEIO_H__
|
||||
#define __FILEIO_H__
|
||||
|
||||
#include <SDL.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// N.B.: All 32/16-bit values are stored in little endian. Which means, to
|
||||
// read/write them safely, we need to use translators as this code may or
|
||||
// may not be compiled on an architecture that supports little endian
|
||||
// natively.
|
||||
|
||||
struct WOZ1Track
|
||||
{
|
||||
uint8_t bits[6646];
|
||||
uint16_t byteCount;
|
||||
uint16_t bitCount;
|
||||
uint16_t splicePoint;
|
||||
uint8_t spliceNibble;
|
||||
uint8_t spliceBitCount;
|
||||
uint16_t reserved;
|
||||
};
|
||||
|
||||
struct WOZMetadata
|
||||
{
|
||||
uint8_t metaTag[4]; // "META"
|
||||
uint32_t metaSize; // Size of the META chunk
|
||||
uint8_t data[]; // Variable length array of metadata
|
||||
};
|
||||
|
||||
struct WOZ1
|
||||
{
|
||||
// Header
|
||||
uint8_t magic[8]; // "WOZ1" $FF $0A $0D $0A
|
||||
uint32_t crc32; // CRC32 of the remaining data in the file
|
||||
|
||||
// INFO chunk
|
||||
uint8_t infoTag[4]; // "INFO"
|
||||
uint32_t infoSize; // Always 60 bytes long
|
||||
uint8_t infoVersion; // Currently 1
|
||||
uint8_t diskType; // 1 = 5 1/4", 2 = 3 1/2"
|
||||
uint8_t writeProtected; // 1 = write protected disk
|
||||
uint8_t synchronized; // 1 = cross-track sync was used during imaging
|
||||
uint8_t cleaned; // 1 = fake bits removed from image
|
||||
uint8_t creator[32]; // Software that made this image, padded with 0x20
|
||||
uint8_t pad1[23]; // Padding to 60 bytes
|
||||
|
||||
// TMAP chunk
|
||||
uint8_t tmapTag[4]; // "TMAP"
|
||||
uint32_t tmapSize; // Always 160 bytes long
|
||||
uint8_t tmap[160]; // Track map, with empty tracks set to $FF
|
||||
|
||||
// TRKS chunk
|
||||
uint8_t trksTag[4]; // "TRKS"
|
||||
uint32_t trksSize; // Varies, depending on # of tracks imaged
|
||||
WOZ1Track track[]; // Variable length array for the track data proper
|
||||
};
|
||||
|
||||
struct WOZTrack2
|
||||
{
|
||||
uint16_t startingBlock; // 512 byte block # where this track starts (relative to the start of the file)
|
||||
uint16_t blockCount; // # of blocks in this track
|
||||
uint32_t bitCount; // # of bits in this track
|
||||
};
|
||||
|
||||
struct WOZ2
|
||||
{
|
||||
// Header
|
||||
uint8_t magic[8]; // "WOZ2" $FF $0A $0D $0A
|
||||
uint32_t crc32; // CRC32 of the remaining data in the file
|
||||
|
||||
// INFO chunk
|
||||
uint8_t infoTag[4]; // "INFO"
|
||||
uint32_t infoSize; // Always 60 bytes long
|
||||
uint8_t infoVersion; // Currently 1
|
||||
uint8_t diskType; // 1 = 5 1/4", 2 = 3 1/2"
|
||||
uint8_t writeProtected; // 1 = write protected disk
|
||||
uint8_t synchronized; // 1 = cross-track sync was used during imaging
|
||||
uint8_t cleaned; // 1 = fake bits removed from image
|
||||
uint8_t creator[32]; // Software that made this image, padded with 0x20
|
||||
uint8_t diskSides; // 5 1/4" disks always have 1 side (v2 from here on)
|
||||
uint8_t bootSectorFmt; // 5 1/4" only (0=unknown, 1=16 sector, 2=13 sector, 3=both)
|
||||
uint8_t optimalBitTmg; // In ticks, standard for 5 1/4" is 32 (4 µs)
|
||||
uint16_t compatibleHW; // Bitfield showing hardware compatibility (1=][, 2=][+, 4=//e (unenh), 8=//c, 16=//e (enh), 32=IIgs, 64=//c+, 128=///, 256=///+)
|
||||
uint16_t requiredRAM; // Minimum size in K, 0=unknown
|
||||
uint16_t largestTrack; // Number of 512 byte blocks used by largest track
|
||||
uint8_t pad1[14]; // Padding to 60 bytes
|
||||
|
||||
// TMAP chunk
|
||||
uint8_t tmapTag[4]; // "TMAP"
|
||||
uint32_t tmapSize; // Always 160 bytes long
|
||||
uint8_t tmap[160]; // Track map, with empty tracks set to $FF
|
||||
|
||||
// TRKS chunk
|
||||
uint8_t trksTag[4]; // "TRKS"
|
||||
uint32_t trksSize; // Varies, depending on # of tracks imaged
|
||||
WOZTrack2 track[160]; // Actual track info (corresponding to TMAP data)
|
||||
uint8_t data[]; // Variable length array for the track data proper
|
||||
};
|
||||
|
||||
// Exported functions
|
||||
uint8_t * ReadFile(const char * filename, uint32_t * size);
|
||||
void InitWOZ2Headers(WOZ2 &);
|
||||
uint8_t * InitWOZ(uint32_t * pSize = NULL);
|
||||
uint8_t * UpconvertWOZ1ToWOZ2(uint8_t * woz1Data, uint32_t woz1Size, uint32_t * newSize);
|
||||
uint8_t CheckWOZType(const uint8_t * wozData, uint32_t wozSize);
|
||||
bool CheckWOZIntegrity(const uint8_t * wozData, uint32_t wozSize);
|
||||
bool SaveWOZ(const char * filename, WOZ2 * woz, uint32_t size);
|
||||
|
||||
// Static in-line functions, for clarity & speed, mostly for reading values out
|
||||
// of the WOZ struct, which stores its data in LE; some for swapping variables
|
||||
static inline uint16_t Uint16LE(uint16_t v)
|
||||
{
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
return ((v & 0xFF) << 8) | ((v & 0xFF00) >> 8);
|
||||
#else
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t Uint32LE(uint32_t v)
|
||||
{
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
return ((v & 0xFF) << 24) | ((v & 0xFF00) << 8)
|
||||
| ((v & 0xFF0000) >> 8) | ((v & 0xFF000000) >> 24);
|
||||
#else
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // __FILEIO_H__
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Apple 2 floppy disk support
|
||||
//
|
||||
// by James Hammons
|
||||
// (c) 2005-2018 Underground Software
|
||||
// (c) 2005-2019 Underground Software
|
||||
//
|
||||
// JLH = James Hammons <jlhamm@acm.org>
|
||||
//
|
||||
|
@ -19,6 +19,7 @@
|
|||
#include <string.h>
|
||||
#include "apple2.h"
|
||||
#include "crc32.h"
|
||||
#include "fileio.h"
|
||||
#include "firmware.h"
|
||||
#include "log.h"
|
||||
#include "mmu.h"
|
||||
|
@ -29,71 +30,32 @@
|
|||
|
||||
enum { IO_MODE_READ, IO_MODE_WRITE };
|
||||
|
||||
// FloppyDrive class variable initialization
|
||||
// Misc. arrays (read only) that are needed
|
||||
|
||||
uint8_t FloppyDrive::doSector[16] = {
|
||||
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF };
|
||||
uint8_t FloppyDrive::poSector[16] = {
|
||||
0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF };
|
||||
uint8_t FloppyDrive::wozHeader[9] = "WOZ1\xFF\x0A\x0D\x0A";
|
||||
uint8_t FloppyDrive::wozHeader2[9] = "WOZ2\xFF\x0A\x0D\x0A";
|
||||
uint8_t FloppyDrive::standardTMAP[141] = {
|
||||
0, 0, 0xFF, 1, 1, 1, 0xFF, 2, 2, 2, 0xFF, 3, 3, 3, 0xFF, 4, 4, 4, 0xFF,
|
||||
5, 5, 5, 0xFF, 6, 6, 6, 0xFF, 7, 7, 7, 0xFF, 8, 8, 8, 0xFF, 9, 9, 9, 0xFF,
|
||||
10, 10, 10, 0xFF, 11, 11, 11, 0xFF, 12, 12, 12, 0xFF, 13, 13, 13, 0xFF,
|
||||
14, 14, 14, 0xFF, 15, 15, 15, 0xFF, 16, 16, 16, 0xFF, 17, 17, 17, 0xFF,
|
||||
18, 18, 18, 0xFF, 19, 19, 19, 0xFF, 20, 20, 20, 0xFF, 21, 21, 21, 0xFF,
|
||||
22, 22, 22, 0xFF, 23, 23, 23, 0xFF, 24, 24, 24, 0xFF, 25, 25, 25, 0xFF,
|
||||
26, 26, 26, 0xFF, 27, 27, 27, 0xFF, 28, 28, 28, 0xFF, 29, 29, 29, 0xFF,
|
||||
30, 30, 30, 0xFF, 31, 31, 31, 0xFF, 32, 32, 32, 0xFF, 33, 33, 33, 0xFF,
|
||||
34, 34, 34, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
uint8_t FloppyDrive::bitMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
|
||||
uint8_t FloppyDrive::sequencerROM[256] = {
|
||||
0x18, 0x18, 0x18, 0x18, 0x0A, 0x0A, 0x0A, 0x0A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x2D, 0x38, 0x2D, 0x38, 0x0A, 0x0A, 0x0A, 0x0A, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
|
||||
0x38, 0x28, 0xD8, 0x08, 0x0A, 0x0A, 0x0A, 0x0A, 0x39, 0x39, 0x39, 0x39, 0x3B, 0x3B, 0x3B, 0x3B,
|
||||
0x48, 0x48, 0xD8, 0x48, 0x0A, 0x0A, 0x0A, 0x0A, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
|
||||
0x58, 0x58, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
|
||||
0x68, 0x68, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68,
|
||||
0x78, 0x78, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
|
||||
0x88, 0x88, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88,
|
||||
0x98, 0x98, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
|
||||
0x29, 0xA8, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
|
||||
0xBD, 0xB8, 0xCD, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xB9, 0xB9, 0xB9, 0xB9, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0x59, 0xC8, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
|
||||
0xD9, 0xA0, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8,
|
||||
0x08, 0xE8, 0xD8, 0xE8, 0x0A, 0x0A, 0x0A, 0x0A, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
|
||||
0xFD, 0xF8, 0xFD, 0xF8, 0x0A, 0x0A, 0x0A, 0x0A, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
|
||||
0x4D, 0xE0, 0xDD, 0xE0, 0x0A, 0x0A, 0x0A, 0x0A, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08
|
||||
static const uint8_t bitMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
|
||||
static const uint8_t sequencerROM[256] = {
|
||||
0x18, 0x18, 0x18, 0x18, 0x0A, 0x0A, 0x0A, 0x0A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x2D, 0x38, 0x2D, 0x38, 0x0A, 0x0A, 0x0A, 0x0A, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
|
||||
0x38, 0x28, 0xD8, 0x08, 0x0A, 0x0A, 0x0A, 0x0A, 0x39, 0x39, 0x39, 0x39, 0x3B, 0x3B, 0x3B, 0x3B,
|
||||
0x48, 0x48, 0xD8, 0x48, 0x0A, 0x0A, 0x0A, 0x0A, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
|
||||
0x58, 0x58, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
|
||||
0x68, 0x68, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68,
|
||||
0x78, 0x78, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
|
||||
0x88, 0x88, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88,
|
||||
0x98, 0x98, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
|
||||
0x29, 0xA8, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
|
||||
0xBD, 0xB8, 0xCD, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xB9, 0xB9, 0xB9, 0xB9, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0x59, 0xC8, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
|
||||
0xD9, 0xA0, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8,
|
||||
0x08, 0xE8, 0xD8, 0xE8, 0x0A, 0x0A, 0x0A, 0x0A, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
|
||||
0xFD, 0xF8, 0xFD, 0xF8, 0x0A, 0x0A, 0x0A, 0x0A, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
|
||||
0x4D, 0xE0, 0xDD, 0xE0, 0x0A, 0x0A, 0x0A, 0x0A, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08
|
||||
};
|
||||
|
||||
char FloppyDrive::nameBuf[MAX_PATH];
|
||||
|
||||
|
||||
// Static in-line functions, for clarity & speed, mostly for reading values out
|
||||
// of the WOZ struct, which stores its data in LE; some for swapping variables
|
||||
static inline uint16_t Uint16LE(uint16_t v)
|
||||
{
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
return ((v & 0xFF) << 8) | ((v & 0xFF00) >> 8);
|
||||
#else
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t Uint32LE(uint32_t v)
|
||||
{
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
return ((v & 0xFF) << 24) | ((v & 0xFF00) << 8)
|
||||
| ((v & 0xFF0000) >> 8) | ((v & 0xFF000000) >> 24);
|
||||
#else
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
static char nameBuf[MAX_PATH];
|
||||
|
||||
|
||||
// Static in-line functions, for clarity & speed, for swapping variables
|
||||
static inline void Swap(uint8_t & a, uint8_t & b)
|
||||
{
|
||||
uint8_t t = a;
|
||||
|
@ -126,23 +88,15 @@ static inline void Swap(uint8_t * & a, uint8_t * & b)
|
|||
}
|
||||
|
||||
|
||||
static inline void Swap(WOZ * & a, WOZ * & b)
|
||||
{
|
||||
WOZ * t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
|
||||
|
||||
// FloppyDrive class implementation...
|
||||
|
||||
FloppyDrive::FloppyDrive(): motorOn(0), activeDrive(0), ioMode(IO_MODE_READ), ioHappened(false)
|
||||
FloppyDrive::FloppyDrive(): motorOn(0), activeDrive(0), ioMode(IO_MODE_READ), ioHappened(false), diskImageReady(false)
|
||||
{
|
||||
phase[0] = phase[1] = 0;
|
||||
headPos[0] = headPos[1] = 0;
|
||||
trackLength[0] = trackLength[1] = 51200;
|
||||
disk[0] = disk[1] = NULL;
|
||||
woz[0] = woz[1] = NULL;
|
||||
// woz[0] = woz[1] = NULL;
|
||||
diskSize[0] = diskSize[1] = 0;
|
||||
diskType[0] = diskType[1] = DT_EMPTY;
|
||||
imageDirty[0] = imageDirty[1] = false;
|
||||
|
@ -153,10 +107,10 @@ FloppyDrive::FloppyDrive(): motorOn(0), activeDrive(0), ioMode(IO_MODE_READ), i
|
|||
FloppyDrive::~FloppyDrive()
|
||||
{
|
||||
if (disk[0])
|
||||
delete[] disk[0];
|
||||
free(disk[0]);
|
||||
|
||||
if (disk[1])
|
||||
delete[] disk[1];
|
||||
free(disk[1]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -172,29 +126,24 @@ bool FloppyDrive::LoadImage(const char * filename, uint8_t driveNum/*= 0*/)
|
|||
|
||||
// Zero out filename, in case it doesn't load
|
||||
imageName[driveNum][0] = 0;
|
||||
//prolly should load EjectImage() first, so we don't have to dick around with crap
|
||||
uint8_t * buffer = ReadFile(filename, &diskSize[driveNum]);
|
||||
|
||||
FILE * fp = fopen(filename, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
if (buffer == NULL)
|
||||
{
|
||||
WriteLog("FLOPPY: Failed to open image file '%s' for reading...\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (disk[driveNum])
|
||||
delete[] disk[driveNum];
|
||||
free(disk[driveNum]);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
diskSize[driveNum] = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
disk[driveNum] = new uint8_t[diskSize[driveNum]];
|
||||
woz[driveNum] = (WOZ *)disk[driveNum];
|
||||
fread(disk[driveNum], 1, diskSize[driveNum], fp);
|
||||
disk[driveNum] = buffer;
|
||||
|
||||
fclose(fp);
|
||||
//printf("Read disk image: %u bytes.\n", diskSize);
|
||||
diskImageReady = false;
|
||||
DetectImageType(filename, driveNum);
|
||||
strcpy(imageName[driveNum], filename);
|
||||
diskImageReady = true;
|
||||
|
||||
WriteLog("FLOPPY: Loaded image '%s' for drive #%u.\n", filename, driveNum);
|
||||
|
||||
|
@ -204,8 +153,6 @@ bool FloppyDrive::LoadImage(const char * filename, uint8_t driveNum/*= 0*/)
|
|||
|
||||
bool FloppyDrive::SaveImage(uint8_t driveNum/*= 0*/)
|
||||
{
|
||||
// comment out for now...
|
||||
#if 0
|
||||
// Various sanity checks...
|
||||
if (driveNum > 1)
|
||||
{
|
||||
|
@ -213,41 +160,24 @@ bool FloppyDrive::SaveImage(uint8_t driveNum/*= 0*/)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (diskType[driveNum] == DT_EMPTY)
|
||||
{
|
||||
WriteLog("FLOPPY: No image in drive #%u to save\n", driveNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!imageDirty[driveNum])
|
||||
{
|
||||
WriteLog("FLOPPY: No need to save unchanged image...\n");
|
||||
WriteLog("FLOPPY: No need to save unchanged image in drive #%u...\n", driveNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageName[driveNum][0] == 0)
|
||||
{
|
||||
WriteLog("FLOPPY: Attempted to save non-existant image!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finally, write the damn image
|
||||
FILE * fp = fopen(imageName[driveNum], "wb");
|
||||
|
||||
if (fp == NULL)
|
||||
{
|
||||
WriteLog("FLOPPY: Failed to open image file '%s' for writing...\n", imageName[driveNum]);
|
||||
return false;
|
||||
}
|
||||
|
||||
fwrite(disk[driveNum], 1, diskSize[driveNum], fp);
|
||||
fclose(fp);
|
||||
|
||||
WriteLog("FLOPPY: Successfully wrote image file '%s'...\n", imageName[driveNum]);
|
||||
|
||||
return true;
|
||||
#else
|
||||
char * ext = strrchr(imageName[driveNum], '.');
|
||||
|
||||
if ((ext != NULL) && (diskType[driveNum] != DT_WOZ))
|
||||
memcpy(ext, ".woz", 4);
|
||||
|
||||
return SaveWOZ(driveNum);
|
||||
#endif
|
||||
return SaveWOZ(imageName[driveNum], (WOZ2 *)disk[driveNum], diskSize[driveNum]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -264,9 +194,9 @@ bool FloppyDrive::SaveImageAs(const char * filename, uint8_t driveNum/*= 0*/)
|
|||
void FloppyDrive::CreateBlankImage(uint8_t driveNum/*= 0*/)
|
||||
{
|
||||
if (disk[driveNum] != NULL)
|
||||
delete disk[driveNum];
|
||||
free(disk[driveNum]);
|
||||
|
||||
InitWOZ(driveNum);
|
||||
disk[driveNum] = InitWOZ(&diskSize[driveNum]);
|
||||
diskType[driveNum] = DT_WOZ;
|
||||
strcpy(imageName[driveNum], "newblank.woz");
|
||||
SpawnMessage("New blank image inserted in drive %u...", driveNum);
|
||||
|
@ -275,17 +205,6 @@ void FloppyDrive::CreateBlankImage(uint8_t driveNum/*= 0*/)
|
|||
|
||||
void FloppyDrive::SwapImages(void)
|
||||
{
|
||||
#if 0
|
||||
WriteLog("SwapImages BEFORE:\n");
|
||||
WriteLog("\tdisk[0]=%X, disk[1]=%X\n", disk[0], disk[1]);
|
||||
WriteLog("\twoz[0]=%X, woz[1]=%X\n", woz[0], woz[1]);
|
||||
WriteLog("\tdiskSize[0]=%X, diskSize[1]=%X\n", diskSize[0], diskSize[1]);
|
||||
WriteLog("\tdiskType[0]=%X, diskType[1]=%X\n", diskType[0], diskType[1]);
|
||||
WriteLog("\timageDirty[0]=%X, imageDirty[1]=%X\n", imageDirty[0], imageDirty[1]);
|
||||
WriteLog("\tphase[0]=%X, phase[1]=%X\n", phase[0], phase[1]);
|
||||
WriteLog("\theadPos[0]=%X, headPos[1]=%X\n", headPos[0], headPos[1]);
|
||||
WriteLog("\tcurrentPos[0]=%X, currentPos[1]=%X\n", currentPos[0], currentPos[1]);
|
||||
#endif
|
||||
char imageNameTmp[MAX_PATH];
|
||||
|
||||
memcpy(imageNameTmp, imageName[0], MAX_PATH);
|
||||
|
@ -293,7 +212,6 @@ WriteLog("\tcurrentPos[0]=%X, currentPos[1]=%X\n", currentPos[0], currentPos[1])
|
|||
memcpy(imageName[1], imageNameTmp, MAX_PATH);
|
||||
|
||||
Swap(disk[0], disk[1]);
|
||||
Swap(woz[0], woz[1]);
|
||||
Swap(diskSize[0], diskSize[1]);
|
||||
Swap(diskType[0], diskType[1]);
|
||||
Swap(imageDirty[0], imageDirty[1]);
|
||||
|
@ -302,31 +220,36 @@ WriteLog("\tcurrentPos[0]=%X, currentPos[1]=%X\n", currentPos[0], currentPos[1])
|
|||
Swap(headPos[0], headPos[1]);
|
||||
Swap(currentPos[0], currentPos[1]);
|
||||
SpawnMessage("Drive 0: %s...", imageName[0]);
|
||||
#if 0
|
||||
WriteLog("SwapImages AFTER:\n");
|
||||
WriteLog("\tdisk[0]=%X, disk[1]=%X\n", disk[0], disk[1]);
|
||||
WriteLog("\twoz[0]=%X, woz[1]=%X\n", woz[0], woz[1]);
|
||||
WriteLog("\tdiskSize[0]=%X, diskSize[1]=%X\n", diskSize[0], diskSize[1]);
|
||||
WriteLog("\tdiskType[0]=%X, diskType[1]=%X\n", diskType[0], diskType[1]);
|
||||
WriteLog("\timageDirty[0]=%X, imageDirty[1]=%X\n", imageDirty[0], imageDirty[1]);
|
||||
WriteLog("\tphase[0]=%X, phase[1]=%X\n", phase[0], phase[1]);
|
||||
WriteLog("\theadPos[0]=%X, headPos[1]=%X\n", headPos[0], headPos[1]);
|
||||
WriteLog("\tcurrentPos[0]=%X, currentPos[1]=%X\n", currentPos[0], currentPos[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Need to add some type of error checking here, so we can report back on bad images, etc.
|
||||
Need to add some type of error checking here, so we can report back on bad images, etc. (basically, it does by returning DFT_UNKNOWN, but we could do better)
|
||||
*/
|
||||
void FloppyDrive::DetectImageType(const char * filename, uint8_t driveNum)
|
||||
{
|
||||
diskType[driveNum] = DFT_UNKNOWN;
|
||||
|
||||
if (memcmp(disk[driveNum], wozHeader, 8) == 0)
|
||||
uint8_t wozType = CheckWOZType(disk[driveNum], diskSize[driveNum]);
|
||||
|
||||
if (wozType > 0)
|
||||
{
|
||||
// Check WOZ integrity...
|
||||
CheckWOZIntegrity(disk[driveNum], diskSize[driveNum]);
|
||||
|
||||
// If it's a WOZ type 1 file, upconvert it to type 2
|
||||
if (wozType == 1)
|
||||
{
|
||||
uint32_t size;
|
||||
uint8_t * buffer = UpconvertWOZ1ToWOZ2(disk[driveNum], diskSize[driveNum], &size);
|
||||
|
||||
free(disk[driveNum]);
|
||||
disk[driveNum] = buffer;
|
||||
diskSize[driveNum] = size;
|
||||
WriteLog("FLOPPY: Upconverted WOZ type 1 to type 2...\n");
|
||||
}
|
||||
|
||||
diskType[driveNum] = DT_WOZ;
|
||||
/*bool r =*/ CheckWOZ(disk[driveNum], diskSize[driveNum], driveNum);
|
||||
}
|
||||
else if (diskSize[driveNum] == 143360)
|
||||
{
|
||||
|
@ -341,8 +264,8 @@ void FloppyDrive::DetectImageType(const char * filename, uint8_t driveNum)
|
|||
diskType[driveNum] = DT_PRODOS;
|
||||
else if ((strcasecmp(ext, ".do") == 0) || (strcasecmp(ext, ".dsk") == 0))
|
||||
{
|
||||
// We assume this, but check for a PRODOS fingerprint. Trust, but
|
||||
// verify. ;-)
|
||||
// We assume this, but check for a PRODOS fingerprint. Trust, but
|
||||
// verify. ;-)
|
||||
diskType[driveNum] = DT_DOS33;
|
||||
|
||||
uint8_t fingerprint[4][4] = {
|
||||
|
@ -384,8 +307,8 @@ void FloppyDrive::DetectImageType(const char * filename, uint8_t driveNum)
|
|||
// No, we don't nybblize anymore. But we should tell the user that the loading failed with a return value
|
||||
|
||||
WriteLog("FLOPPY: Detected image type %s...\n", (diskType[driveNum] == DT_DOS33 ?
|
||||
"DOS 3.3 image" : (diskType[driveNum] == DT_DOS33_HDR ?
|
||||
"DOS 3.3 image (headered)" : (diskType[driveNum] == DT_PRODOS ? "ProDOS image" : (diskType[driveNum] == DT_WOZ ? "WOZ image" : "unknown")))));
|
||||
"DOS 3.3" : (diskType[driveNum] == DT_DOS33_HDR ?
|
||||
"DOS 3.3 (headered)" : (diskType[driveNum] == DT_PRODOS ? "ProDOS" : (diskType[driveNum] == DT_WOZ ? "WOZ" : "unknown")))));
|
||||
}
|
||||
|
||||
|
||||
|
@ -394,7 +317,7 @@ void FloppyDrive::DetectImageType(const char * filename, uint8_t driveNum)
|
|||
// Writes 'bits' number of bits to 'dest', starting at bit position 'dstPtr',
|
||||
// updating 'dstPtr' for the caller.
|
||||
//
|
||||
void FloppyDrive::WriteBits(uint8_t * dest, uint8_t * src, uint16_t bits, uint16_t * dstPtr)
|
||||
void FloppyDrive::WriteBits(uint8_t * dest, const uint8_t * src, uint16_t bits, uint16_t * dstPtr)
|
||||
{
|
||||
for(uint16_t i=0; i<bits; i++)
|
||||
{
|
||||
|
@ -421,13 +344,13 @@ void FloppyDrive::WOZifyImage(uint8_t driveNum)
|
|||
// let's go back to what we had, and see what happens :-)
|
||||
// [still need to expand them back to what they were]
|
||||
|
||||
uint8_t ff10[2] = { 0xFF, 0x00 };
|
||||
const uint8_t ff10[2] = { 0xFF, 0x00 };
|
||||
uint8_t addressHeader[14] = {
|
||||
0xD5, 0xAA, 0x96, 0xFF, 0xFE, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xDE, 0xAA, 0xEB };
|
||||
uint8_t sectorHeader[3] = { 0xD5, 0xAA, 0xAD };
|
||||
uint8_t footer[3] = { 0xDE, 0xAA, 0xEB };
|
||||
uint8_t diskbyte[0x40] = {
|
||||
const uint8_t sectorHeader[3] = { 0xD5, 0xAA, 0xAD };
|
||||
const uint8_t footer[3] = { 0xDE, 0xAA, 0xEB };
|
||||
const uint8_t diskbyte[0x40] = {
|
||||
0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6,
|
||||
0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,
|
||||
0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC,
|
||||
|
@ -436,24 +359,25 @@ void FloppyDrive::WOZifyImage(uint8_t driveNum)
|
|||
0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,
|
||||
0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
|
||||
0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF };
|
||||
const uint8_t doSector[16] = {
|
||||
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF };
|
||||
const uint8_t poSector[16] = {
|
||||
0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF };
|
||||
|
||||
uint8_t tmpNib[343];
|
||||
// memcpy(tmpDisk, disk[driveNum], diskSize[driveNum]);
|
||||
// delete[] disk[driveNum];
|
||||
// Save current image until we're done converting
|
||||
uint8_t * tmpDisk = disk[driveNum];
|
||||
disk[driveNum] = NULL;//new uint8_t[diskSize[driveNum]];
|
||||
|
||||
// Set up track index...
|
||||
// memcpy(woz[driveNum]->tmap, standardTMAP, 141);
|
||||
InitWOZ(driveNum);
|
||||
disk[driveNum] = InitWOZ(&diskSize[driveNum]);
|
||||
WOZ2 & woz = *((WOZ2 *)disk[driveNum]);
|
||||
|
||||
// Upconvert data from DSK & friends format to WOZ tracks :-)
|
||||
for(uint8_t trk=0; trk<35; trk++)
|
||||
{
|
||||
uint16_t dstBitPtr = 0;
|
||||
uint8_t * img = woz[driveNum]->track[trk].bits;
|
||||
//already done
|
||||
// memset(img, 0, 6646);
|
||||
uint8_t * img = disk[driveNum] + (Uint16LE(woz.track[trk].startingBlock) * 512);
|
||||
//printf("Converting track %u: startingBlock=%u, %u blocks, img=%X\n", trk, Uint16LE(woz.track[trk].startingBlock), Uint16LE(woz.track[trk].blockCount), img);
|
||||
|
||||
// Write self-sync header bytes (16, should it be 64? Dunno.)
|
||||
for(int i=0; i<64; i++)
|
||||
|
@ -478,7 +402,6 @@ void FloppyDrive::WOZifyImage(uint8_t driveNum)
|
|||
|
||||
// Write sector header (D5 AA AD)
|
||||
WriteBits(img, sectorHeader, 3 * 8, &dstBitPtr);
|
||||
// uint8_t * bytes = disk[driveNum];
|
||||
uint8_t * bytes = tmpDisk;
|
||||
|
||||
//Need to fix this so it writes the correct sector in the correct place *and* put the correct sector # into the header above as well. !!! FIX !!!
|
||||
|
@ -529,11 +452,11 @@ void FloppyDrive::WOZifyImage(uint8_t driveNum)
|
|||
}
|
||||
|
||||
// Set the proper bit/byte lengths in the WOZ for this track
|
||||
woz[driveNum]->track[trk].bitCount = Uint16LE(dstBitPtr);
|
||||
woz[driveNum]->track[trk].byteCount = Uint16LE((dstBitPtr + 7) / 8);
|
||||
woz.track[trk].bitCount = Uint16LE(dstBitPtr);
|
||||
}
|
||||
|
||||
delete[] tmpDisk;
|
||||
// Finally, free the non-WOZ image now that we're done converting
|
||||
free(tmpDisk);
|
||||
}
|
||||
|
||||
|
||||
|
@ -585,10 +508,10 @@ void FloppyDrive::EjectImage(uint8_t driveNum/*= 0*/)
|
|||
WriteLog("FLOPPY: Ejected image file '%s' from drive %u...\n", imageName[driveNum], driveNum);
|
||||
|
||||
if (disk[driveNum])
|
||||
delete[] disk[driveNum];
|
||||
free(disk[driveNum]);
|
||||
|
||||
disk[driveNum] = NULL;
|
||||
woz[driveNum] = NULL;
|
||||
// woz[driveNum] = NULL;
|
||||
diskSize[driveNum] = 0;
|
||||
diskType[driveNum] = DT_EMPTY;
|
||||
imageDirty[driveNum] = false;
|
||||
|
@ -616,7 +539,8 @@ bool FloppyDrive::IsWriteProtected(uint8_t driveNum/*= 0*/)
|
|||
return true;
|
||||
}
|
||||
|
||||
return (bool)woz[driveNum]->writeProtected;
|
||||
WOZ2 & woz = *((WOZ2 *)disk[driveNum]);
|
||||
return (bool)woz.writeProtected;
|
||||
}
|
||||
|
||||
|
||||
|
@ -628,7 +552,8 @@ void FloppyDrive::SetWriteProtect(bool state, uint8_t driveNum/*= 0*/)
|
|||
return;
|
||||
}
|
||||
|
||||
woz[driveNum]->writeProtected = (uint8_t)state;
|
||||
WOZ2 & woz = *((WOZ2 *)disk[driveNum]);
|
||||
woz.writeProtected = (uint8_t)state;
|
||||
}
|
||||
|
||||
|
||||
|
@ -713,7 +638,6 @@ void FloppyDrive::LoadState(FILE * file)
|
|||
imageDirty[0] = (fgetc(file) == 1 ? true : false);
|
||||
fread(disk[0], 1, diskSize[0], file);
|
||||
fread(imageName[0], 1, MAX_PATH, file);
|
||||
woz[0] = (WOZ *)disk[0];
|
||||
}
|
||||
|
||||
diskSize[1] = ReadLong(file);
|
||||
|
@ -728,7 +652,6 @@ void FloppyDrive::LoadState(FILE * file)
|
|||
imageDirty[1] = (fgetc(file) == 1 ? true : false);
|
||||
fread(disk[1], 1, diskSize[1], file);
|
||||
fread(imageName[1], 1, MAX_PATH, file);
|
||||
woz[1] = (WOZ *)disk[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -754,30 +677,6 @@ void FloppyDrive::WriteLong(FILE * file, uint32_t l)
|
|||
}
|
||||
|
||||
|
||||
void FloppyDrive::WriteLongLE(FILE * file, uint32_t l)
|
||||
{
|
||||
for(int i=0; i<4; i++)
|
||||
{
|
||||
fputc(l & 0xFF, file);
|
||||
l >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FloppyDrive::WriteWordLE(FILE * file, uint16_t w)
|
||||
{
|
||||
fputc(w & 0xFF, file);
|
||||
fputc((w >> 8) & 0xFF, file);
|
||||
}
|
||||
|
||||
|
||||
void FloppyDrive::WriteZeroes(FILE * file, uint32_t num)
|
||||
{
|
||||
for(uint32_t i=0; i<num; i++)
|
||||
fputc(0, file);
|
||||
}
|
||||
|
||||
|
||||
// Memory mapped I/O functions + Logic State Sequencer
|
||||
|
||||
/*
|
||||
|
@ -824,7 +723,7 @@ If it ever *does* become a problem, doing the physical modeling of the head movi
|
|||
// patterns. The numbers represent how many quarter tracks the head will
|
||||
// move given its current position and the pattern of energized solenoids.
|
||||
// N.B.: Patterns for 11 & 13 haven't been filled in as I'm not sure how
|
||||
// the stub would react to those patterns. :-/
|
||||
// the stub(s) would react to those patterns. :-/
|
||||
int16_t step[16][8] = {
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // [....]
|
||||
{ 0, -1, -2, 0, 0, 0, +2, +1 }, // [|...]
|
||||
|
@ -884,13 +783,14 @@ If it ever *does* become a problem, doing the physical modeling of the head movi
|
|||
|
||||
if (oldHeadPos != headPos[activeDrive])
|
||||
{
|
||||
uint8_t newTIdx = woz[activeDrive]->tmap[headPos[activeDrive]];
|
||||
WOZ2 & woz = *((WOZ2 *)disk[activeDrive]);
|
||||
uint8_t newTIdx = woz.tmap[headPos[activeDrive]];
|
||||
float newBitLen = (newTIdx == 0xFF ? 51200.0f
|
||||
: Uint16LE(woz[activeDrive]->track[newTIdx].bitCount));
|
||||
: Uint16LE(woz.track[newTIdx].bitCount));
|
||||
|
||||
uint8_t oldTIdx = woz[activeDrive]->tmap[oldHeadPos];
|
||||
uint8_t oldTIdx = woz.tmap[oldHeadPos];
|
||||
float oldBitLen = (oldTIdx == 0xFF ? 51200.0f
|
||||
: Uint16LE(woz[activeDrive]->track[oldTIdx].bitCount));
|
||||
: Uint16LE(woz.track[oldTIdx].bitCount));
|
||||
currentPos[activeDrive] = (uint32_t)((float)currentPos[activeDrive] * (newBitLen / oldBitLen));
|
||||
|
||||
trackLength[activeDrive] = (uint16_t)newBitLen;
|
||||
|
@ -965,9 +865,10 @@ uint8_t FloppyDrive::DataRegister(void)
|
|||
// Sanity check
|
||||
if (diskType[activeDrive] != DT_EMPTY)
|
||||
{
|
||||
uint8_t tIdx = woz[activeDrive]->tmap[headPos[activeDrive]];
|
||||
WOZ2 & woz = *((WOZ2 *)disk[activeDrive]);
|
||||
uint8_t tIdx = woz.tmap[headPos[activeDrive]];
|
||||
uint32_t bitLen = (tIdx == 0xFF ? 51200
|
||||
: Uint16LE(woz[activeDrive]->track[tIdx].bitCount));
|
||||
: Uint16LE(woz.track[tIdx].bitCount));
|
||||
SpawnMessage("%u:Reading $%02X from track %u, sector %u...",
|
||||
activeDrive, dataRegister, headPos[activeDrive] >> 2, (uint32_t)(((float)currentPos[activeDrive] / (float)bitLen) * 16.0f));
|
||||
ioMode = IO_MODE_READ;
|
||||
|
@ -1058,194 +959,6 @@ $57: Duplicate volume
|
|||
$5A: File structure damaged
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// This is used mainly to initialize blank disks and upconvert non-WOZ disks
|
||||
//
|
||||
void FloppyDrive::InitWOZ(uint8_t driveNum/*= 0*/)
|
||||
{
|
||||
// Sanity check
|
||||
if (disk[driveNum] != NULL)
|
||||
{
|
||||
WriteLog("FLOPPY: Attempted to initialize non-NULL WOZ structure\n");
|
||||
return;
|
||||
}
|
||||
|
||||
diskSize[driveNum] = 256 + (35 * sizeof(WOZTrack));
|
||||
disk[driveNum] = new uint8_t[diskSize[driveNum]];
|
||||
woz[driveNum] = (WOZ *)disk[driveNum];
|
||||
|
||||
// Zero out WOZ image in memory
|
||||
memset(woz[driveNum], 0, diskSize[driveNum]);
|
||||
|
||||
// Set up header (leave CRC as 0 for now)
|
||||
memcpy(woz[driveNum]->magic, wozHeader, 8);
|
||||
|
||||
// INFO header
|
||||
memcpy(woz[driveNum]->infoTag, "INFO", 4);
|
||||
woz[driveNum]->infoSize = Uint32LE(60);
|
||||
woz[driveNum]->infoVersion = 1;
|
||||
woz[driveNum]->diskType = 1;
|
||||
woz[driveNum]->writeProtected = 0;
|
||||
woz[driveNum]->synchronized = 0;
|
||||
woz[driveNum]->cleaned = 1;
|
||||
memset(woz[driveNum]->creator, ' ', 32);
|
||||
memcpy(woz[driveNum]->creator, "Apple2 emulator v1.0.0", 22);
|
||||
|
||||
// TMAP header
|
||||
memcpy(woz[driveNum]->tmapTag, "TMAP", 4);
|
||||
woz[driveNum]->tmapSize = Uint32LE(160);
|
||||
memcpy(woz[driveNum]->tmap, standardTMAP, 141);
|
||||
|
||||
// TRKS header
|
||||
memcpy(woz[driveNum]->trksTag, "TRKS", 4);
|
||||
woz[driveNum]->trksSize = Uint32LE(35 * sizeof(WOZTrack));
|
||||
|
||||
for(int i=0; i<35; i++)
|
||||
{
|
||||
woz[driveNum]->track[i].bitCount = Uint16LE(51200);
|
||||
woz[driveNum]->track[i].byteCount = Uint16LE((51200 + 7) / 8);
|
||||
}
|
||||
|
||||
// META header (how to handle? prolly with a separate pointer)
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Do basic sanity checks on the passed in contents (file loaded elsewhere).
|
||||
// Returns true if successful, false on failure.
|
||||
//
|
||||
bool FloppyDrive::CheckWOZ(const uint8_t * wozData, uint32_t wozSize, uint8_t driveNum/*= 0*/)
|
||||
{
|
||||
// Hey! This reference works!! :-D
|
||||
WOZ & woz1 = *((WOZ *)wozData);
|
||||
woz[driveNum] = (WOZ *)wozData;
|
||||
|
||||
// Basic sanity checking
|
||||
if (wozData == NULL)
|
||||
{
|
||||
WriteLog("FLOPPY: NULL pointer passed in to CheckWOZ()...\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(woz1.magic, wozHeader, 8) != 0)
|
||||
{
|
||||
WriteLog("FLOPPY: Invalid WOZ header in file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t crc = CRC32(&wozData[12], wozSize - 12);
|
||||
uint32_t wozCRC = Uint32LE(woz1.crc32);
|
||||
|
||||
if ((wozCRC != 0) && (wozCRC != crc))
|
||||
{
|
||||
WriteLog("FLOPPY: Corrupted data found in WOZ. CRC32: %08X, computed: %08X\n", wozCRC, crc);
|
||||
return false;
|
||||
}
|
||||
else if (wozCRC == 0)
|
||||
WriteLog("FLOPPY: Warning--WOZ file has no CRC...\n");
|
||||
|
||||
#if 1
|
||||
WriteLog("Track map:\n");
|
||||
WriteLog(" 1 1 1 1 1 1 1 1\n");
|
||||
WriteLog("0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.\n");
|
||||
WriteLog("------------------------------------------------------------------------\n");
|
||||
|
||||
for(uint8_t j=0; j<2; j++)
|
||||
{
|
||||
for(uint8_t i=0; i<72; i++)
|
||||
{
|
||||
char buf[64] = "..";
|
||||
buf[0] = buf[1] = '.';
|
||||
|
||||
if (woz1.tmap[i] != 0xFF)
|
||||
sprintf(buf, "%02d", woz1.tmap[i]);
|
||||
|
||||
WriteLog("%c", buf[j]);
|
||||
}
|
||||
|
||||
WriteLog("\n");
|
||||
}
|
||||
|
||||
WriteLog("\n1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3\n");
|
||||
WriteLog("8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5\n");
|
||||
WriteLog("---------------------------------------------------------------------\n");
|
||||
|
||||
for(uint8_t j=0; j<2; j++)
|
||||
{
|
||||
for(uint8_t i=72; i<141; i++)
|
||||
{
|
||||
char buf[64] = "..";
|
||||
|
||||
if (woz1.tmap[i] != 0xFF)
|
||||
sprintf(buf, "%02d", woz1.tmap[i]);
|
||||
|
||||
WriteLog("%c", buf[j]);
|
||||
}
|
||||
|
||||
WriteLog("\n");
|
||||
}
|
||||
|
||||
WriteLog("\n");
|
||||
|
||||
uint8_t numTracks = woz1.trksSize / sizeof(WOZTrack);
|
||||
|
||||
// N.B.: Need to check the track[] to have this tell the correct track... Right now, it doesn't
|
||||
for(uint8_t i=0; i<numTracks; i++)
|
||||
{
|
||||
WriteLog("WOZ: Track %2.2f: %d bits (packed into %d bytes)\n", (float)i / 4.0f, woz1.track[i].bitCount, woz1.track[i].byteCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
WriteLog("FLOPPY: Well formed WOZ file found\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FloppyDrive::SaveWOZ(uint8_t driveNum)
|
||||
{
|
||||
// Various sanity checks...
|
||||
if (driveNum > 1)
|
||||
{
|
||||
WriteLog("FLOPPY: Attempted to save image to drive #%u!\n", driveNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (diskType[driveNum] == DT_EMPTY)
|
||||
{
|
||||
WriteLog("FLOPPY: No image in drive #%u to save\n", driveNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!imageDirty[driveNum])
|
||||
{
|
||||
WriteLog("FLOPPY: No need to save unchanged image in drive #%u...\n", driveNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up CRC32 before writing
|
||||
woz[driveNum]->crc32 = Uint32LE(CRC32(&disk[driveNum][12], diskSize[driveNum] - 12));
|
||||
|
||||
// META header (skip for now) (actually, should be in the disk[] image already)
|
||||
|
||||
// Finally, write the damn image
|
||||
FILE * fp = fopen(imageName[driveNum], "wb");
|
||||
|
||||
if (fp == NULL)
|
||||
{
|
||||
WriteLog("FLOPPY: Failed to open image file '%s' for writing...\n", imageName[driveNum]);
|
||||
return false;
|
||||
}
|
||||
|
||||
fwrite(disk[driveNum], 1, diskSize[driveNum], fp);
|
||||
fclose(fp);
|
||||
|
||||
WriteLog("FLOPPY: Successfully wrote image file '%s'...\n", imageName[driveNum]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// N.B.: The WOZ documentation says that the bitstream is normalized to 4µs.
|
||||
// Which means on the //e that you would have to run it at that clock
|
||||
// rate (instead of the //e clock rate 0.9799µs/cycle) to get the
|
||||
|
@ -1265,16 +978,22 @@ void FloppyDrive::RunSequencer(uint32_t cyclesToRun)
|
|||
static uint32_t prng = 1;
|
||||
|
||||
// Sanity checks
|
||||
if (diskType[activeDrive] == DT_EMPTY)
|
||||
if (!diskImageReady)
|
||||
return;
|
||||
else if (diskType[activeDrive] == DT_EMPTY)
|
||||
return;
|
||||
else if (motorOn == false)
|
||||
{
|
||||
if (driveOffTimeout == 0)
|
||||
return;
|
||||
else
|
||||
driveOffTimeout--;
|
||||
|
||||
driveOffTimeout--;
|
||||
}
|
||||
|
||||
WOZ2 & woz = *((WOZ2 *)disk[activeDrive]);
|
||||
uint8_t tIdx = woz.tmap[headPos[activeDrive]];
|
||||
uint8_t * tdata = disk[activeDrive] + (Uint16LE(woz.track[tIdx].startingBlock) * 512);
|
||||
|
||||
// It's x2 because the sequencer clock runs twice as fast as the CPU clock.
|
||||
cyclesToRun *= 2;
|
||||
|
||||
|
@ -1289,17 +1008,19 @@ if (logSeq)
|
|||
|
||||
while (cyclesToRun-- > 0)
|
||||
{
|
||||
pulseClock = (pulseClock + 1) & 0x07;
|
||||
// pulseClock = (pulseClock + 1) & 0x07;
|
||||
pulseClock = (pulseClock + 1) % 8;
|
||||
// 7 doesn't work... Is that 3.5µs? Seems to be. Which means to get a 0.25µs granularity here, we need to double the # of cycles to run...
|
||||
// pulseClock = (pulseClock + 1) % 7;
|
||||
|
||||
if (pulseClock == 0)
|
||||
{
|
||||
uint16_t bytePos = currentPos[activeDrive] / 8;
|
||||
uint8_t bitPos = currentPos[activeDrive] % 8;
|
||||
uint8_t tIdx = woz[activeDrive]->tmap[headPos[activeDrive]];
|
||||
|
||||
if (tIdx != 0xFF)
|
||||
{
|
||||
if (woz[activeDrive]->track[tIdx].bits[bytePos] & bitMask[bitPos])
|
||||
if (tdata[bytePos] & bitMask[bitPos])
|
||||
{
|
||||
// According to Jim Sather (Understanding the Apple II),
|
||||
// the Read Pulse, when it happens, is 1µs long, which is 2
|
||||
|
@ -1309,18 +1030,9 @@ if (logSeq)
|
|||
}
|
||||
else
|
||||
zeroBitCount++;
|
||||
#if 0
|
||||
currentPos[activeDrive] = (currentPos[activeDrive] + 1) % Uint16LE(woz[activeDrive]->track[tIdx].bitCount);
|
||||
}
|
||||
else
|
||||
currentPos[activeDrive] = (currentPos[activeDrive] + 1) % 51200;
|
||||
#else
|
||||
}
|
||||
|
||||
//this doesn't work reliably for some reason...
|
||||
//seems to work OK now...
|
||||
currentPos[activeDrive] = (currentPos[activeDrive] + 1) % trackLength[activeDrive];
|
||||
#endif
|
||||
|
||||
// If we hit more than 2 zero bits in a row, simulate the disk head
|
||||
// reader's Automatic Gain Control (AGC) turning itself up too high
|
||||
|
@ -1373,10 +1085,8 @@ chop = (chop + 1) % 20;
|
|||
dataRegister <<= 1;
|
||||
//if (!stopWriting)
|
||||
{
|
||||
uint8_t tIdx = woz[activeDrive]->tmap[headPos[activeDrive]];
|
||||
|
||||
if (rwSwitch && (tIdx != 0xFF)
|
||||
&& !woz[activeDrive]->writeProtected)
|
||||
&& !woz.writeProtected)
|
||||
{
|
||||
imageDirty[activeDrive] = true;
|
||||
uint16_t bytePos = currentPos[activeDrive] / 8;
|
||||
|
@ -1384,10 +1094,10 @@ chop = (chop + 1) % 20;
|
|||
|
||||
if (dataRegister & 0x80)
|
||||
// Fill in the one, if necessary
|
||||
woz[activeDrive]->track[tIdx].bits[bytePos] |= bitMask[bitPos];
|
||||
tdata[bytePos] |= bitMask[bitPos];
|
||||
else
|
||||
// Otherwise, punch in the zero
|
||||
woz[activeDrive]->track[tIdx].bits[bytePos] &= ~bitMask[bitPos];
|
||||
tdata[bytePos] &= ~bitMask[bitPos];
|
||||
|
||||
#if 0
|
||||
if (dumpDis || tripwire)
|
||||
|
@ -1408,7 +1118,7 @@ lastPos = currentPos[activeDrive];
|
|||
case 0x0E:
|
||||
// SR (shift right write protect bit)
|
||||
dataRegister >>= 1;
|
||||
dataRegister |= (woz[activeDrive]->writeProtected ? 0x80 : 0x00);
|
||||
dataRegister |= (woz.writeProtected ? 0x80 : 0x00);
|
||||
break;
|
||||
case 0x0B:
|
||||
case 0x0F:
|
||||
|
@ -1416,15 +1126,12 @@ lastPos = currentPos[activeDrive];
|
|||
dataRegister = cpuDataBus;
|
||||
//if (!stopWriting)
|
||||
{
|
||||
uint8_t tIdx = woz[activeDrive]->tmap[headPos[activeDrive]];
|
||||
|
||||
if (rwSwitch && (tIdx != 0xFF)
|
||||
&& !woz[activeDrive]->writeProtected)
|
||||
if (rwSwitch && (tIdx != 0xFF) && !woz.writeProtected)
|
||||
{
|
||||
imageDirty[activeDrive] = true;
|
||||
uint16_t bytePos = currentPos[activeDrive] / 8;
|
||||
uint8_t bitPos = currentPos[activeDrive] % 8;
|
||||
woz[activeDrive]->track[tIdx].bits[bytePos] |= bitMask[bitPos];
|
||||
tdata[bytePos] |= bitMask[bitPos];
|
||||
#if 0
|
||||
if (dumpDis || tripwire)
|
||||
{
|
||||
|
|
|
@ -24,98 +24,7 @@ enum { DT_EMPTY = 0, DT_WOZ, DT_DOS33, DT_DOS33_HDR, DT_PRODOS, DT_NYBBLE,
|
|||
DFT_UNKNOWN };
|
||||
enum { DLS_OFF, DLS_READ, DLS_WRITE };
|
||||
|
||||
// N.B.: All 32/16-bit values are stored in little endian. Which means, to
|
||||
// read/write them safely, we need to use translators as this code may or
|
||||
// may not be compiled on an architecture that supports little endian
|
||||
// natively.
|
||||
|
||||
struct WOZTrack
|
||||
{
|
||||
uint8_t bits[6646];
|
||||
uint16_t byteCount;
|
||||
uint16_t bitCount;
|
||||
uint16_t splicePoint;
|
||||
uint8_t spliceNibble;
|
||||
uint8_t spliceBitCount;
|
||||
uint16_t reserved;
|
||||
};
|
||||
|
||||
struct WOZMetadata
|
||||
{
|
||||
uint8_t metaTag[4]; // "META"
|
||||
uint32_t metaSize; // Size of the META chunk
|
||||
uint8_t data[]; // Variable length array of metadata
|
||||
};
|
||||
|
||||
struct WOZ
|
||||
{
|
||||
// Header
|
||||
uint8_t magic[8]; // "WOZ1" $FF $0A $0D $0A
|
||||
uint32_t crc32; // CRC32 of the remaining data in the file
|
||||
|
||||
// INFO chunk
|
||||
uint8_t infoTag[4]; // "INFO"
|
||||
uint32_t infoSize; // Always 60 bytes long
|
||||
uint8_t infoVersion; // Currently 1
|
||||
uint8_t diskType; // 1 = 5 1/4", 2 = 3 1/2"
|
||||
uint8_t writeProtected; // 1 = write protected disk
|
||||
uint8_t synchronized; // 1 = cross-track sync was used during imaging
|
||||
uint8_t cleaned; // 1 = fake bits removed from image
|
||||
uint8_t creator[32]; // Software that made this image, padded with 0x20
|
||||
uint8_t pad1[23]; // Padding to 60 bytes
|
||||
|
||||
// TMAP chunk
|
||||
uint8_t tmapTag[4]; // "TMAP"
|
||||
uint32_t tmapSize; // Always 160 bytes long
|
||||
uint8_t tmap[160]; // Track map, with empty tracks set to $FF
|
||||
|
||||
// TRKS chunk
|
||||
uint8_t trksTag[4]; // "TRKS"
|
||||
uint32_t trksSize; // Varies, depending on # of tracks imaged
|
||||
WOZTrack track[]; // Variable length array for the track data proper
|
||||
};
|
||||
|
||||
struct WOZTrack2
|
||||
{
|
||||
uint16_t startingBlock; // 512 byte block # where this track starts (relative to the start of the file)
|
||||
uint16_t blockCount; // # of blocks in this track
|
||||
uint32_t bitCount; // # of bits in this track
|
||||
};
|
||||
|
||||
struct WOZ2
|
||||
{
|
||||
// Header
|
||||
uint8_t magic[8]; // "WOZ2" $FF $0A $0D $0A
|
||||
uint32_t crc32; // CRC32 of the remaining data in the file
|
||||
|
||||
// INFO chunk
|
||||
uint8_t infoTag[4]; // "INFO"
|
||||
uint32_t infoSize; // Always 60 bytes long
|
||||
uint8_t infoVersion; // Currently 1
|
||||
uint8_t diskType; // 1 = 5 1/4", 2 = 3 1/2"
|
||||
uint8_t writeProtected; // 1 = write protected disk
|
||||
uint8_t synchronized; // 1 = cross-track sync was used during imaging
|
||||
uint8_t cleaned; // 1 = fake bits removed from image
|
||||
uint8_t creator[32]; // Software that made this image, padded with 0x20
|
||||
uint8_t diskSides; // 5 1/4" disks always have 1 side (v2 from here on)
|
||||
uint8_t bootSectorFmt; // 5 1/4" only (0=unknown, 1=16 sector, 2=13 sector, 3=both)
|
||||
uint8_t optimalBitTmg; // In ticks, standard for 5 1/4" is 32 (4 µs)
|
||||
uint16_t compatibleHW; // Bitfield showing hardware compatibility (1=][, 2=][+, 4=//e (unenh), 8=//c, 16=//e (enh), 32=IIgs, 64=//c+, 128=///, 256=///+)
|
||||
uint16_t requiredRAM; // Minimum size in K, 0=unknown
|
||||
uint16_t largestTrack; // Number of 512 byte blocks used by largest track
|
||||
uint8_t pad1[14]; // Padding to 60 bytes
|
||||
|
||||
// TMAP chunk
|
||||
uint8_t tmapTag[4]; // "TMAP"
|
||||
uint32_t tmapSize; // Always 160 bytes long
|
||||
uint8_t tmap[160]; // Track map, with empty tracks set to $FF
|
||||
|
||||
// TRKS chunk
|
||||
uint8_t trksTag[4]; // "TRKS"
|
||||
uint32_t trksSize; // Varies, depending on # of tracks imaged
|
||||
WOZTrack2 track[160]; // Actual track info (corresponding to TMAP data)
|
||||
uint8_t data[]; // Variable length array for the track data proper
|
||||
};
|
||||
class WOZ2;
|
||||
|
||||
class FloppyDrive
|
||||
{
|
||||
|
@ -136,16 +45,10 @@ class FloppyDrive
|
|||
int DriveLightStatus(uint8_t driveNum = 0);
|
||||
void SaveState(FILE *);
|
||||
void LoadState(FILE *);
|
||||
void InitWOZ(uint8_t driveNum = 0);
|
||||
bool CheckWOZ(const uint8_t * wozData, uint32_t wozSize, uint8_t driveNum = 0);
|
||||
bool SaveWOZ(uint8_t driveNum);
|
||||
|
||||
private:
|
||||
uint32_t ReadLong(FILE *);
|
||||
void WriteLong(FILE *, uint32_t);
|
||||
void WriteLongLE(FILE *, uint32_t);
|
||||
void WriteWordLE(FILE *, uint16_t);
|
||||
void WriteZeroes(FILE *, uint32_t);
|
||||
|
||||
// I/O functions ($C0Ex accesses)
|
||||
|
||||
|
@ -161,7 +64,7 @@ class FloppyDrive
|
|||
|
||||
protected:
|
||||
void DetectImageType(const char * filename, uint8_t driveNum);
|
||||
void WriteBits(uint8_t * dest, uint8_t * src, uint16_t bits, uint16_t * start);
|
||||
void WriteBits(uint8_t * dest, const uint8_t * src, uint16_t bits, uint16_t * start);
|
||||
void WOZifyImage(uint8_t driveNum);
|
||||
|
||||
private:
|
||||
|
@ -177,9 +80,9 @@ class FloppyDrive
|
|||
uint8_t phase[2];
|
||||
uint8_t headPos[2];
|
||||
bool ioHappened;
|
||||
bool diskImageReady;
|
||||
|
||||
uint32_t currentPos[2];
|
||||
WOZ * woz[2];
|
||||
|
||||
uint8_t cpuDataBus;
|
||||
uint8_t slSwitch; // Shift/Load soft switch
|
||||
|
@ -190,19 +93,9 @@ class FloppyDrive
|
|||
uint32_t driveOffTimeout;
|
||||
uint8_t zeroBitCount;
|
||||
uint16_t trackLength[2];
|
||||
|
||||
// And here are some private class variables (to reduce function
|
||||
// redundancy):
|
||||
static uint8_t doSector[16];
|
||||
static uint8_t poSector[16];
|
||||
static uint8_t wozHeader[9];
|
||||
static uint8_t wozHeader2[9];
|
||||
static uint8_t standardTMAP[141];
|
||||
static uint8_t sequencerROM[256];
|
||||
static uint8_t bitMask[8];
|
||||
static char nameBuf[MAX_PATH];
|
||||
};
|
||||
|
||||
// Exported functions/variables
|
||||
void InstallFloppy(uint8_t slot);
|
||||
extern FloppyDrive floppyDrive[];
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include "crc32.h"
|
||||
#include "fileio.h"
|
||||
#include "floppydrive.h"
|
||||
#include "font10pt.h"
|
||||
#include "gui.h"
|
||||
|
@ -341,25 +342,6 @@ bool DiskSelector::CheckManifest(const char * path, DiskSet * ds)
|
|||
}
|
||||
|
||||
|
||||
uint8_t * DiskSelector::ReadFile(const char * filename, uint32_t * size)
|
||||
{
|
||||
FILE * fp = fopen(filename, "r");
|
||||
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
*size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
uint8_t * buffer = (uint8_t *)malloc(*size);
|
||||
fread(buffer, 1, *size, fp);
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
bool DiskSelector::HasLegalExtension(const char * name)
|
||||
{
|
||||
// Find the file's extension, if any
|
||||
|
|
|
@ -19,7 +19,6 @@ class DiskSelector
|
|||
static void FindDisks(const char *);
|
||||
static void ReadManifest(FILE *, DiskSet *);
|
||||
static bool CheckManifest(const char *, DiskSet *);
|
||||
static uint8_t * ReadFile(const char *, uint32_t *);
|
||||
static bool HasLegalExtension(const char *);
|
||||
static void DrawFilenames(SDL_Renderer *);
|
||||
static void DrawCharacter(SDL_Renderer *, int, int, uint8_t, bool inv=false);
|
||||
|
|
Loading…
Reference in New Issue