mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-12-29 08:30:04 +00:00
Write support for WOZ1/WOZ2 images (#756)
Also: - Allow creation of a blank (WOZ2) image - multi-zip support extended to scan for the first valid image (useful for most woz-a-day zips which have at least 2 entries and were previously failing)
This commit is contained in:
parent
d07558b610
commit
4956957ca1
185
source/Disk.cpp
185
source/Disk.cpp
@ -282,6 +282,12 @@ void Disk2InterfaceCard::ReadTrack(const int drive, ULONG uExecutedCycles)
|
||||
if (ImagePhaseToTrack(pFloppy->m_imagehandle, pDrive->m_phasePrecise, false) >= ImageGetNumTracks(pFloppy->m_imagehandle))
|
||||
{
|
||||
_ASSERT(0); // What can cause this? Add a comment to replace this assert.
|
||||
// Boot with DOS 3.3 Master in D1
|
||||
// Create a blank disk in D2
|
||||
// INIT HELLO,D2
|
||||
// RUN HELLO
|
||||
// F2 to reboot DOS 3.3 Master
|
||||
// RUN HELLO,D2
|
||||
pFloppy->m_trackimagedata = false;
|
||||
return;
|
||||
}
|
||||
@ -729,17 +735,6 @@ void Disk2InterfaceCard::NotifyInvalidImage(const int drive, LPCTSTR pszImageFil
|
||||
pszImageFilename);
|
||||
break;
|
||||
|
||||
case eIMAGE_ERROR_UNSUPPORTED_MULTI_ZIP:
|
||||
StringCbPrintf(
|
||||
szBuffer,
|
||||
MAX_PATH + 128,
|
||||
TEXT("Unable to use the file %s\nbecause the ")
|
||||
TEXT("first file (%s) in this multi-zip archive is not recognized.\n")
|
||||
TEXT("Try unzipping and using the disk images directly.\n"),
|
||||
pszImageFilename,
|
||||
m_floppyDrive[drive].m_disk.m_strFilenameInZip.c_str());
|
||||
break;
|
||||
|
||||
case eIMAGE_ERROR_GZ:
|
||||
case eIMAGE_ERROR_ZIP:
|
||||
StringCbPrintf(
|
||||
@ -984,24 +979,18 @@ void Disk2InterfaceCard::ResetLogicStateSequencer(void)
|
||||
m_shiftReg = 0;
|
||||
m_latchDelay = 0;
|
||||
m_resetSequencer = true;
|
||||
m_writeStarted = false;
|
||||
m_dbgLatchDelayedCnt = 0;
|
||||
}
|
||||
|
||||
void Disk2InterfaceCard::UpdateBitStreamPositionAndDiskCycle(const ULONG uExecutedCycles)
|
||||
UINT Disk2InterfaceCard::GetBitCellDelta(const ULONG uExecutedCycles)
|
||||
{
|
||||
FloppyDisk& floppy = m_floppyDrive[m_currDrive].m_disk;
|
||||
|
||||
CpuCalcCycles(uExecutedCycles);
|
||||
const UINT bitCellDelta = GetBitCellDelta(ImageGetOptimalBitTiming(floppy.m_imagehandle));
|
||||
UpdateBitStreamPosition(floppy, bitCellDelta);
|
||||
|
||||
m_diskLastCycle = g_nCumulativeCycles;
|
||||
}
|
||||
|
||||
UINT Disk2InterfaceCard::GetBitCellDelta(const BYTE optimalBitTiming)
|
||||
{
|
||||
FloppyDisk& floppy = m_floppyDrive[m_currDrive].m_disk;
|
||||
|
||||
const BYTE optimalBitTiming = ImageGetOptimalBitTiming(floppy.m_imagehandle);
|
||||
|
||||
// NB. m_extraCycles is needed to retain accuracy:
|
||||
// . Read latch #1: 0-> 9: cycleDelta= 9, bitCellDelta=2, extraCycles=1
|
||||
// . Read latch #2: 9->20: cycleDelta=11, bitCellDelta=2, extraCycles=3
|
||||
@ -1010,9 +999,9 @@ UINT Disk2InterfaceCard::GetBitCellDelta(const BYTE optimalBitTiming)
|
||||
#if 0
|
||||
if (optimalBitTiming == 32)
|
||||
{
|
||||
const ULONG cycleDelta = (ULONG)(g_nCumulativeCycles - m_diskLastCycle) + (BYTE) m_extraCycles;
|
||||
const ULONG cycleDelta = (ULONG)(g_nCumulativeCycles - m_diskLastCycle) + (BYTE) floppy.m_extraCycles;
|
||||
bitCellDelta = cycleDelta / 4; // DIV 4 for 4us per bit-cell
|
||||
m_extraCycles = cycleDelta & 3; // MOD 4 : remainder carried forward for next time
|
||||
floppy.m_extraCycles = cycleDelta & 3; // MOD 4 : remainder carried forward for next time
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -1022,6 +1011,11 @@ UINT Disk2InterfaceCard::GetBitCellDelta(const BYTE optimalBitTiming)
|
||||
bitCellDelta = (UINT) floor( cycleDelta / bitTime );
|
||||
floppy.m_extraCycles = (double)cycleDelta - ((double)bitCellDelta * bitTime);
|
||||
}
|
||||
|
||||
// NB. actual m_diskLastCycle for the last bitCell is minus floppy.m_extraCycles
|
||||
// - but don't need this value; and it's correctly accounted for in this function.
|
||||
m_diskLastCycle = g_nCumulativeCycles;
|
||||
|
||||
return bitCellDelta;
|
||||
}
|
||||
|
||||
@ -1036,6 +1030,8 @@ void Disk2InterfaceCard::UpdateBitStreamPosition(FloppyDisk& floppy, const ULONG
|
||||
floppy.m_bitOffset %= floppy.m_bitCount;
|
||||
|
||||
UpdateBitStreamOffsets(floppy);
|
||||
|
||||
m_resetSequencer = false;
|
||||
}
|
||||
|
||||
void Disk2InterfaceCard::UpdateBitStreamOffsets(FloppyDisk& floppy)
|
||||
@ -1045,8 +1041,28 @@ void Disk2InterfaceCard::UpdateBitStreamOffsets(FloppyDisk& floppy)
|
||||
floppy.m_bitMask = 1 << remainder;
|
||||
}
|
||||
|
||||
void __stdcall Disk2InterfaceCard::DataLatchReadWriteWOZ(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles)
|
||||
__forceinline void Disk2InterfaceCard::IncBitStream(FloppyDisk& floppy)
|
||||
{
|
||||
floppy.m_bitMask >>= 1;
|
||||
if (!floppy.m_bitMask)
|
||||
{
|
||||
floppy.m_bitMask = 1 << 7;
|
||||
floppy.m_byte++;
|
||||
}
|
||||
|
||||
floppy.m_bitOffset++;
|
||||
if (floppy.m_bitOffset == floppy.m_bitCount)
|
||||
{
|
||||
floppy.m_bitMask = 1 << 7;
|
||||
floppy.m_bitOffset = 0;
|
||||
floppy.m_byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void __stdcall Disk2InterfaceCard::DataLatchReadWriteWOZ(WORD pc, WORD addr, BYTE bWrite, ULONG uExecutedCycles)
|
||||
{
|
||||
_ASSERT(m_seqFunc.function != dataShiftWrite);
|
||||
|
||||
FloppyDrive& drive = m_floppyDrive[m_currDrive];
|
||||
FloppyDisk& floppy = drive.m_disk;
|
||||
|
||||
@ -1067,14 +1083,11 @@ void __stdcall Disk2InterfaceCard::DataLatchReadWriteWOZ(WORD pc, WORD addr, BYT
|
||||
if (!drive.m_spinning) // GH#599
|
||||
return;
|
||||
|
||||
CpuCalcCycles(uExecutedCycles);
|
||||
|
||||
// Skipping forward a large amount of bitcells means the bitstream will very likely be out-of-sync.
|
||||
// The first 1-bit will produce a latch nibble, and this 1-bit is unlikely to be the nibble's high bit.
|
||||
// So we need to ensure we run enough bits through the sequencer to re-sync.
|
||||
// NB. For Planetfall 13 bitcells(NG) / 14 bitcells(OK)
|
||||
const UINT significantBitCells = 50; // 5x 10-bit sync FF nibbles
|
||||
UINT bitCellDelta = GetBitCellDelta(ImageGetOptimalBitTiming(floppy.m_imagehandle));
|
||||
UINT bitCellDelta = GetBitCellDelta(uExecutedCycles);
|
||||
|
||||
UINT bitCellRemainder;
|
||||
if (bitCellDelta <= significantBitCells)
|
||||
@ -1092,20 +1105,21 @@ void __stdcall Disk2InterfaceCard::DataLatchReadWriteWOZ(WORD pc, WORD addr, BYT
|
||||
drive.m_headWindow = 0;
|
||||
}
|
||||
|
||||
// NB. actual m_diskLastCycle for the last bitCell is minus floppy.m_extraCycles
|
||||
// - but don't need this value; and it's correctly accounted for in GetBitCellDelta()
|
||||
m_diskLastCycle = g_nCumulativeCycles;
|
||||
|
||||
if (!bWrite)
|
||||
{
|
||||
if (m_seqFunc.function != readSequencing)
|
||||
{
|
||||
_ASSERT(m_seqFunc.function == checkWriteProtAndInitWrite);
|
||||
UpdateBitStreamPosition(floppy, bitCellRemainder);
|
||||
return;
|
||||
}
|
||||
|
||||
DataLatchReadWOZ(pc, addr, bitCellRemainder);
|
||||
}
|
||||
else
|
||||
{
|
||||
DataLatchWriteWOZ(pc, addr, d, bitCellRemainder);
|
||||
_ASSERT(m_seqFunc.function == dataLoadWrite);
|
||||
DataLoadWriteWOZ(pc, addr, bitCellRemainder);
|
||||
}
|
||||
|
||||
// Show track status (GH#201) - NB. Prevent flooding of forcing UI to redraw!!!
|
||||
@ -1147,20 +1161,7 @@ void Disk2InterfaceCard::DataLatchReadWOZ(WORD pc, WORD addr, UINT bitCellRemain
|
||||
BYTE outputBit = (drive.m_headWindow & 0xf) ? (drive.m_headWindow >> 1) & 1
|
||||
: (rand() < ((RAND_MAX * 3) / 10)) ? 1 : 0; // ~30% chance of a 1 bit (Ref: WOZ-2.0)
|
||||
|
||||
floppy.m_bitMask >>= 1;
|
||||
if (!floppy.m_bitMask)
|
||||
{
|
||||
floppy.m_bitMask = 1 << 7;
|
||||
floppy.m_byte++;
|
||||
}
|
||||
|
||||
floppy.m_bitOffset++;
|
||||
if (floppy.m_bitOffset == floppy.m_bitCount)
|
||||
{
|
||||
floppy.m_bitMask = 1 << 7;
|
||||
floppy.m_bitOffset = 0;
|
||||
floppy.m_byte = 0;
|
||||
}
|
||||
IncBitStream(floppy);
|
||||
|
||||
if (m_resetSequencer)
|
||||
{
|
||||
@ -1238,17 +1239,64 @@ void Disk2InterfaceCard::DataLatchReadWOZ(WORD pc, WORD addr, UINT bitCellRemain
|
||||
#endif
|
||||
}
|
||||
|
||||
void Disk2InterfaceCard::DataLatchWriteWOZ(WORD pc, WORD addr, BYTE d, UINT bitCellRemainder)
|
||||
void Disk2InterfaceCard::DataLoadWriteWOZ(WORD pc, WORD addr, UINT bitCellRemainder)
|
||||
{
|
||||
_ASSERT(m_seqFunc.writeMode);
|
||||
_ASSERT(m_seqFunc.function == dataLoadWrite);
|
||||
|
||||
FloppyDrive& drive = m_floppyDrive[m_currDrive];
|
||||
FloppyDisk& floppy = drive.m_disk;
|
||||
|
||||
if (!floppy.m_bWriteProtected)
|
||||
if (floppy.m_bWriteProtected)
|
||||
{
|
||||
//TODO
|
||||
_ASSERT(0); // Must be a bug in the 6502 code for this to occur!
|
||||
UpdateBitStreamPosition(floppy, bitCellRemainder);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_writeStarted)
|
||||
UpdateBitStreamPosition(floppy, bitCellRemainder); // skip over bitCells before switching to write mode
|
||||
|
||||
m_writeStarted = true;
|
||||
#if LOG_DISK_WOZ_LOADWRITE
|
||||
LOG_DISK("load shiftReg with %02X (was: %02X)\n", m_floppyLatch, m_shiftReg);
|
||||
#endif
|
||||
m_shiftReg = m_floppyLatch;
|
||||
}
|
||||
|
||||
void Disk2InterfaceCard::DataShiftWriteWOZ(WORD pc, WORD addr, ULONG uExecutedCycles)
|
||||
{
|
||||
_ASSERT(m_seqFunc.function == dataShiftWrite);
|
||||
|
||||
FloppyDrive& drive = m_floppyDrive[m_currDrive];
|
||||
FloppyDisk& floppy = drive.m_disk;
|
||||
|
||||
const UINT bitCellRemainder = GetBitCellDelta(uExecutedCycles);
|
||||
|
||||
if (floppy.m_bWriteProtected)
|
||||
{
|
||||
_ASSERT(0); // Must be a bug in the 6502 code for this to occur!
|
||||
UpdateBitStreamPosition(floppy, bitCellRemainder);
|
||||
return;
|
||||
}
|
||||
|
||||
#if LOG_DISK_WOZ_SHIFTWRITE
|
||||
LOG_DISK("T$%02X, bitOffset=%04X: %02X (%d bits)\n", drive.m_phase/2, floppy.m_bitOffset, m_shiftReg, bitCellRemainder);
|
||||
#endif
|
||||
|
||||
for (UINT i = 0; i < bitCellRemainder; i++)
|
||||
{
|
||||
BYTE outputBit = m_shiftReg & 0x80;
|
||||
m_shiftReg <<= 1;
|
||||
|
||||
BYTE n = floppy.m_trackimage[floppy.m_byte];
|
||||
n &= ~floppy.m_bitMask;
|
||||
if (outputBit) n |= floppy.m_bitMask;
|
||||
floppy.m_trackimage[floppy.m_byte] = n;
|
||||
|
||||
IncBitStream(floppy);
|
||||
}
|
||||
|
||||
floppy.m_trackimagedirty = true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
@ -1485,7 +1533,9 @@ bool Disk2InterfaceCard::UserSelectNewDiskImage(const int drive, LPCSTR pszFilen
|
||||
|
||||
void __stdcall Disk2InterfaceCard::LoadWriteProtect(WORD, WORD, BYTE write, BYTE value, ULONG uExecutedCycles)
|
||||
{
|
||||
// NB. m_seqFunc.function == checkWriteProtAndInitWrite or shiftWrite (both OK)
|
||||
// NB. Only reads in LOAD mode can issue the SR (shift write-protect) operation - UTAIIe page 9-20, fig 9.11
|
||||
// But STA $C08D,X (no PX) does a read from $C08D+X, followed by the write to $C08D+X
|
||||
// So just want to ignore: STA $C0ED or eg. STA $BFFF,X (PX, X=$EE)
|
||||
|
||||
// Don't change latch if drive off after 1 second drive-off delay (UTAIIe page 9-13)
|
||||
// "DRIVES OFF forces the data register to hold its present state." (UTAIIe page 9-12)
|
||||
@ -1500,20 +1550,27 @@ void __stdcall Disk2InterfaceCard::LoadWriteProtect(WORD, WORD, BYTE write, BYTE
|
||||
// the write protect switch would still be read correctly" (UTAIIe page 9-21)
|
||||
// . Sequencer "SR" (Shift Right) command only loads QA (bit7) of data register (UTAIIe page 9-21)
|
||||
// . A read or write will shift 'write protect' in QA.
|
||||
if (m_floppyDrive[m_currDrive].m_disk.m_bWriteProtected)
|
||||
FloppyDisk& floppy = m_floppyDrive[m_currDrive].m_disk;
|
||||
if (floppy.m_bWriteProtected)
|
||||
m_floppyLatch |= 0x80;
|
||||
else
|
||||
m_floppyLatch &= 0x7F;
|
||||
|
||||
if (ImageIsWOZ(m_floppyDrive[m_currDrive].m_disk.m_imagehandle))
|
||||
if (m_writeStarted) // Prevent ResetLogicStateSequencer() from resetting m_writeStarted
|
||||
return;
|
||||
|
||||
if (ImageIsWOZ(floppy.m_imagehandle))
|
||||
{
|
||||
#if LOG_DISK_NIBBLES_READ
|
||||
CpuCalcCycles(uExecutedCycles);
|
||||
LOG_DISK("%08X: reset LSS: ~PC=%04X\r\n", (UINT32)g_nCumulativeCycles, regs.pc);
|
||||
#endif
|
||||
|
||||
const UINT bitCellDelta = GetBitCellDelta(uExecutedCycles);
|
||||
UpdateBitStreamPosition(floppy, bitCellDelta); // Fix E7-copy protection
|
||||
|
||||
// UpdateBitStreamPosition() must be done below ResetLSS, as the former clears m_resetSequencer. (Commando.woz is sensitive to this)
|
||||
ResetLogicStateSequencer(); // reset sequencer (UTAIIe page 9-21)
|
||||
// m_latchDelay = 7; // TODO: Treat like a regular $C0EC latch load?
|
||||
UpdateBitStreamPositionAndDiskCycle(uExecutedCycles); // Fix E7-copy protection
|
||||
}
|
||||
}
|
||||
|
||||
@ -1688,6 +1745,9 @@ void Disk2InterfaceCard::SetSequencerFunction(WORD addr)
|
||||
case 2: m_seqFunc.loadMode = 0; break; // $C08C,X (sequence addr A3 input)
|
||||
case 3: m_seqFunc.loadMode = 1; break; // $C08D,X (sequence addr A3 input)
|
||||
}
|
||||
|
||||
if (!m_seqFunc.writeMode)
|
||||
m_writeStarted = false;
|
||||
}
|
||||
|
||||
BYTE __stdcall Disk2InterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
|
||||
@ -1698,6 +1758,9 @@ BYTE __stdcall Disk2InterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE
|
||||
ImageInfo* pImage = pCard->m_floppyDrive[pCard->m_currDrive].m_disk.m_imagehandle;
|
||||
bool isWOZ = ImageIsWOZ(pImage);
|
||||
|
||||
if (isWOZ && pCard->m_seqFunc.function == dataShiftWrite) // Occurs at end of sector write ($C0EE)
|
||||
pCard->DataShiftWriteWOZ(pc, addr, nExecutedCycles); // Finish any previous write
|
||||
|
||||
pCard->SetSequencerFunction(addr);
|
||||
|
||||
switch (addr & 0xF)
|
||||
@ -1723,8 +1786,8 @@ BYTE __stdcall Disk2InterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE
|
||||
// only even addresses return the latch (UTAIIe Table 9.1)
|
||||
if (!(addr & 1))
|
||||
{
|
||||
if (isWOZ)
|
||||
pCard->DataLatchReadWriteWOZ(pc, addr, bWrite, d, nExecutedCycles);
|
||||
if (isWOZ && pCard->m_seqFunc.function != dataShiftWrite)
|
||||
pCard->DataLatchReadWriteWOZ(pc, addr, bWrite, nExecutedCycles);
|
||||
|
||||
return pCard->m_floppyLatch;
|
||||
}
|
||||
@ -1740,6 +1803,9 @@ BYTE __stdcall Disk2InterfaceCard::IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE
|
||||
ImageInfo* pImage = pCard->m_floppyDrive[pCard->m_currDrive].m_disk.m_imagehandle;
|
||||
bool isWOZ = ImageIsWOZ(pImage);
|
||||
|
||||
if (isWOZ && pCard->m_seqFunc.function == dataShiftWrite)
|
||||
pCard->DataShiftWriteWOZ(pc, addr, nExecutedCycles); // Finish any previous write
|
||||
|
||||
pCard->SetSequencerFunction(addr);
|
||||
|
||||
switch (addr & 0xF)
|
||||
@ -1763,13 +1829,12 @@ BYTE __stdcall Disk2InterfaceCard::IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE
|
||||
}
|
||||
|
||||
// any address writes the latch via sequencer LD command (74LS323 datasheet)
|
||||
// if (pCard->m_seqFunc.writeMode /* && m_seqFunc.loadMode */)
|
||||
if (pCard->m_seqFunc.function == dataLoadWrite)
|
||||
{
|
||||
pCard->m_floppyLatch = d;
|
||||
|
||||
if (isWOZ)
|
||||
pCard->DataLatchReadWriteWOZ(pc, addr, bWrite, d, nExecutedCycles);
|
||||
pCard->DataLatchReadWriteWOZ(pc, addr, bWrite, nExecutedCycles);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -185,12 +185,13 @@ private:
|
||||
void WriteTrack(const int drive);
|
||||
const std::string & DiskGetFullPathName(const int drive);
|
||||
void ResetLogicStateSequencer(void);
|
||||
void UpdateBitStreamPositionAndDiskCycle(const ULONG uExecutedCycles);
|
||||
UINT GetBitCellDelta(const BYTE optimalBitTiming);
|
||||
UINT GetBitCellDelta(const ULONG uExecutedCycles);
|
||||
void UpdateBitStreamPosition(FloppyDisk& floppy, const ULONG bitCellDelta);
|
||||
void UpdateBitStreamOffsets(FloppyDisk& floppy);
|
||||
__forceinline void IncBitStream(FloppyDisk& floppy);
|
||||
void DataLatchReadWOZ(WORD pc, WORD addr, UINT bitCellRemainder);
|
||||
void DataLatchWriteWOZ(WORD pc, WORD addr, BYTE d, UINT bitCellRemainder);
|
||||
void DataLoadWriteWOZ(WORD pc, WORD addr, UINT bitCellRemainder);
|
||||
void DataShiftWriteWOZ(WORD pc, WORD addr, ULONG uExecutedCycles);
|
||||
void SetSequencerFunction(WORD addr);
|
||||
void DumpSectorWOZ(FloppyDisk floppy);
|
||||
void DumpTrackWOZ(FloppyDisk floppy);
|
||||
@ -206,7 +207,7 @@ private:
|
||||
void __stdcall ControlMotor(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles);
|
||||
void __stdcall Enable(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles);
|
||||
void __stdcall ReadWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
|
||||
void __stdcall DataLatchReadWriteWOZ(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
|
||||
void __stdcall DataLatchReadWriteWOZ(WORD pc, WORD addr, BYTE bWrite, ULONG uExecutedCycles);
|
||||
void __stdcall LoadWriteProtect(WORD, WORD, BYTE write, BYTE value, ULONG);
|
||||
void __stdcall SetReadMode(WORD, WORD, BYTE, BYTE, ULONG);
|
||||
void __stdcall SetWriteMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles);
|
||||
@ -240,8 +241,9 @@ private:
|
||||
BYTE m_shiftReg;
|
||||
int m_latchDelay;
|
||||
bool m_resetSequencer;
|
||||
bool m_writeStarted;
|
||||
|
||||
enum SEQFUNC {readSequencing=0, checkWriteProtAndInitWrite, dataShiftWrite, dataLoadWrite}; // UTAIIe 9-14
|
||||
enum SEQFUNC {readSequencing=0, dataShiftWrite, checkWriteProtAndInitWrite, dataLoadWrite}; // UTAIIe 9-14
|
||||
union SEQUENCER_FUNCTION
|
||||
{
|
||||
struct
|
||||
|
@ -63,7 +63,7 @@ ImageError_e ImageOpen( const std::string & pszImageFilename,
|
||||
ImageError_e Err = pImageInfo->pImageHelper->Open(pszImageFilename.c_str(), pImageInfo, bCreateIfNecessary, strFilenameInZip);
|
||||
if (Err != eIMAGE_ERROR_NONE)
|
||||
{
|
||||
ImageClose(*ppImageInfo, true);
|
||||
ImageClose(*ppImageInfo);
|
||||
*ppImageInfo = NULL;
|
||||
return Err;
|
||||
}
|
||||
@ -83,9 +83,6 @@ ImageError_e ImageOpen( const std::string & pszImageFilename,
|
||||
|
||||
pImageInfo->uNumTracks = sg_DiskImageHelper.GetNumTracksInImage(pImageInfo->pImageType);
|
||||
|
||||
for (UINT uTrack = 0; uTrack < pImageInfo->uNumTracks; uTrack++)
|
||||
pImageInfo->ValidTrack[uTrack] = (pImageInfo->uImageSize > 0) ? 1 : 0;
|
||||
|
||||
*pWriteProtected = pImageInfo->bWriteProtected;
|
||||
|
||||
return eIMAGE_ERROR_NONE;
|
||||
@ -93,25 +90,9 @@ ImageError_e ImageOpen( const std::string & pszImageFilename,
|
||||
|
||||
//===========================================================================
|
||||
|
||||
void ImageClose(ImageInfo* const pImageInfo, const bool bOpenError /*=false*/)
|
||||
void ImageClose(ImageInfo* const pImageInfo)
|
||||
{
|
||||
bool bDeleteFile = false;
|
||||
|
||||
if (!bOpenError)
|
||||
{
|
||||
for (UINT uTrack = 0; uTrack < pImageInfo->uNumTracks; uTrack++)
|
||||
{
|
||||
if (!pImageInfo->ValidTrack[uTrack])
|
||||
{
|
||||
// TODO: Comment using info from this URL:
|
||||
// http://groups.google.de/group/comp.emulators.apple2/msg/7a1b9317e7905152
|
||||
bDeleteFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pImageInfo->pImageHelper->Close(pImageInfo, bDeleteFile);
|
||||
pImageInfo->pImageHelper->Close(pImageInfo);
|
||||
|
||||
delete pImageInfo;
|
||||
}
|
||||
@ -162,7 +143,7 @@ void ImageReadTrack( ImageInfo* const pImageInfo,
|
||||
|
||||
const UINT track = pImageInfo->pImageType->PhaseToTrack(phase);
|
||||
|
||||
if (pImageInfo->pImageType->AllowRW() && pImageInfo->ValidTrack[track])
|
||||
if (pImageInfo->pImageType->AllowRW())
|
||||
{
|
||||
pImageInfo->pImageType->Read(pImageInfo, phase, pTrackImageBuffer, pNibbles, pBitCount, enhanceDisk);
|
||||
}
|
||||
@ -190,7 +171,14 @@ void ImageWriteTrack( ImageInfo* const pImageInfo,
|
||||
if (pImageInfo->pImageType->AllowRW() && !pImageInfo->bWriteProtected)
|
||||
{
|
||||
pImageInfo->pImageType->Write(pImageInfo, phase, pTrackImageBuffer, nNibbles);
|
||||
pImageInfo->ValidTrack[track] = 1;
|
||||
|
||||
eImageType imageType = pImageInfo->pImageType->GetType();
|
||||
if (imageType == eImageWOZ1 || imageType == eImageWOZ2)
|
||||
{
|
||||
DWORD dummy;
|
||||
bool res = sg_DiskImageHelper.WOZUpdateInfo(pImageInfo, dummy);
|
||||
_ASSERT(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,7 +222,7 @@ bool ImageIsWriteProtected(ImageInfo* const pImageInfo)
|
||||
|
||||
bool ImageIsMultiFileZip(ImageInfo* const pImageInfo)
|
||||
{
|
||||
return pImageInfo ? (pImageInfo->uNumEntriesInZip > 1) : false;
|
||||
return pImageInfo ? (pImageInfo->uNumValidImagesInZip > 1) : false;
|
||||
}
|
||||
|
||||
const std::string & ImageGetPathname(ImageInfo* const pImageInfo)
|
||||
|
@ -51,7 +51,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
eIMAGE_ERROR_GZ,
|
||||
eIMAGE_ERROR_ZIP,
|
||||
eIMAGE_ERROR_REJECTED_MULTI_ZIP,
|
||||
eIMAGE_ERROR_UNSUPPORTED_MULTI_ZIP,
|
||||
eIMAGE_ERROR_UNABLE_TO_OPEN,
|
||||
eIMAGE_ERROR_UNABLE_TO_OPEN_GZ,
|
||||
eIMAGE_ERROR_UNABLE_TO_OPEN_ZIP,
|
||||
@ -66,7 +65,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
struct ImageInfo;
|
||||
|
||||
ImageError_e ImageOpen(const std::string & pszImageFilename, ImageInfo** ppImageInfo, bool* pWriteProtected, const bool bCreateIfNecessary, std::string& strFilenameInZip, const bool bExpectFloppy=true);
|
||||
void ImageClose(ImageInfo* const pImageInfo, const bool bOpenError=false);
|
||||
void ImageClose(ImageInfo* const pImageInfo);
|
||||
BOOL ImageBoot(ImageInfo* const pImageInfo);
|
||||
void ImageDestroy(void);
|
||||
void ImageInitialize(void);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,11 +31,11 @@ struct ImageInfo
|
||||
std::string szFilenameInZip;
|
||||
zip_fileinfo zipFileInfo;
|
||||
UINT uNumEntriesInZip;
|
||||
UINT uNumValidImagesInZip;
|
||||
// Floppy only
|
||||
BYTE ValidTrack[TRACKS_MAX];
|
||||
UINT uNumTracks;
|
||||
BYTE* pImageBuffer;
|
||||
BYTE* pTrackMap; // WOZ only
|
||||
BYTE* pWOZTrackMap; // WOZ only (points into pImageBuffer)
|
||||
BYTE optimalBitTiming; // WOZ only
|
||||
UINT maxNibblesPerTrack;
|
||||
|
||||
@ -73,6 +73,7 @@ public:
|
||||
virtual const char* GetCreateExtensions(void) = 0;
|
||||
virtual const char* GetRejectExtensions(void) = 0;
|
||||
|
||||
bool WriteImageHeader(ImageInfo* pImageInfo, LPBYTE pHdr, const UINT hdrSize);
|
||||
void SetVolumeNumber(const BYTE uVolumeNumber) { m_uVolumeNumber = uVolumeNumber; }
|
||||
bool IsValidImageSize(const DWORD uImageSize);
|
||||
|
||||
@ -88,6 +89,7 @@ protected:
|
||||
bool WriteTrack(ImageInfo* pImageInfo, const int nTrack, LPBYTE pTrackBuffer, const UINT uTrackSize);
|
||||
bool ReadBlock(ImageInfo* pImageInfo, const int nBlock, LPBYTE pBlockBuffer);
|
||||
bool WriteBlock(ImageInfo* pImageInfo, const int nBlock, LPBYTE pBlockBuffer);
|
||||
bool WriteImageData(ImageInfo* pImageInfo, LPBYTE pSrcBuffer, const UINT uSrcSize, const long offset);
|
||||
|
||||
LPBYTE Code62(int sector);
|
||||
void Decode62(LPBYTE imageptr);
|
||||
@ -134,6 +136,10 @@ private:
|
||||
#pragma pack(push)
|
||||
#pragma pack(1) // Ensure Header2IMG & WOZ structs are packed
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4200) // Allow zero-sized array in struct
|
||||
|
||||
|
||||
class C2IMGHelper : public CHdrHelper
|
||||
{
|
||||
public:
|
||||
@ -200,10 +206,15 @@ public:
|
||||
virtual ~CWOZHelper(void) {}
|
||||
virtual eDetectResult DetectHdr(LPBYTE& pImage, DWORD& dwImageSize, DWORD& dwOffset) { _ASSERT(0); return eMismatch; }
|
||||
virtual UINT GetMaxHdrSize(void) { return sizeof(WOZHeader); }
|
||||
eDetectResult ProcessChunks(const LPBYTE pImage, const DWORD dwImageSize, DWORD& dwOffset, BYTE*& pTrackMap);
|
||||
eDetectResult ProcessChunks(ImageInfo* pImageInfo, DWORD& dwOffset);
|
||||
bool IsWriteProtected(void) { return m_pInfo->v1.writeProtected == 1; }
|
||||
BYTE GetOptimalBitTiming(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->optimalBitTiming : CWOZHelper::InfoChunkv2::optimalBitTiming5_25; }
|
||||
UINT GetMaxNibblesPerTrack(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->largestTrack*CWOZHelper::BLOCK_SIZE : CWOZHelper::WOZ1_TRACK_SIZE; }
|
||||
BYTE GetOptimalBitTiming(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->optimalBitTiming : InfoChunkv2::optimalBitTiming5_25; }
|
||||
UINT GetMaxNibblesPerTrack(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->largestTrack*CWOZHelper::BLOCK_SIZE : WOZ1_TRACK_SIZE; }
|
||||
void InvalidateInfo(void) { m_pInfo = NULL; }
|
||||
BYTE* CreateEmptyDisk(DWORD& size);
|
||||
#if _DEBUG
|
||||
BYTE* CreateEmptyDiskv1(DWORD& size);
|
||||
#endif
|
||||
|
||||
static const UINT32 ID1_WOZ1 = '1ZOW'; // 'WOZ1'
|
||||
static const UINT32 ID1_WOZ2 = '2ZOW'; // 'WOZ2'
|
||||
@ -217,10 +228,24 @@ public:
|
||||
};
|
||||
|
||||
static const UINT32 MAX_TRACKS_5_25 = 40;
|
||||
static const UINT32 MAX_QUARTER_TRACKS_5_25 = MAX_TRACKS_5_25 * 4;
|
||||
static const UINT32 WOZ1_TRACK_SIZE = 6656; // 0x1A00
|
||||
static const UINT32 WOZ1_TRK_OFFSET = 6646;
|
||||
static const UINT32 EMPTY_TRACK_SIZE = 6400;
|
||||
static const UINT32 EMPTY_TRACK_SIZE = 6400; // $C.5 blocks
|
||||
static const UINT32 BLOCK_SIZE = 512;
|
||||
static const BYTE TMAP_TRACK_EMPTY = 0xFF;
|
||||
static const UINT16 TRK_DEFAULT_BLOCK_COUNT_5_25 = 13; // $D is default for TRKv2.blockCount
|
||||
|
||||
struct WOZChunkHdr
|
||||
{
|
||||
UINT32 id;
|
||||
UINT32 size;
|
||||
};
|
||||
|
||||
struct Tmap
|
||||
{
|
||||
BYTE tmap[MAX_QUARTER_TRACKS_5_25];
|
||||
};
|
||||
|
||||
struct TRKv1
|
||||
{
|
||||
@ -239,17 +264,22 @@ public:
|
||||
UINT32 bitCount;
|
||||
};
|
||||
|
||||
struct Trks
|
||||
{
|
||||
TRKv2 trks[MAX_QUARTER_TRACKS_5_25];
|
||||
BYTE bits[0]; // bits[] starts at offset 3 x BLOCK_SIZE = 1536
|
||||
};
|
||||
|
||||
private:
|
||||
static const UINT32 INFO_CHUNK_ID = 'OFNI'; // 'INFO'
|
||||
static const UINT32 TMAP_CHUNK_ID = 'PAMT'; // 'TMAP'
|
||||
static const UINT32 TRKS_CHUNK_ID = 'SKRT'; // 'TRKS'
|
||||
static const UINT32 WRIT_CHUNK_ID = 'TIRW'; // 'WRIT' - WOZv2
|
||||
static const UINT32 META_CHUNK_ID = 'ATEM'; // 'META'
|
||||
static const UINT32 INFO_CHUNK_SIZE = 60; // Fixed size for both WOZv1 & WOZv2
|
||||
|
||||
struct InfoChunk
|
||||
{
|
||||
UINT32 id;
|
||||
UINT32 size;
|
||||
BYTE version;
|
||||
BYTE diskType;
|
||||
BYTE writeProtected; // 1 = Floppy is write protected
|
||||
@ -281,9 +311,41 @@ private:
|
||||
static const BYTE optimalBitTiming5_25 = 32;
|
||||
};
|
||||
|
||||
InfoChunkv2* m_pInfo;
|
||||
InfoChunkv2* m_pInfo; // NB. image-specific - only valid during Detect(), which calls InvalidateInfo() when done
|
||||
|
||||
//
|
||||
|
||||
struct WOZEmptyImage525 // 5.25"
|
||||
{
|
||||
WOZHeader hdr;
|
||||
|
||||
WOZChunkHdr infoHdr;
|
||||
InfoChunkv2 info;
|
||||
BYTE infoPadding[INFO_CHUNK_SIZE-sizeof(InfoChunkv2)];
|
||||
|
||||
WOZChunkHdr tmapHdr;
|
||||
Tmap tmap;
|
||||
|
||||
WOZChunkHdr trksHdr;
|
||||
Trks trks;
|
||||
};
|
||||
|
||||
struct WOZv1EmptyImage525 // 5.25"
|
||||
{
|
||||
WOZHeader hdr;
|
||||
|
||||
WOZChunkHdr infoHdr;
|
||||
InfoChunk info;
|
||||
BYTE infoPadding[INFO_CHUNK_SIZE-sizeof(InfoChunk)];
|
||||
|
||||
WOZChunkHdr tmapHdr;
|
||||
Tmap tmap;
|
||||
|
||||
WOZChunkHdr trksHdr;
|
||||
};
|
||||
};
|
||||
|
||||
#pragma warning(pop)
|
||||
#pragma pack(pop)
|
||||
|
||||
//-------------------------------------
|
||||
@ -304,7 +366,8 @@ public:
|
||||
}
|
||||
|
||||
ImageError_e Open(LPCTSTR pszImageFilename, ImageInfo* pImageInfo, const bool bCreateIfNecessary, std::string& strFilenameInZip);
|
||||
void Close(ImageInfo* pImageInfo, const bool bDeleteFile);
|
||||
void Close(ImageInfo* pImageInfo);
|
||||
bool WOZUpdateInfo(ImageInfo* pImageInfo, DWORD& dwOffset);
|
||||
|
||||
virtual CImageBase* Detect(LPBYTE pImage, DWORD dwSize, const TCHAR* pszExt, DWORD& dwOffset, ImageInfo* pImageInfo) = 0;
|
||||
virtual CImageBase* GetImageForCreation(const TCHAR* pszExt, DWORD* pCreateImageSize) = 0;
|
||||
@ -317,7 +380,7 @@ protected:
|
||||
ImageError_e CheckNormalFile(LPCTSTR pszImageFilename, ImageInfo* pImageInfo, const bool bCreateIfNecessary);
|
||||
void GetCharLowerExt(TCHAR* pszExt, LPCTSTR pszImageFilename, const UINT uExtSize);
|
||||
void GetCharLowerExt2(TCHAR* pszExt, LPCTSTR pszImageFilename, const UINT uExtSize);
|
||||
void SetImageInfo(ImageInfo* pImageInfo, FileType_e eFileGZip, DWORD dwOffset, CImageBase* pImageType, DWORD dwSize);
|
||||
void SetImageInfo(ImageInfo* pImageInfo, FileType_e fileType, DWORD dwOffset, CImageBase* pImageType, DWORD dwSize);
|
||||
|
||||
UINT GetNumImages(void) { return m_vecImageTypes.size(); };
|
||||
CImageBase* GetImage(UINT uIndex) { _ASSERT(uIndex<GetNumImages()); return m_vecImageTypes[uIndex]; }
|
||||
|
@ -10,6 +10,8 @@
|
||||
#define LOG_DISK_NIBBLES_WRITE 1
|
||||
#define LOG_DISK_NIBBLES_WRITE_TRACK_GAPS 1 // Gap1, Gap2 & Gap3 info when writing a track
|
||||
#define LOG_DISK_NIBBLES_USE_RUNTIME_VAR 1
|
||||
#define LOG_DISK_WOZ_LOADWRITE 1
|
||||
#define LOG_DISK_WOZ_SHIFTWRITE 1
|
||||
|
||||
// __VA_ARGS__ not supported on MSVC++ .NET 7.x
|
||||
#if (LOG_DISK_ENABLED)
|
||||
|
Loading…
Reference in New Issue
Block a user