#include #include #include #include #include "../../file_io.h" #include "../../user_io.h" #include "../../hardware.h" #include "dsk2nib_lib.h" // Constants from original dsk2nib.c #define TRACKS_PER_DISK 35 #define SECTORS_PER_TRACK 16 #define BYTES_PER_SECTOR 256 #define BYTES_PER_TRACK 4096 #define PRIMARY_BUF_LEN 256 #define SECONDARY_BUF_LEN 86 #define DATA_LEN (PRIMARY_BUF_LEN+SECONDARY_BUF_LEN) #define PROLOG_LEN 3 #define EPILOG_LEN 3 #define GAP1_LEN 48 #define GAP2_LEN 5 #define BYTES_PER_NIB_SECTOR 416 #define BYTES_PER_NIB_TRACK 6656 #define DEFAULT_VOLUME 254 #define GAP_BYTE 0xff // Structures from original typedef struct { uchar prolog[ PROLOG_LEN ]; uchar volume[ 2 ]; uchar track[ 2 ]; uchar sector[ 2 ]; uchar checksum[ 2 ]; uchar epilog[ EPILOG_LEN ]; } addr_t; typedef struct { uchar prolog[ PROLOG_LEN ]; uchar data[ DATA_LEN ]; uchar data_checksum; uchar epilog[ EPILOG_LEN ]; } data_t; typedef struct { uchar gap1[ GAP1_LEN ]; addr_t addr; uchar gap2[ GAP2_LEN ]; data_t data; } nib_sector_t; // Static data from original static uchar addr_prolog[] = { 0xd5, 0xaa, 0x96 }; static uchar addr_epilog[] = { 0xde, 0xaa, 0xeb }; static uchar data_prolog[] = { 0xd5, 0xaa, 0xad }; static uchar data_epilog[] = { 0xde, 0xaa, 0xeb }; static int soft_interleave[ SECTORS_PER_TRACK ] = { 0, 7, 0xE, 6, 0xD, 5, 0xC, 4, 0xB, 3, 0xA, 2, 9, 1, 8, 0xF }; static int phys_interleave[ SECTORS_PER_TRACK ] = { 0, 0xD, 0xB, 9, 7, 5, 3, 1, 0xE, 0xC, 0xA, 8, 6, 4, 2, 0xF }; // Translation table for 6+2 encoding static uchar table[ 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, 0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3, 0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; // Helper functions from original static uchar translate(uchar byte) { return table[byte & 0x3f]; } static void odd_even_encode(uchar a[], int i) { a[0] = (i >> 1) & 0x55; a[0] |= 0xaa; a[1] = i & 0x55; a[1] |= 0xaa; } static void nibbilize(uchar *src, data_t *data_field) { int i, index, section; uchar pair; uchar primary_buf[PRIMARY_BUF_LEN]; uchar secondary_buf[SECONDARY_BUF_LEN]; uchar *dest = data_field->data; // Clear buffers memset(primary_buf, 0, PRIMARY_BUF_LEN); memset(secondary_buf, 0, SECONDARY_BUF_LEN); // Nibbilize data into primary and secondary buffers for (i = 0; i < PRIMARY_BUF_LEN; i++) { primary_buf[i] = src[i] >> 2; index = i % SECONDARY_BUF_LEN; section = i / SECONDARY_BUF_LEN; pair = ((src[i]&2)>>1) | ((src[i]&1)<<1); // swap the low bits secondary_buf[index] |= pair << (section*2); } // XOR pairs of nibbilized bytes in correct order index = 0; dest[index++] = translate(secondary_buf[0]); for (i = 1; i < SECONDARY_BUF_LEN; i++) dest[index++] = translate(secondary_buf[i] ^ secondary_buf[i-1]); dest[index++] = translate(primary_buf[0] ^ secondary_buf[SECONDARY_BUF_LEN-1]); for (i = 1; i < PRIMARY_BUF_LEN; i++) dest[index++] = translate(primary_buf[i] ^ primary_buf[i-1]); data_field->data_checksum = translate(primary_buf[PRIMARY_BUF_LEN-1]); } // Convert NIB physical sector to logical sector using interleave tables static int phys_to_logical_sector(int phys_sector) { // Find which logical sector maps to this physical sector for (int i = 0; i < SECTORS_PER_TRACK; i++) { if (phys_interleave[i] == phys_sector) { return i; } } return 0; // fallback } void a2_readDsk2Nib(fileTYPE*fd, uint64_t offset, uchar *byte) { int nib_track = offset / BYTES_PER_NIB_TRACK; uint64_t track_offset = offset % BYTES_PER_NIB_TRACK; int volume = DEFAULT_VOLUME; // Bounds check if (nib_track >= TRACKS_PER_DISK) { memset(byte, 0, 512); return; } // Build entire NIB track in memory uchar nib_track_data[BYTES_PER_NIB_TRACK]; // Process all 16 sectors in this track for (int phys_sector = 0; phys_sector < SECTORS_PER_TRACK; phys_sector++) { // Convert physical sector to logical sector int logical_sector = phys_to_logical_sector(phys_sector); // Get corresponding DSK soft sector int dsk_soft_sector = soft_interleave[logical_sector]; // Read DSK sector data uchar dsk_sector[BYTES_PER_SECTOR]; off_t dsk_offset = (off_t)nib_track * BYTES_PER_TRACK + (off_t)dsk_soft_sector * BYTES_PER_SECTOR; if (FileSeek(fd, dsk_offset, SEEK_SET)) { if (FileReadAdv(fd, dsk_sector, BYTES_PER_SECTOR)) { // good } else { memset(dsk_sector, 0, BYTES_PER_SECTOR); } } else { memset(dsk_sector, 0, BYTES_PER_SECTOR); } //if (lseek(fd, dsk_offset, SEEK_SET) == -1) { //} else if (read(fd, dsk_sector, BYTES_PER_SECTOR) != BYTES_PER_SECTOR) { // memset(dsk_sector, 0, BYTES_PER_SECTOR); //} // Build NIB sector structure nib_sector_t nib_sector; // Initialize gaps memset(nib_sector.gap1, GAP_BYTE, GAP1_LEN); memset(nib_sector.gap2, GAP_BYTE, GAP2_LEN); // Set address field memcpy(nib_sector.addr.prolog, addr_prolog, 3); memcpy(nib_sector.addr.epilog, addr_epilog, 3); odd_even_encode(nib_sector.addr.volume, volume); odd_even_encode(nib_sector.addr.track, nib_track); odd_even_encode(nib_sector.addr.sector, logical_sector); int csum = volume ^ nib_track ^ logical_sector; odd_even_encode(nib_sector.addr.checksum, csum); // Set data field memcpy(nib_sector.data.prolog, data_prolog, 3); memcpy(nib_sector.data.epilog, data_epilog, 3); nibbilize(dsk_sector, &nib_sector.data); // Copy this sector to the track buffer memcpy(nib_track_data + phys_sector * BYTES_PER_NIB_SECTOR, &nib_sector, sizeof(nib_sector)); } // Copy requested 512 bytes from the track int bytes_to_copy = 512; int available_bytes = BYTES_PER_NIB_TRACK - track_offset; if (available_bytes <= 0) { memset(byte, 0, 512); return; } if (bytes_to_copy > available_bytes) { bytes_to_copy = available_bytes; } memcpy(byte, nib_track_data + track_offset, bytes_to_copy); // Fill remaining bytes with zeros if needed if (bytes_to_copy < 512) { memset(byte + bytes_to_copy, 0, 512 - bytes_to_copy); } } // Helper functions for NIB to DSK conversion static uchar odd_even_decode(uchar byte1, uchar byte2) { uchar byte; byte = (byte1 << 1) & 0xaa; byte |= byte2 & 0x55; return byte; } static uchar untranslate(uchar x) { uchar *ptr; int index; if ((ptr = (uchar*)memchr(table, x, 0x40)) == NULL) { return 0; // Invalid byte, return 0 instead of fatal error } index = ptr - table; return index; } // Parse a NIB sector from byte stream and extract DSK data static int parse_nib_sector(uchar *nib_data, int data_len, uchar *dsk_sector, int *track, int *sector) { int pos = 0; int state = 0; uchar primary_buf[PRIMARY_BUF_LEN]; uchar secondary_buf[SECONDARY_BUF_LEN]; uchar checksum; int i; // State machine to parse NIB sector while (pos < data_len) { uchar byte = nib_data[pos++]; switch (state) { case 0: // Looking for address prolog D5 if (byte == 0xd5) state = 1; break; case 1: // Looking for address prolog AA if (byte == 0xaa) state = 2; else state = 0; break; case 2: // Looking for address prolog 96 if (byte == 0x96) state = 3; else state = 0; break; case 3: // Read volume (first byte) if (pos >= data_len) return 0; odd_even_decode(byte, nib_data[pos++]); // Read volume but don't store state = 4; break; case 4: // Read track (first byte) if (pos >= data_len) return 0; *track = odd_even_decode(byte, nib_data[pos++]); state = 5; break; case 5: // Read sector (first byte) if (pos >= data_len) return 0; *sector = odd_even_decode(byte, nib_data[pos++]); state = 6; break; case 6: // Read checksum (first byte) if (pos >= data_len) return 0; pos++; // Skip checksum, we don't validate it state = 7; break; case 7: // Skip address epilog DE if (byte == 0xde) state = 8; break; case 8: // Skip address epilog AA if (byte == 0xaa) state = 9; else state = 7; break; case 9: // Skip address epilog EB, look for data prolog D5 if (byte == 0xd5) state = 10; break; case 10: // Looking for data prolog AA if (byte == 0xaa) state = 11; else state = 9; break; case 11: // Looking for data prolog AD if (byte == 0xad) state = 12; else state = 9; break; case 12: // Process data field // Read and decode the 342 data bytes plus checksum checksum = untranslate(byte); secondary_buf[0] = checksum; // Read secondary buffer (85 more bytes) for (i = 1; i < SECONDARY_BUF_LEN; i++) { if (pos >= data_len) return 0; checksum ^= untranslate(nib_data[pos++]); secondary_buf[i] = checksum; } // Read primary buffer (256 bytes) for (i = 0; i < PRIMARY_BUF_LEN; i++) { if (pos >= data_len) return 0; checksum ^= untranslate(nib_data[pos++]); primary_buf[i] = checksum; } // Read and validate checksum if (pos >= data_len) return 0; checksum ^= untranslate(nib_data[pos++]); // Ignore checksum validation for now // Denibbilize - reconstruct the 256-byte sector for (i = 0; i < PRIMARY_BUF_LEN; i++) { int index = i % SECONDARY_BUF_LEN; uchar bit0, bit1; switch (i / SECONDARY_BUF_LEN) { case 0: bit0 = (secondary_buf[index] & 2) > 0; bit1 = (secondary_buf[index] & 1) > 0; break; case 1: bit0 = (secondary_buf[index] & 8) > 0; bit1 = (secondary_buf[index] & 4) > 0; break; case 2: bit0 = (secondary_buf[index] & 0x20) > 0; bit1 = (secondary_buf[index] & 0x10) > 0; break; default: bit0 = bit1 = 0; break; } dsk_sector[i] = (primary_buf[i] << 2) | (bit1 << 1) | bit0; } return 1; // Success default: state = 0; break; } } return 0; // Failed to parse } void a2_writeDSK(fileTYPE* idx, uint64_t lba, int ack) { //printf("a2_writeDSK(lba:%lld ack:%d\n",lba,ack); // Fetch sector data from FPGA ... uchar chunk[512]; EnableIO(); spi_w(UIO_SECTOR_WR | ack); spi_block_read(chunk, user_io_get_width(), 512); DisableIO(); a2_writeNib2Dsk(idx, lba*512, chunk); } void a2_readDSK(fileTYPE* idx, uint64_t lba, int ack) { //printf("a2_readDSK(lba:%lld ack:%d\n",lba,ack); uchar chunk[512]; a2_readDsk2Nib(idx, lba*512, chunk); //printf("%x %x %x %x %x\n",chunk[0],chunk[1],chunk[2],chunk[3],chunk[4]); EnableIO(); spi_w(UIO_SECTOR_RD | ack); spi_block_write(chunk, user_io_get_width(), 512); DisableIO(); } void a2_writeNib2Dsk(fileTYPE*fd, uint64_t offset, uchar *byte) { int nib_track = offset / BYTES_PER_NIB_TRACK; uint64_t track_offset = offset % BYTES_PER_NIB_TRACK; // Bounds check if (nib_track >= TRACKS_PER_DISK) { return; } // We need to accumulate a full track's worth of NIB data to properly decode // This is a simplified approach - we'll try to parse sectors from the given 512 bytes static uchar track_buffer[BYTES_PER_NIB_TRACK]; static int current_track = -1; static int bytes_accumulated = 0; // If this is a new track, reset the buffer if (current_track != nib_track) { current_track = nib_track; bytes_accumulated = 0; memset(track_buffer, 0, BYTES_PER_NIB_TRACK); } // Copy the 512 bytes into our track buffer at the appropriate offset int copy_len = 512; if (track_offset + copy_len > BYTES_PER_NIB_TRACK) { copy_len = BYTES_PER_NIB_TRACK - track_offset; } if (copy_len > 0) { memcpy(track_buffer + track_offset, byte, copy_len); bytes_accumulated += copy_len; } // Try to parse and write any complete sectors we can find // Look for sectors in the accumulated data int pos = 0; while (pos < bytes_accumulated - 400) { // Need at least 400 bytes for a sector uchar dsk_sector[BYTES_PER_SECTOR]; int track_num, sector_num; if (parse_nib_sector(track_buffer + pos, bytes_accumulated - pos, dsk_sector, &track_num, §or_num)) { // Successfully parsed a sector if (track_num == nib_track && sector_num < SECTORS_PER_TRACK) { // Map logical sector to soft sector using interleave int soft_sector = soft_interleave[sector_num]; // Calculate DSK file offset off_t dsk_offset = (off_t)track_num * BYTES_PER_TRACK + (off_t)soft_sector * BYTES_PER_SECTOR; // Write sector to DSK file //if (lseek(fd, dsk_offset, SEEK_SET) != -1) { if (FileSeek(fd,dsk_offset, SEEK_SET)) // if (lseek(fd, dsk_offset, SEEK_SET) != -1) { FileWriteAdv(fd, dsk_sector,BYTES_PER_SECTOR); //write(fd, dsk_sector, BYTES_PER_SECTOR); //} } pos += BYTES_PER_NIB_SECTOR; // Move to next sector } else { pos++; // Try next byte position } } }