diff --git a/Inc/control.h b/Inc/control.h index 1381931..1bf9e1f 100644 --- a/Inc/control.h +++ b/Inc/control.h @@ -23,6 +23,7 @@ typedef struct { uint32_t counter; uint32_t lba; uint8_t* buffer; + uint8_t* directory; unsigned int size; } Storage; diff --git a/Src/control.c b/Src/control.c index ef06c70..86d0f38 100644 --- a/Src/control.c +++ b/Src/control.c @@ -21,8 +21,8 @@ extern uint8_t ack[1]; extern uint8_t nack[1]; #define CPM_RECORD_SIZE 128 -#define CPM_RECODS_PER_BLOCK 128 -#define CPM_BLOCK_SIZE CPM_RECORD_SIZE*CPM_RECODS_PER_BLOCK +#define CPM_RECORDS_PER_BLOCK 128 +#define CPM_BLOCK_SIZE CPM_RECORD_SIZE*CPM_RECORDS_PER_BLOCK uint8_t get_device(uint16_t address) { uint8_t page = address >> 12; @@ -114,11 +114,15 @@ void handle_io_read() { // Read byte from disk case 0x08: if (control.storage.ready && control.storage.command == 0x20) { - write_data(control.storage.buffer[control.storage.counter]); + if (control.storage.counter < control.storage.size) { + write_data(control.storage.buffer[control.storage.counter]); + } else { + write_data(0x00); + } + control.storage.counter++; - if (control.storage.counter >= control.storage.size) { - control.storage.command = 0; + if (control.storage.counter >= CPM_RECORD_SIZE) { control.storage.ready = 0; } } else { @@ -128,31 +132,6 @@ void handle_io_read() { // Check if disk is ready case 0x0f: - if (control.storage.command == 0x30 && !control.storage.ready) { - printf("Write: 0x%lx\n\r", control.storage.lba * CPM_RECORD_SIZE); - for (int i = 0; i < 128; ++i) { - control.storage.buffer[i] = 0x00; - } - control.storage.ready = 1; - } - - if (control.storage.command == 0x20 && !control.storage.ready) { - printf("Read: 0x%lx\n\r", control.storage.lba * CPM_RECORD_SIZE); - FRESULT fr = f_lseek(control.storage.file, control.storage.lba * CPM_RECORD_SIZE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_read(control.storage.file, control.storage.buffer, CPM_RECORD_SIZE, &control.storage.size); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - control.storage.ready = 1; - } - write_data(0x08*control.storage.ready); break; @@ -187,145 +166,7 @@ void handle_io_write() { // Write byte to disk case 0x08: - if (control.storage.ready && control.storage.command == 0x30) { - control.storage.buffer[control.storage.counter] = value; - control.storage.counter++; - - // Commit changes - if (control.storage.counter == CPM_RECORD_SIZE) { - FRESULT fr = f_lseek(control.storage.file, control.storage.lba * CPM_RECORD_SIZE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - unsigned int bytes_written; - fr = f_write(control.storage.file, control.storage.buffer, CPM_RECORD_SIZE, &bytes_written); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - if (control.storage.lba >= 0x100 && control.storage.lba < 0x180) { - for (int i = 0; i < 4; ++i) { - DiskEntry entry; - - entry.user = control.storage.buffer[32*i + 0]; - printf("User: %i\n\r", entry.user); - - for (int j = 0; j < 8; ++j) { - char c = control.storage.buffer[32*i + 1 + j]; - if (c == ' ') { - c = 0x00; - } - entry.name[j] = c; - } - printf("Name: %.8s\n\r", entry.name); - - for (int j = 0; j < 3; ++j) { - char c = control.storage.buffer[32*i + 9 + j]; - if (c == ' ') { - c = 0x00; - } - entry.ext[j] = c; - } - printf("Ext: %.3s\n\r", entry.ext); - - entry.size = control.storage.buffer[32*i + 15]; - - for (int j = 0; j < 8; ++j) { - uint16_t allocation = control.storage.buffer[32*i + 2*j + 16]; - allocation += control.storage.buffer[32*i + 2*j + 17] << 8; - entry.allocation[j] = allocation; - printf("Allocation: %i\n\r", allocation); - if (j && allocation) { - entry.size += 0x80; - } - } - printf("Size: %li records (%li)\n\r", entry.size, entry.size * CPM_RECORD_SIZE); - - char filename[128]; - snprintf(filename, 128, "0:A/%.8s.%.3s", entry.name, entry.ext); - FIL file; - if (entry.user == 0xe5) { - FILINFO nfo; - fr = f_stat(filename, &nfo); - if (fr == FR_OK) { - printf("Removing file %s\n\r", filename); - fr = f_unlink(filename); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - } - } else { - printf("Opening %s\n\r", filename); - fr = f_open(&file, filename, FA_WRITE | FA_CREATE_ALWAYS); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - for (int j = 0; j < 8; ++j) { - if (entry.allocation[j] == 0) { - continue; - } - - uint8_t buffer[CPM_BLOCK_SIZE] = {0}; - - printf("Copying allocation %i (%i) to %s\n\r", j, entry.allocation[j], filename); - - fr = f_lseek(control.storage.file, 0x8000 + entry.allocation[j]*CPM_BLOCK_SIZE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - unsigned int bytes_read; - fr = f_read(control.storage.file, buffer, entry.size * CPM_RECORD_SIZE, &bytes_read); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - printf("Bytes read: %i\n\r", bytes_read); - - fr = f_lseek(&file, j*CPM_BLOCK_SIZE); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - unsigned int bytes_written; - fr = f_write(&file, buffer, bytes_read, &bytes_written); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - printf("Bytes written: %i\n\r", bytes_written); - - f_sync(control.storage.file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - } - - fr = f_close(&file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - } - } - // @todo Verify that this is how it works - // If there was a write here a file got modified - printf("File(s) in record %li (0x%lx) changed\n\r", control.storage.lba, control.storage.lba * CPM_RECORD_SIZE); - } - - control.storage.command = 0; - control.storage.ready = 0; - } - } + // @todo Implement this from scratch break; case 0x0b: { @@ -348,9 +189,93 @@ void handle_io_write() { // Receive disk command case 0x0f: { - control.storage.ready = 0; - control.storage.counter = 0; control.storage.command = value; + control.storage.counter = 0; + control.storage.size = 0; + + if (control.storage.command == 0x20) { + char filename[128] = {0}; + uint32_t offset = 0; + if (control.storage.lba == 0) { + snprintf(filename, 128, "0:loader.bin"); + offset = control.storage.lba - 0; + } else if (control.storage.lba >= 1 && control.storage.lba < 45) { + snprintf(filename, 128, "0:cpm22.bin"); + offset = control.storage.lba - 1; + } else if (control.storage.lba >= 45 && control.storage.lba < 51) { + snprintf(filename, 128, "0:bios.bin"); + offset = control.storage.lba - 45; + } else if (control.storage.lba >= 256 && control.storage.lba < 384) { + offset = control.storage.lba - 256; + control.storage.size = 128; + for (int i = 0; i < CPM_RECORD_SIZE; ++i) { + control.storage.buffer[i] = control.storage.directory[offset*CPM_RECORD_SIZE + i]; + } + } else if (control.storage.lba >= 384) { + uint32_t block = (control.storage.lba - 256) / CPM_RECORDS_PER_BLOCK; + + for (int entry = 0; entry < 127; ++entry) { + for (int i = 0; i < 8; ++i) { + uint16_t allocation = control.storage.directory[entry*32 + 16 + 2*i]; + allocation += control.storage.directory[entry*32 + 17 + 2*i] << 8; + + if (allocation == block) { + offset = (control.storage.lba - 256 - block*CPM_RECORDS_PER_BLOCK) + i*CPM_RECORDS_PER_BLOCK; + + char name[8]; + for (int j = 0; j < 8; ++j) { + char c = control.storage.directory[entry*32 + 1 + j]; + if (c == ' ') { + c = 0x00; + } + name[j] = c; + } + + char ext[3]; + for (int j = 0; j < 3; ++j) { + char c = control.storage.directory[entry*32 + 9 + j]; + if (c == ' ') { + c = 0x00; + } + ext[j] = c; + } + + snprintf(filename, 128, "0:A/%.8s.%.3s", name, ext); + } + } + } + } + + if (filename[0]) { + FIL file; + // @0todo Cache the currently opened file so we are not opening it every 128 bytes + FRESULT fr = f_open(&file, filename, FA_READ); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_lseek(&file, offset * 0x80); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_read(&file, control.storage.buffer, CPM_RECORD_SIZE, &control.storage.size); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + + fr = f_close(&file); + if (fr) { + printf("File error: %i\n\r", fr); + return; + } + } + + control.storage.ready = 1; + } break; } @@ -394,68 +319,15 @@ void control_cycle() { set_clock(0); } -void copy_file_to_image(char* filename, FIL* disk, uint32_t source, uint32_t destination, uint32_t size) { - FIL file; - FRESULT fr = f_open(&file, filename, FA_READ); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_lseek(&file, source); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - uint8_t* buffer = malloc(size); - unsigned int bytes_read; - fr = f_read(&file, buffer, size, &bytes_read); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_lseek(disk, destination); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - printf("copying: %s %lx @ %lx (%i)\n\r", filename, source, destination, bytes_read); - - unsigned int bytes_written; - fr = f_write(disk, buffer, bytes_read, &bytes_written); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - fr = f_close(&file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - free(buffer); -} - -DiskEntry* get_disk_entries(char* diskpath) { +void get_disk_entries(char* diskpath) { printf("Scanning: %s\n\r", diskpath); - DiskEntry* entries = malloc(127*sizeof(DiskEntry)); // Clear all entries - for (int i = 0; i < 127; ++i) { - entries[i].user = 0xe5; - for (int j = 0; j < 8; ++j) { - entries[i].name[j] = 0x00; - } - for (int j = 0; j < 3; ++j) { - entries[i].ext[j] = 0x00; - } - entries[i].size = 0; - for (int j = 0; j < 8; ++j) { - entries[i].allocation[j] = 0x00; + for (int i = 0; i < 0x4000; ++i) { + if (i % 32 == 0) { + control.storage.directory[i] = 0xe5; + } else { + control.storage.directory[i] = 0x00; } } @@ -472,26 +344,32 @@ DiskEntry* get_disk_entries(char* diskpath) { } if (!(fno.fattrib & AM_DIR)) { - entries[index].user = 0x00; + printf("File: %s\n\r", fno.fname); + control.storage.directory[index*32 + 0] = 0x00; // Calculate the number of records uint32_t size = (fno.fsize + CPM_RECORD_SIZE - 1) / CPM_RECORD_SIZE; - entries[index].allocation[0] = end; + control.storage.directory[index*32 + 16] = end & 0xFF; + control.storage.directory[index*32 + 17] = (end >> 8) & 0xFF; end++; int i = 1; while (size >= 0x80) { size -= 0x80; - entries[index].allocation[i] = end; + control.storage.directory[index*32 + 16 + i*2] = end & 0xFF; + control.storage.directory[index*32 + 17 + i*2] = (end >> 8) & 0xFF; end++; i++; } + control.storage.directory[index*32 + 12] = (i-1) & 0xFF; + control.storage.directory[index*32 + 13] = 0x00; + control.storage.directory[index*32 + 14] = ((i-1) >> 8) & 0xFF; + // Store the size in the number of records - entries[index].size = size; + control.storage.directory[index*32 + 15] = size; /* free(entries[index].filename); */ - entries[index].filename = strdup(fno.fname); uint8_t name_len = 9; for (uint8_t i = 0; i < 8; ++i) { @@ -503,7 +381,7 @@ DiskEntry* get_disk_entries(char* diskpath) { name_len = i+1; } - entries[index].name[i] = c; + control.storage.directory[index*32 + 1+i] = c; } uint8_t done = 0; @@ -516,7 +394,7 @@ DiskEntry* get_disk_entries(char* diskpath) { done = 1; } - entries[index].ext[i] = c; + control.storage.directory[index*32 + 9+i] = c; } index++; @@ -524,22 +402,21 @@ DiskEntry* get_disk_entries(char* diskpath) { } } else { printf("File error: %i\n\r", fr); - return entries; + return; } fr = f_closedir(&dir); if (fr) { printf("File error: %i\n\r", fr); - return entries; + return; } - - return entries; } // @todo Properly reset everything void control_reset() { free(control.storage.buffer); + free(control.storage.directory); f_close(control.storage.file); free(control.storage.file); @@ -547,99 +424,23 @@ void control_reset() { f_mount(0, "0:", 0); free(control.storage.fs); - Control temp = {0, {NULL, NULL, 0, 0, 0, 0, NULL, 0}}; + Control temp = {0, {NULL, NULL, 0, 0, 0, 0, NULL, NULL, 0}}; control = temp; control.storage.buffer = (uint8_t*)malloc(CPM_RECORD_SIZE); + control.storage.directory = (uint8_t*)malloc(0x4000); control.storage.fs = (FATFS*)malloc(sizeof(FATFS)); control.storage.file = (FIL*)malloc(sizeof(FIL)); + printf("Status: %i\n\r", disk_status(0)); + FRESULT fr = f_mount(control.storage.fs, "0:", 0); if (fr) { printf("File error: %i\n\r", fr); } - // Open the image file - fr = f_open(control.storage.file, "0:A.img", FA_READ | FA_WRITE | FA_CREATE_ALWAYS); - if (fr) { - printf("File error: %i\n\r", fr); - } - - fr = f_chmod("0:A.img", AM_HID, 0xFF); - if (fr) { - printf("File error: %i\n\r", fr); - } - - copy_file_to_image("0:loader.bin", control.storage.file, 0x00, 0x00, 0x80); - copy_file_to_image("0:cpm22.bin", control.storage.file, 0x00, 0x80, 0x1600); - copy_file_to_image("0:bios.bin", control.storage.file, 0x00, 0x1680, 0x600); - - f_lseek(control.storage.file, 0x8000); - - DiskEntry* entries = get_disk_entries("0:A"); - for (int i = 0; i < 127; ++i) { - char buffer[32]; - - buffer[0] = entries[i].user; - for (int j = 0; j < 8; ++j) { - buffer[1+j] = entries[i].name[j]; - } - - for (int j = 0; j < 3; ++j) { - buffer[9+j] = entries[i].ext[j]; - } - - uint16_t extents = 0x00; - for (int j = 1; j < 8; ++j) { - if (entries[i].allocation[j]) { - extents++; - } - } - - buffer[12] = extents & 0xFF; - buffer[13] = 0x00; - buffer[14] = (extents >> 8) & 0xFF; - buffer[15] = entries[i].size; - - for (int j = 0; j < 8; ++j) { - uint16_t allocation = entries[i].allocation[j]; - buffer[16 + j*2] = allocation & 0xFF; - buffer[17 + j*2] = (allocation >> 8) & 0xFF; - } - - unsigned int bytes_written; - fr = f_write(control.storage.file, buffer, 32, &bytes_written); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - } - - for (int i = 0; i < 127; ++i) { - if (entries[i].user == 0xe5) { - continue; - } - - char buf[128]; - snprintf(buf, 128, "0:A/%s", entries[i].filename); - for (int j = 0; j < 8; ++j) { - uint16_t allocation = entries[i].allocation[j]; - if (allocation) { - printf("allocation: %s (%i)\n\r", buf, allocation); - copy_file_to_image(buf, control.storage.file, j*CPM_BLOCK_SIZE, 0x8000+allocation*CPM_BLOCK_SIZE, CPM_BLOCK_SIZE); - } - } - } - - f_sync(control.storage.file); - if (fr) { - printf("File error: %i\n\r", fr); - return; - } - - // @todo Pretty sure we have to free things within DiskEntry - free(entries); + get_disk_entries("0:A"); set_reset(1); for (int i = 0; i <= 10; ++i) {