Read and write a bit faster and more reliable

This commit is contained in:
tudnai 2021-05-16 18:55:25 -07:00
parent 97e5711887
commit def9aacb61
2 changed files with 185 additions and 165 deletions

View File

@ -34,9 +34,9 @@ WOZread_t WOZread = {0};
WOZread_t WOZwrite = {0};
int trackWRoffset = 0;
int trackOffset = 0;
int bitOffset = 0;
unsigned trackNextOffset = 0;
unsigned trackOffset = 0;
unsigned bitOffset = 0;
uint64_t clkelpased;
@ -75,6 +75,76 @@ readState_t readState = readNormal;
uint8_t readLatch;
/*
CRC generator. Essentially that of Gary S. Brown from 1986, but I've
fixed the initial value. This is exactly the code advocated by the
WOZ file specifications (with some extra consts).
*/
static const uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/*!
Computes the CRC32 of an input buffer.
@param buf A pointer to the data to compute a CRC32 from.
@param size The size of the data to compute a CRC32 from.
@return The computed CRC32.
*/
static uint32_t crc32(const uint8_t *buf, size_t size) {
uint32_t crc = ~0;
size_t byte = 0;
while (size--) {
crc = crc32_tab[(crc ^ buf[byte]) & 0xFF] ^ (crc >> 8);
++byte;
}
return ~crc;
}
void woz_loadTrack_old( int track ) {
trackEntry_t reg = {0};
@ -232,121 +302,66 @@ void woz_loadTrack( int track ) {
}
// number needs to be unsigned to work with these macros
INLINE unsigned woz_incTrackOffset( unsigned ofs, unsigned limit) {
return (ofs + 1) % limit;
}
INLINE uint8_t woz_readByte(unsigned trk, unsigned ofs) {
return (*woz_trks)[trk].data[ofs];
}
uint8_t woz_read() {
if ( woz_tmap && woz_trks ) {
int track = woz_tmap->phase[disk.phase.count];
if (outdev) fprintf(outdev, "track: %d (%d) ", track, disk.phase.count);
if (outdev) fprintf(outdev, "track: %d (%d)\n", track, disk.phase.count);
if ( track >= 40 ) {
dbgPrintf("TRCK TOO HIGH!\n");
return rand();
}
static int clkBeforeSync = 0;
clkelpased = m6502.clktime + clkfrm - m6502.clklast;
m6502.clklast = m6502.clktime + clkfrm;
clkBeforeSync += clkelpased;
const int clkBeforeAdjusting = 512;
const int magicShiftOffset = 45;
static uint8_t latch = 0;
uint64_t clktime = m6502.clktime + m6502.clkfrm;
clkelpased = clktime - m6502.clklast;
m6502.clklast = clktime;
uint16_t usedBytes = (*woz_trks)[track].bytes_used < WOZ1_TRACK_BYTE_COUNT ? (*woz_trks)[track].bytes_used : WOZ1_TRACK_BYTE_COUNT;
if ( usedBytes ) {
int shiftOffset = magicShiftOffset;
uint64_t bitForward = (clkelpased >> 2) + 1;
// printf("elpased : %llu (clkBefRd:%d)\n", clkelpased, clkBeforeSync);
if ( clkelpased > clkBeforeAdjusting ) {
// printf("NEED SYNC : %llu (clkBefRd:%d)\n", clkelpased, clkBeforeSync);
clkBeforeSync = 0;
bitOffset = (clkelpased >> 2) & 7;
trackOffset += clkelpased >> 5;
if ( trackOffset >= usedBytes ) {
// Simulate idle spinning until s close point to the actual turn position
while ( bitForward-- ) {
if ( ++bitOffset > 7 ) {
bitOffset = 0;
trackOffset = 0;
WOZread.shift = 0;
shiftOffset = 0;
}
// trackOffset %= usedBytes;
// preroll data stream
WOZread.shift = 0;
WOZread.data = (*woz_trks)[track].data[trackOffset++];
trackOffset %= usedBytes;
trackWRoffset = trackOffset;
WOZread.shift <<= bitOffset;
WOZwrite = WOZread;
for ( int i = 0; i < shiftOffset; i++ ) {
for ( ; bitOffset < 8; bitOffset++ ) {
WOZread.shift <<= 1;
WOZwrite.shift <<= 1;
if ( WOZread.valid ) {
WOZread.latch = 0;
}
}
trackWRoffset = trackOffset;
WOZwrite.data = WOZread.data = (*woz_trks)[track].data[trackOffset++];
trackOffset %= usedBytes;
bitOffset = 0;
}
}
else {
uint64_t bitForward = (clkelpased >> 2);
// to avoid infinite loop and to search for bit 7 high
for ( uint64_t i = 0; i < bitForward; i++ ) {
if ( ++bitOffset >= 8 ) {
bitOffset = 0;
trackWRoffset = trackOffset;
trackOffset++;
trackOffset %= usedBytes;
WOZwrite.data = WOZread.data = (*woz_trks)[track].data[trackOffset];
}
WOZread.shift <<= 1;
WOZwrite.shift <<= 1;
if ( WOZread.valid ) {
WOZread.latch = 0;
}
}
}
// to avoid infinite loop and to search for bit 7 high
for ( int i = 0; i < usedBytes * 8; i++ ) {
if ( WOZread.valid ) {
WOZread.latch = 0;
// if (outdev) fprintf(outdev, "byte: %02X\n", byte);
if ( woz_decodeTrkSec(WOZwrite.latch, clkelpased, trackOffset * 8 + bitOffset) == wozTrackState_END ) {
if (outdev) fprintf(outdev, "vol:%d trk:%d sec:%d\n", vol, trk, sec);
}
trackOffset = woz_incTrackOffset(trackOffset, usedBytes);
if (outdev) fprintf(outdev, "elpased:%lld read: %02X\n", clkelpased, WOZwrite.latch);
return WOZwrite.latch;
}
if ( ++bitOffset >= 8 ) {
bitOffset = 0;
trackWRoffset = trackOffset;
trackOffset++;
trackOffset %= usedBytes;
WOZwrite.data = WOZread.data = (*woz_trks)[track].data[trackOffset];
WOZwrite.data =
WOZread.data = woz_readByte(track, trackOffset);
//if (outdev) fprintf(outdev, "(%02X.%u:%u): d:%02X\n", track, trackOffset, bitOffset, WOZread.data);
}
WOZread.shift <<= 1;
WOZwrite.shift <<= 1;
if ( WOZread.valid ) {
latch = WOZread.latch;
//if (outdev) fprintf(outdev, "(%02X.%u:%u): r:%02X\n", track, trackOffset, bitOffset, WOZread.latch);
// latch is cleared when bit 7 is high
// WOZwrite.latch =
WOZread.latch = 0;
// but we do not want to miss that latch valid nibble...
// in other words synchronization is needed because of imperfect cycle calculation
if ( bitForward < 8 ) {
return latch;
}
}
}
// if (outdev) fprintf(outdev, "TIME OUT!\n");
// return nibble
return WOZread.latch;
}
}
@ -378,11 +393,11 @@ void printWozBuffer (const char * s, int n, WOZread_t WOZbuf ) {
}
}
void woz_write( uint8_t data ) {
if ( woz_tmap && woz_trks ) {
int track = woz_tmap->phase[disk.phase.count];
if (outdev) fprintf(outdev, "track: %d (%d) ", track, disk.phase.count);
//if (outdev) fprintf(outdev, "track: %d (%d)\n", track, disk.phase.count);
if ( track >= 40 ) {
dbgPrintf("TRACK TOO HIGH!\n");
return;
@ -390,97 +405,80 @@ void woz_write( uint8_t data ) {
woz_flags.disk_modified = 1;
clkelpased = m6502.clktime + clkfrm - m6502.clklast;
m6502.clklast = m6502.clktime + clkfrm;
uint64_t clktime = m6502.clktime + m6502.clkfrm;
clkelpased = clktime - m6502.clklast;
m6502.clklast = clktime;
uint16_t usedBytes = (*woz_trks)[track].bytes_used < WOZ1_TRACK_BYTE_COUNT ? (*woz_trks)[track].bytes_used : WOZ1_TRACK_BYTE_COUNT;
if ( usedBytes ) {
uint64_t bitForward = (clkelpased >> 2) + 1;
// uint64_t bitOffsShouldBe = (bitOffset + bitForward) % 8;
// uint64_t trkOffsShouldBe = (trackOffset + bitForward / 8) % usedBytes;
//if (outdev) fprintf(outdev, "[%02X.%llu:%llu]: *:%02X\n", track, trkOffsShouldBe, bitOffsShouldBe, data);
// for DEBUG ONLY!!!
if (outdev) fprintf(outdev, "elpased:%llu data:$%02X\n", clkelpased, data);
//if (outdev) fprintf(outdev, "elpased:%llu data:$%02X\n", clkelpased, data);
printWozBuffer("*start", 0, WOZwrite);
if ( clkelpased > 32 ) {
// if (outdev) fprintf(outdev, "I/O ERROR : %llu\n", clkelpased);
uint64_t bitForward = (clkelpased - 32) >> 2;
// simulate disk spin over time
//printf("(");
// Simulate idle spinning until s close point to the actual turn position
while ( bitForward-- ) {
if ( ++bitOffset >= 8 ) {
if ( ++bitOffset > 7 ) {
bitOffset = 0;
trackWRoffset = trackOffset;
trackOffset++;
trackOffset %= usedBytes;
trackOffset = woz_incTrackOffset(trackOffset, usedBytes);
// WOZwrite.data =
WOZread.data = (*woz_trks)[track].data[trackOffset];
WOZwrite.data =
WOZread.data = woz_readByte(track, trackOffset);
//if (outdev) fprintf(outdev, "[%02X.%u:%u]: d:%02X (%016llX)\n", track, trackOffset, bitOffset, WOZwrite.data, WOZwrite.shift);
trackNextOffset = woz_incTrackOffset(trackOffset, usedBytes);
// load original following data
WOZwrite.next = woz_readByte(track, trackNextOffset);
//if (outdev) fprintf(outdev, "[%02X.%u:%u]: n:%02X (%016llX)\n", track, trackNextOffset, bitOffset, WOZwrite.next, WOZwrite.shift);
}
WOZread.shift <<= 1;
WOZwrite.shift <<= 1;
if ( WOZread.valid ) {
//if (outdev) fprintf(outdev, "[%02X.%u:%u]: r:%02X (%016llX) {%llu}\n", track, trackOffset, bitOffset, WOZwrite.latch, WOZwrite.shift, bitForward);
//printf("%2X ", WOZread.latch);
// we do not clear write latch as we need that
// for writing data in byte alignment
WOZread.latch = 0;
// synchronize
if ( bitForward < 8 ) {
break;
}
}
}
// ok now we can latch data
WOZwrite.data = WOZread.data = data;
printWozBuffer("datain", 0, WOZwrite);
int i = 8; // 8 bit to shift in
// shift in 8 bits of data and write it out
while ( i-- ) {
if ( ++bitOffset >= 8 ) {
// write out first part
(*woz_trks)[track].data[trackWRoffset] = WOZwrite.latch;
bitOffset = 0;
trackWRoffset = trackOffset;
trackOffset++;
trackOffset %= usedBytes;
// feed write buffer
WOZwrite.latch = data;
//if (outdev) fprintf(outdev, "[%02X.%u:%u]: D:%02X (%016llX)\n", track, trackNextOffset, bitOffset, WOZwrite.latch, WOZwrite.shift);
// simulate shift in data (path of write latch is already loaded, we should not overwrite it!)
uint8_t new = (*woz_trks)[track].data[trackOffset];
new >>= i + 1;
WOZread.data |= new;
// WOZwrite.data |= new;
printWozBuffer("shl1in", i, WOZwrite);
WOZread.shift <<= 1;
WOZwrite.shift <<= 1;
break;
}
WOZread.shift <<= 1;
WOZwrite.shift <<= 1;
printWozBuffer("shift1", i, WOZwrite);
};
printWozBuffer("shift1", 9, WOZwrite);
// write the remaining bits without altering WOZ track offsets and indexes
// WOZread_t WOZtmp = WOZwrite;
// int bo = bitOffset;
// shift to byte alignment so we can write to the byte stream
WOZwrite.shift >>= bitOffset + 1;
// second half
while ( i-- ) {
if ( ++bitOffset >= 8 ) {
// write out first part
(*woz_trks)[track].data[trackWRoffset] = WOZwrite.latch;
break;
}
WOZwrite.shift <<= 1;
printWozBuffer("shift2", i, WOZwrite);
};
printWozBuffer("shift2", 9, WOZwrite);
// write out upper part
//if (outdev) fprintf(outdev, "[%02X.%u:%u]: R:%02X -> %02X (%016llX)\n", track, trackOffset, 0, (*woz_trks)[track].data[trackOffset], WOZwrite.latch, WOZwrite.shift);
(*woz_trks)[track].data[trackOffset] = WOZwrite.latch;
// write out lower part
//if (outdev) fprintf(outdev, "[%02X.%u:%u]: R:%02X -> %02X (%016llX)\n", track, trackNextOffset, 0, (*woz_trks)[track].data[trackNextOffset], WOZwrite.data, WOZwrite.shift);
trackNextOffset = woz_incTrackOffset(trackOffset, usedBytes);
(*woz_trks)[track].data[trackNextOffset] = WOZwrite.data;
// shift back to actual bit alignment
WOZwrite.shift <<= bitOffset + 1;
}
}
}
@ -522,6 +520,9 @@ int woz_parseBuffer() {
return WOZ_ERR_NOT_WOZ_FILE;
}
// woz_header->crc
// check if bits and line ends not been altered by data transmission protocols
if ( woz_header->bit_correctness != 0x0A0D0AFF ) {
woz_free_buffer();
@ -529,6 +530,15 @@ int woz_parseBuffer() {
}
bufOffs += sizeof(woz_header_t);
uint32_t crc = crc32( &woz_file_buffer[bufOffs], woz_file_size - bufOffs);
if ( crc != woz_header->crc ) {
printf("WOZ Invalid CRC (%u vs %u)\n", woz_header->crc, crc);
}
else {
printf("WOZ valid CRC (%u vs %u)\n", woz_header->crc, crc);
}
while ( bufOffs < woz_file_size ) {
// beginning of the chunk, so we can skip it later
@ -632,6 +642,8 @@ int woz_saveFile( const char * filename ) {
filename = woz_filename;
}
woz_header->crc = crc32( woz_file_buffer + sizeof(woz_header_t), woz_file_size - sizeof(woz_header_t));
FILE * f = fopen( filename, "wb" );
if (f == NULL) {
perror("Failed to crete WOZ: ");

View File

@ -157,15 +157,23 @@ typedef woz1_track_t woz1_trks_t[DISKII_MAXTRACKS];
typedef union {
struct {
// for buffering for shifting during write process
// also for debug and diag purposes
uint8_t next_next;
uint8_t next;
uint8_t data;
uint8_t latch;
// for debug and diag purposes
uint8_t out[6];
// for buffering for shifting during write process
// also for debug and diag purposes
uint8_t out[4];
};
struct {
uint16_t next16; // unused
uint16_t lower15 : 15;
uint16_t valid : 1;
uint32_t out32; // unused
};
uint64_t shift;
} WOZread_t;