diff --git a/zx_disk.cpp b/zx_disk.cpp index 4a2ac93..fe589c6 100644 --- a/zx_disk.cpp +++ b/zx_disk.cpp @@ -7,9 +7,15 @@ #define ZX_FDC_MODE_EXECUTION 2 #define ZX_FDC_MODE_RESULT 3 -#define ZX_FDC_COMMAND_MASK 0x1F -#define ZX_FDC_COMMAND_SPECIFY 0x03 -#define ZX_FDC_COMMAND_SENSE_DRIVE_STATUS 0x04 +#define ZX_FDC_DATA_DIRECTION_INPUT 0x00 +#define ZX_FDC_DATA_DIRECTION_OUTPUT 0x40 + +#define ZX_FDC_COMMAND_MASK 0x1F +#define ZX_FDC_COMMAND_SPECIFY 0x03 +#define ZX_FDC_COMMAND_SENSE_DRIVE_STATUS 0x04 +#define ZX_FDC_COMMAND_RECALIBRATE 0x07 +#define ZX_FDC_COMMAND_SENSE_INTERRUPT_STATUS 0x08 +#define ZX_FDC_COMMAND_SEEK 0x0F #define ZX_FDC_MAIN_DRIVE0_BUSY 1 #define ZX_FDC_MAIN_DRIVE1_BUSY 2 @@ -25,17 +31,14 @@ namespace zx_disk { uint8_t mode = ZX_FDC_MODE_IDLE; uint8_t call_count = 0; - - uint8_t main_status_register = 0x80; - uint8_t st0 = 0x00; - uint8_t st1 = 0x00; - uint8_t st2 = 0x00; - uint8_t st3 = 0x00; - + //uint8_t data_direction = 0x00; // 0x40 + uint8_t fdd0busy = 0; uint8_t srt, hlt, hut, nd; + bool seeking = false; uint8_t current_head = 0; uint8_t current_drive = 0; + uint8_t current_track = 0; int zx_fdc_main_status_port_in(int port); int zx_fdc_data_port_in(int port); @@ -52,21 +55,50 @@ namespace zx_disk } + uint8_t main_status_register() + { + const uint8_t val = (fdd0busy) | + ((mode==ZX_FDC_MODE_IDLE) ? 0x00 : 0x10) | + ((mode==ZX_FDC_MODE_EXECUTION) ? 0x20 : 0x00) | + ((mode==ZX_FDC_MODE_RESULT) ? 0x40 : 0x00) | + (0x80); + return val; + + } + int zx_fdc_main_status_port_in(int port) { printf("FDC port 0x2ffd IN\n"); - return main_status_register; + return main_status_register(); + } + + uint8_t ST0() + { + return current_drive | (current_head<<2) | (seeking ? 0x20 : 0x00) | (fdd0busy ? 0x00 : 0x40); + } + + uint8_t ST3() + { + return current_drive | (current_head<<2) | 0x38; // ST3 } void start_command(uint8_t command); uint8_t (*process_current_command)(uint8_t) = nullptr; + uint8_t process_command_unknown(uint8_t command); uint8_t process_command_specify(uint8_t command); uint8_t process_command_sense_drive_status(uint8_t command); + uint8_t process_command_recalibrate(uint8_t command); + uint8_t process_command_sense_interrupt_status(uint8_t command); + uint8_t process_command_seek(uint8_t command); int zx_fdc_data_port_in(int port) { printf("FDC port 0x3ffd IN\n"); + if (mode == ZX_FDC_MODE_COMMAND) { + printf("IGNORED!\n"); + return 0; + } if (process_current_command) return process_current_command(0); return 0; } @@ -74,6 +106,10 @@ namespace zx_disk void zx_fdc_data_port_out(int port, int val) { printf("FDC port 0x3ffd OUT: 0x%02x\n", val); + if (mode == ZX_FDC_MODE_RESULT) { + printf("IGNORED!\n"); + return; + } if (process_current_command) process_current_command(val); else @@ -82,7 +118,8 @@ namespace zx_disk void start_command(uint8_t command) { - main_status_register |= ZX_FDC_MAIN_BUSY; + if ((fdd0busy) && (command != ZX_FDC_COMMAND_SENSE_INTERRUPT_STATUS)) return; + mode = ZX_FDC_MODE_COMMAND; call_count = 1; switch(command) @@ -93,14 +130,42 @@ namespace zx_disk case ZX_FDC_COMMAND_SENSE_DRIVE_STATUS: process_current_command = process_command_sense_drive_status; break; + case ZX_FDC_COMMAND_RECALIBRATE: + process_current_command = process_command_recalibrate; + fdd0busy = 1; + break; + case ZX_FDC_COMMAND_SENSE_INTERRUPT_STATUS: + process_current_command = process_command_sense_interrupt_status; + mode = ZX_FDC_MODE_RESULT; + call_count = 0; + break; + case ZX_FDC_COMMAND_SEEK: + process_current_command = process_command_seek; + fdd0busy = 1; + seeking = true; + break; default: { + process_current_command = process_command_unknown; mode = ZX_FDC_MODE_RESULT; call_count = 0; } } } + + // =================================================================== + // FDC COMMAND: UNKNOWN + // =================================================================== + uint8_t process_command_unknown(uint8_t command) + { + process_current_command = nullptr; + mode = ZX_FDC_MODE_IDLE; + const uint8_t val = ST0(); + printf("--> (returning 0x%02x)\n", val); + return val; + } + // =================================================================== // FDC COMMAND: SPECIFY (0x03) // =================================================================== @@ -118,7 +183,6 @@ namespace zx_disk call_count=0; process_current_command = nullptr; mode = ZX_FDC_MODE_IDLE; - main_status_register &= ~ZX_FDC_MAIN_BUSY; break; } return 0; @@ -138,12 +202,82 @@ namespace zx_disk mode = ZX_FDC_MODE_RESULT; break; case ZX_FDC_MODE_RESULT: + { process_current_command = nullptr; mode = ZX_FDC_MODE_IDLE; - main_status_register &= ~ZX_FDC_MAIN_BUSY; - return current_drive | (current_head<<2) | 0x38; // ST3 + const uint8_t val = ST3(); + printf("--> (returning 0x%02x)\n", val); + return val; + } } return 0; } + // =================================================================== + // FDC COMMAND: RECALIBRATE (0x07) + // =================================================================== + uint8_t process_command_recalibrate(uint8_t command) + { + switch (mode) + { + case ZX_FDC_MODE_COMMAND: + current_drive = command & 0x3; + call_count = 0; + current_track = 0; + process_current_command = nullptr; + mode = ZX_FDC_MODE_IDLE; + break; + } + return 0; + } + + // =================================================================== + // FDC COMMAND: SENSE INTERRUPT STATUS (0x08) + // =================================================================== + uint8_t process_command_sense_interrupt_status(uint8_t command) + { + switch (call_count) + { + case 0: + { + call_count++; + const uint8_t val = ST0(); + printf("--> (returning 0x%02x)\n", val); + return val; + } + case 1: + process_current_command = nullptr; + fdd0busy = 0; + seeking = false; + call_count = 0; + mode = ZX_FDC_MODE_IDLE; + printf("--> (returning 0x%02x)\n", current_track); + return current_track; + } + return 0; + } + + // =================================================================== + // FDC COMMAND: SEEK (0x0F) + // =================================================================== + uint8_t process_command_seek(uint8_t command) + { + switch (call_count) + { + case 1: + { + current_head = (command & 0x4)>>2; + current_drive = command & 0x3; + call_count++; + break; + } + case 2: + current_track = command; + process_current_command = nullptr; + call_count = 0; + mode = ZX_FDC_MODE_IDLE; + break; + } + return 0; + } }