2018-05-20 04:53:34 +00:00
|
|
|
// Pi1541 - A Commodore 1541 disk drive emulator
|
|
|
|
// Copyright(C) 2018 Stephen White
|
|
|
|
//
|
|
|
|
// This file is part of Pi1541.
|
|
|
|
//
|
|
|
|
// Pi1541 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 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// Pi1541 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 Pi1541. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#ifndef DISKIMAGE_H
|
|
|
|
#define DISKIMAGE_H
|
|
|
|
#include "types.h"
|
|
|
|
#include "ff.h"
|
|
|
|
|
2018-09-23 07:22:01 +00:00
|
|
|
#define READBUFFER_SIZE 1024 * 512 * 2 // Now need over 800K for D81s
|
2018-05-20 04:53:34 +00:00
|
|
|
|
2018-09-23 07:22:01 +00:00
|
|
|
#define MAX_TRACK_LENGTH 0x2000
|
2018-05-20 04:53:34 +00:00
|
|
|
#define NIB_TRACK_LENGTH 0x2000
|
|
|
|
|
|
|
|
#define BAM_OFFSET 4
|
|
|
|
#define BAM_ENTRY_SIZE 4
|
|
|
|
|
|
|
|
#define DIR_ENTRY_OFFSET_TYPE 0
|
|
|
|
#define DIR_ENTRY_OFFSET_NAME 3
|
|
|
|
#define DIR_ENTRY_OFFSET_BLOCKS 28
|
|
|
|
|
|
|
|
#define DIR_ENTRY_NAME_LENGTH 18-2
|
|
|
|
|
|
|
|
static const unsigned char HALF_TRACK_COUNT = 84;
|
2018-09-23 07:22:01 +00:00
|
|
|
static const unsigned char D71_HALF_TRACK_COUNT = 70;
|
|
|
|
static const unsigned char D81_TRACK_COUNT = 80;
|
2018-05-20 04:53:34 +00:00
|
|
|
static const unsigned short GCR_SYNC_LENGTH = 5;
|
|
|
|
static const unsigned short GCR_HEADER_LENGTH = 10;
|
|
|
|
static const unsigned short GCR_HEADER_GAP_LENGTH = 8;
|
|
|
|
static const unsigned short GCR_SECTOR_DATA_LENGTH = 325;
|
|
|
|
static const unsigned short GCR_SECTOR_GAP_LENGTH = 8;
|
|
|
|
static const unsigned short GCR_SECTOR_LENGTH = GCR_SYNC_LENGTH + GCR_HEADER_LENGTH + GCR_HEADER_GAP_LENGTH + GCR_SYNC_LENGTH + GCR_SECTOR_DATA_LENGTH + GCR_SECTOR_GAP_LENGTH; //361
|
|
|
|
|
|
|
|
static const unsigned short G64_MAX_TRACK_LENGTH = 7928;
|
|
|
|
|
2018-09-23 07:22:01 +00:00
|
|
|
static const unsigned short D81_SECTOR_LENGTH = 512;
|
|
|
|
|
2018-05-20 04:53:34 +00:00
|
|
|
class DiskImage
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum DiskType
|
|
|
|
{
|
|
|
|
NONE,
|
|
|
|
D64,
|
|
|
|
G64,
|
|
|
|
NIB,
|
|
|
|
NBZ,
|
|
|
|
LST,
|
2018-09-23 07:22:01 +00:00
|
|
|
D71,
|
|
|
|
D81,
|
2018-05-20 04:53:34 +00:00
|
|
|
RAW
|
|
|
|
};
|
|
|
|
|
|
|
|
DiskImage();
|
|
|
|
|
|
|
|
bool OpenD64(const FILINFO* fileInfo, unsigned char* diskImage, unsigned size);
|
|
|
|
bool OpenG64(const FILINFO* fileInfo, unsigned char* diskImage, unsigned size);
|
|
|
|
bool OpenNIB(const FILINFO* fileInfo, unsigned char* diskImage, unsigned size);
|
|
|
|
bool OpenNBZ(const FILINFO* fileInfo, unsigned char* diskImage, unsigned size);
|
2018-09-23 07:22:01 +00:00
|
|
|
bool OpenD71(const FILINFO* fileInfo, unsigned char* diskImage, unsigned size);
|
|
|
|
bool OpenD81(const FILINFO* fileInfo, unsigned char* diskImage, unsigned size);
|
|
|
|
|
2018-05-20 04:53:34 +00:00
|
|
|
void Close();
|
|
|
|
|
|
|
|
bool GetDecodedSector(u32 track, u32 sector, u8* buffer);
|
|
|
|
|
|
|
|
inline bool GetNextBit(u32 track, u32 byte, u32 bit)
|
|
|
|
{
|
2018-09-23 07:22:01 +00:00
|
|
|
//if (attachedImageSize == 0)
|
|
|
|
// return 0;
|
2018-05-20 04:53:34 +00:00
|
|
|
|
|
|
|
return ((tracks[track][byte] >> bit) & 1) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void SetBit(u32 track, u32 byte, u32 bit, bool value)
|
|
|
|
{
|
|
|
|
if (attachedImageSize == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
u8 dataOld = tracks[track][byte];
|
|
|
|
u8 bitMask = 1 << bit;
|
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
TestDirty(track, (dataOld & bitMask) == 0);
|
|
|
|
tracks[track][byte] |= bitMask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TestDirty(track, (dataOld & bitMask) != 0);
|
|
|
|
tracks[track][byte] &= ~bitMask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const unsigned char SectorsPerTrack[42];
|
|
|
|
|
|
|
|
void DumpTrack(unsigned track);
|
|
|
|
|
|
|
|
const char* GetName() { return fileInfo->fname; }
|
|
|
|
|
|
|
|
inline unsigned BitsInTrack(unsigned track) const { return trackLengths[track] << 3; }
|
2018-09-23 07:22:01 +00:00
|
|
|
inline unsigned TrackLength(unsigned track) const { return trackLengths[track]; }
|
|
|
|
|
|
|
|
inline bool IsD81() const { return diskType == D81; }
|
|
|
|
inline unsigned char GetD81Byte(unsigned track, unsigned headIndex, unsigned headPos) const { return tracksD81[track][headIndex][headPos]; }
|
|
|
|
inline void SetD81Byte(unsigned track, unsigned headIndex, unsigned headPos, unsigned char data)
|
|
|
|
{
|
|
|
|
//unsigned headDataOffset;
|
|
|
|
//if (headPos > 0)
|
|
|
|
// headDataOffset = headPos - 1;
|
|
|
|
//else
|
|
|
|
// headDataOffset = trackLengths[track] - 1;
|
|
|
|
//if (tracksD81[track][headIndex][headDataOffset] != data)
|
|
|
|
//{
|
|
|
|
// tracksD81[track][headIndex][headDataOffset] = data;
|
|
|
|
// trackDirty[track] = true;
|
|
|
|
// trackUsed[track] = true;
|
|
|
|
// dirty = true;
|
|
|
|
//}
|
|
|
|
|
|
|
|
if (tracksD81[track][headIndex][headPos] != data)
|
|
|
|
{
|
|
|
|
tracksD81[track][headIndex][headPos] = data;
|
|
|
|
trackDirty[track] = true;
|
|
|
|
trackUsed[track] = true;
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//unsigned headDataOffset;
|
|
|
|
//if (headPos < trackLengths[track])
|
|
|
|
// headDataOffset = headPos + 1;
|
|
|
|
//else
|
|
|
|
// headDataOffset = 0;
|
|
|
|
//if (tracksD81[track][headIndex][headDataOffset] != data)
|
|
|
|
//{
|
|
|
|
// tracksD81[track][headIndex][headDataOffset] = data;
|
|
|
|
// trackDirty[track] = true;
|
|
|
|
// trackUsed[track] = true;
|
|
|
|
// dirty = true;
|
|
|
|
//}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool IsD81ByteASync(unsigned track, unsigned headIndex, unsigned headPos) const
|
|
|
|
{
|
|
|
|
return (trackD81SyncBits[track][headIndex][headPos >> 3] & (1 << (headPos & 7))) != 0;
|
|
|
|
}
|
|
|
|
inline void SetD81SyncBit(unsigned track, unsigned headIndex, unsigned headPos, bool sync)
|
|
|
|
{
|
|
|
|
if (sync)
|
|
|
|
trackD81SyncBits[track][headIndex][headPos >> 3] |= 1 << (headPos & 7);
|
|
|
|
else
|
|
|
|
trackD81SyncBits[track][headIndex][headPos >> 3] &= ~(1 << (headPos & 7));
|
|
|
|
|
|
|
|
}
|
2018-05-20 04:53:34 +00:00
|
|
|
|
|
|
|
static DiskType GetDiskImageTypeViaExtention(const char* diskImageName);
|
|
|
|
static bool IsDiskImageExtention(const char* diskImageName);
|
2018-09-23 07:22:01 +00:00
|
|
|
static bool IsDiskImageD81Extention(const char* diskImageName);
|
|
|
|
static bool IsDiskImageD71Extention(const char* diskImageName);
|
2018-05-20 04:53:34 +00:00
|
|
|
static bool IsLSTExtention(const char* diskImageName);
|
|
|
|
|
|
|
|
bool GetReadOnly() const { return readOnly; }
|
|
|
|
void SetReadOnly(bool readOnly) { this->readOnly = readOnly; }
|
|
|
|
|
|
|
|
unsigned LastTrackUsed();
|
|
|
|
|
2018-06-11 09:31:24 +00:00
|
|
|
bool IsDirty() const { return dirty; }
|
|
|
|
|
2018-05-20 04:53:34 +00:00
|
|
|
static unsigned char readBuffer[READBUFFER_SIZE];
|
|
|
|
|
2018-09-23 07:22:01 +00:00
|
|
|
static void CRC(unsigned short& runningCRC, unsigned char data);
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
unsigned char tracks[HALF_TRACK_COUNT][MAX_TRACK_LENGTH];
|
|
|
|
unsigned char tracksD81[HALF_TRACK_COUNT][2][MAX_TRACK_LENGTH];
|
|
|
|
};
|
|
|
|
|
2018-05-20 04:53:34 +00:00
|
|
|
private:
|
|
|
|
void CloseD64();
|
|
|
|
void CloseG64();
|
|
|
|
void CloseNIB();
|
|
|
|
void CloseNBZ();
|
2018-09-23 07:22:01 +00:00
|
|
|
void CloseD71();
|
|
|
|
void CloseD81();
|
2018-05-20 04:53:34 +00:00
|
|
|
|
|
|
|
bool WriteD64();
|
|
|
|
bool WriteG64();
|
|
|
|
bool WriteNIB();
|
|
|
|
bool WriteNBZ();
|
2018-09-23 07:22:01 +00:00
|
|
|
bool WriteD71();
|
|
|
|
bool WriteD81();
|
2018-05-20 04:53:34 +00:00
|
|
|
|
|
|
|
inline void TestDirty(u32 track, bool isDirty)
|
|
|
|
{
|
|
|
|
if (isDirty)
|
|
|
|
{
|
|
|
|
trackDirty[track] = true;
|
|
|
|
trackUsed[track] = true;
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ConvertSector(unsigned track, unsigned sector, unsigned char* buffer);
|
|
|
|
void DecodeBlock(unsigned track, int bitIndex, unsigned char* buf, int num);
|
|
|
|
unsigned GetID(unsigned track, unsigned char* id);
|
|
|
|
int FindSectorHeader(unsigned track, unsigned sector, unsigned char* id);
|
|
|
|
int FindSync(unsigned track, int bitIndex, int maxBits, int* syncStartIndex = 0);
|
|
|
|
|
2018-09-23 07:22:01 +00:00
|
|
|
void OutputD81HeaderByte(unsigned char*& dest, unsigned char byte);
|
|
|
|
void OutputD81DataByte(unsigned char*& src, unsigned char*& dest);
|
|
|
|
|
2018-05-20 04:53:34 +00:00
|
|
|
bool readOnly;
|
|
|
|
bool dirty;
|
|
|
|
unsigned attachedImageSize;
|
|
|
|
DiskType diskType;
|
|
|
|
const FILINFO* fileInfo;
|
|
|
|
|
|
|
|
unsigned short trackLengths[HALF_TRACK_COUNT];
|
2018-09-23 07:22:01 +00:00
|
|
|
union
|
|
|
|
{
|
|
|
|
unsigned char trackDensity[HALF_TRACK_COUNT];
|
|
|
|
unsigned char trackD81SyncBits[HALF_TRACK_COUNT][2][MAX_TRACK_LENGTH >> 3];
|
|
|
|
};
|
2018-05-20 04:53:34 +00:00
|
|
|
bool trackDirty[HALF_TRACK_COUNT];
|
|
|
|
bool trackUsed[HALF_TRACK_COUNT];
|
2018-09-23 07:22:01 +00:00
|
|
|
|
|
|
|
unsigned short crc;
|
|
|
|
static unsigned short CRC1021[256];
|
2018-05-20 04:53:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|