diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 92b1365f8..8373d5c96 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -5,7 +5,7 @@ WINDRES = windres.exe CFLAGS = -O3 -march=native -mtune=native -fbranch-probabilities -fvpt -funroll-loops -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse -mstackrealign OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ cdrom-null.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o dac.o \ - device.o disc.o disc_86f.o disc_fdi.o disc_img.o disc_random.o disc_sector_86box.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ + device.o disc.o disc_86f.o disc_fdi.o disc_img_86box.o disc_random.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ i430nx.o i430vx.o i440fx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \ mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index e1f21c9db..fd5dc4328 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -5,7 +5,7 @@ WINDRES = windres.exe CFLAGS = -O3 -march=native -mtune=native -fbranch-probabilities -fvpt -funroll-loops -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse -mstackrealign OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ cdrom-null.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.o compaq.o config.o cpu.o dac.o \ - device.o disc.o disc_86f.o disc_fdi.o disc_img.o disc_random.o disc_sector_86box.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ + device.o disc.o disc_86f.o disc_fdi.o disc_img_86box.o disc_random.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ i430nx.o i430vx.o i440fx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \ mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \ diff --git a/src/codegen_ops_fpu.h b/src/codegen_ops_fpu.h index 69e20597e..02b3f4795 100644 --- a/src/codegen_ops_fpu.h +++ b/src/codegen_ops_fpu.h @@ -580,6 +580,7 @@ static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint MEM_LOAD_ADDR_EA_W(target_seg); STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.npxc, 0); + UPDATE_NPXC(0); return op_pc + 1; } diff --git a/src/codegen_ops_x86-64.h b/src/codegen_ops_x86-64.h index 05582c28d..dc6330cfd 100644 --- a/src/codegen_ops_x86-64.h +++ b/src/codegen_ops_x86-64.h @@ -4556,6 +4556,10 @@ static void FP_COMPARE_IL() FP_COMPARE_MEM(); } +static void UPDATE_NPXC(int reg) +{ +} + static void SET_BITS(uintptr_t addr, uint32_t val) { if (IS_32_ADDR(addr)) diff --git a/src/codegen_ops_x86.h b/src/codegen_ops_x86.h index 736700930..79db54ee5 100644 --- a/src/codegen_ops_x86.h +++ b/src/codegen_ops_x86.h @@ -2173,82 +2173,6 @@ static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) *host_reg2 = REG_ECX; } - -static double _fp_half = 0.5; - -static void FP_LOAD_ROUNDING() -{ - pclog("cpu_state.npxc %04x\n", cpu_state.npxc); - addbyte(0x8b); /*MOV EDX, npxc*/ - addbyte(0x15); - addlong((uintptr_t)&cpu_state.npxc); - addbyte(0xd9); /*FSTCW [ESP+8]*/ - addbyte(0x7c); - addbyte(0x24); - addbyte(0x08); - addbyte(0x89); /*MOV [ESP+12],EDX*/ - addbyte(0x54); - addbyte(0x24); - addbyte(0x0c); - addbyte(0xd9); /*FLDCW [ESP+12]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x0c); -} -static void FP_RESTORE_ROUNDING() -{ - addbyte(0xd9); /*FLDCW [ESP+8]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x08); -} - -static int32_t x87_fround32(double b) -{ - int64_t a, c; - - switch ((cpu_state.npxc >> 10) & 3) - { - case 0: /*Nearest*/ - a = (int64_t)floor(b); - c = (int64_t)floor(b + 1.0); - if ((b - a) < (c - b)) - return a; - else if ((b - a) > (c - b)) - return c; - else - return (a & 1) ? c : a; - case 1: /*Down*/ - return (int32_t)floor(b); - case 2: /*Up*/ - return (int32_t)ceil(b); - case 3: /*Chop*/ - return (int32_t)b; - } -} -static int64_t x87_fround64(double b) -{ - int64_t a, c; - - switch ((cpu_state.npxc >> 10) & 3) - { - case 0: /*Nearest*/ - a = (int64_t)floor(b); - c = (int64_t)floor(b + 1.0); - if ((b - a) < (c - b)) - return a; - else if ((b - a) > (c - b)) - return c; - else - return (a & 1) ? c : a; - case 1: /*Down*/ - return (int64_t)floor(b); - case 2: /*Up*/ - return (int64_t)ceil(b); - case 3: /*Chop*/ - return (int64_t)b; - } -} static int FP_LOAD_REG_INT_W(int reg) { addbyte(0x8b); /*MOV EBX, TOP*/ @@ -2268,25 +2192,19 @@ static int FP_LOAD_REG_INT_W(int reg) addbyte(0xdd); addbyte(cpu_state_offset(ST)); - addbyte(0x89); /*MOV [ESP+8], EAX*/ - addbyte(0x44); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); + addbyte(0xdb); /*FISTP [ESP]*/ + addbyte(0x1c); addbyte(0x24); - addbyte(0x08); - - addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); - CALL_FUNC(x87_fround32); - - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - - addbyte(0x8b); /*MOV EAX, [ESP+8]*/ - addbyte(0x44); - addbyte(0x24); - addbyte(0x08); - return REG_EBX; } static int FP_LOAD_REG_INT(int reg) @@ -2308,25 +2226,19 @@ static int FP_LOAD_REG_INT(int reg) addbyte(0xdd); addbyte(cpu_state_offset(ST)); - addbyte(0x89); /*MOV [ESP+8], EAX*/ - addbyte(0x44); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); + addbyte(0xdb); /*FISTP [ESP]*/ + addbyte(0x1c); addbyte(0x24); - addbyte(0x08); - - addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); - CALL_FUNC(x87_fround32); - - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - - addbyte(0x8b); /*MOV EAX, [ESP+8]*/ - addbyte(0x44); - addbyte(0x24); - addbyte(0x08); - return REG_EBX; } static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) @@ -2378,34 +2290,29 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(cpu_state_offset(MM)); addbyte(0xeb); /*JMP done*/ - addbyte(4+4+3+5+2+2+4); + addbyte(4+3+3+3+3+4); addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); addbyte(cpu_state_offset(ST)); - addbyte(0x89); /*MOV [ESP+8], EAX*/ - addbyte(0x44); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); + addbyte(0xdf); /*FISTPQ [ESP]*/ + addbyte(0x3c); addbyte(0x24); - addbyte(0x08); - - addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); - - CALL_FUNC(x87_fround64); - - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - - addbyte(0x89); /*MOV ECX, EDX*/ - addbyte(0xd1); - - addbyte(0x8b); /*MOV EAX, [ESP+8]*/ - addbyte(0x44); + addbyte(0x8b); /*MOV ECX, 4[ESP]*/ + addbyte(0x4c); addbyte(0x24); - addbyte(0x08); + addbyte(4); *host_reg1 = REG_EBX; *host_reg2 = REG_ECX; @@ -2511,31 +2418,9 @@ static void FP_OP_D(int op) addbyte(0x04); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { - addbyte(0x9b); /*FSTCW [ESP+8]*/ - addbyte(0xd9); - addbyte(0x7c); - addbyte(0x24); - addbyte(0x08); - addbyte(0x66); /*MOV AX, [ESP+8]*/ - addbyte(0x8b); - addbyte(0x44); - addbyte(0x24); - addbyte(0x08); - addbyte(0x66); /*AND AX, ~(3 << 10)*/ - addbyte(0x25); - addword(~(3 << 10)); - addbyte(0x66); /*OR AX, npxc & (3 << 10)*/ - addbyte(0x0d); - addword(cpu_state.npxc & (3 << 10)); - addbyte(0x66); /*MOV [ESP+12], AX*/ - addbyte(0x89); - addbyte(0x44); - addbyte(0x24); - addbyte(0x0c); - addbyte(0xd9); /*FLDCW [ESP+12]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x0c); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); } addbyte(0xdd); /*FLD ST[dst][EBP]*/ addbyte(0x45); @@ -2552,10 +2437,9 @@ static void FP_OP_D(int op) addbyte(cpu_state_offset(ST[cpu_state.TOP])); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { - addbyte(0xd9); /*FLDCW [ESP+8]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x08); + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); } } else @@ -2568,31 +2452,9 @@ static void FP_OP_D(int op) addbyte(0x24); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { - addbyte(0x9b); /*FSTCW [ESP+8]*/ - addbyte(0xd9); - addbyte(0x7c); - addbyte(0x24); - addbyte(0x08); - addbyte(0x66); /*MOV AX, [ESP+8]*/ - addbyte(0x8b); - addbyte(0x44); - addbyte(0x24); - addbyte(0x08); - addbyte(0x66); /*AND AX, ~(3 << 10)*/ - addbyte(0x25); - addword(~(3 << 10)); - addbyte(0x66); /*OR AX, npxc & (3 << 10)*/ - addbyte(0x0d); - addword(cpu_state.npxc & (3 << 10)); - addbyte(0x66); /*MOV [ESP+12], AX*/ - addbyte(0x89); - addbyte(0x44); - addbyte(0x24); - addbyte(0x0c); - addbyte(0xd9); /*FLDCW [ESP+12]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x0c); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); } addbyte(0x89); /*MOV [ESP+4], EDX*/ addbyte(0x54); @@ -2616,10 +2478,9 @@ static void FP_OP_D(int op) addbyte(cpu_state_offset(ST)); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { - addbyte(0xd9); /*FLDCW [ESP+8]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x08); + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); } } } @@ -3226,6 +3087,32 @@ static void FP_COMPARE_REG(int dst, int src) } } +static void UPDATE_NPXC(int reg) +{ + addbyte(0x66); /*AND cpu_state.new_npxc, ~0xc00*/ + addbyte(0x81); + addbyte(0x65); + addbyte(cpu_state_offset(new_npxc)); + addword(~0xc00); + if (reg) + { + addbyte(0x66); /*AND reg, 0xc00*/ + addbyte(0x81); + addbyte(0xe0 | reg); + addword(0xc00); + } + else + { + addbyte(0x66); /*AND AX, 0xc00*/ + addbyte(0x25); + addword(0xc00); + } + addbyte(0x66); /*OR cpu_state.new_npxc, reg*/ + addbyte(0x09); + addbyte(0x45 | (reg << 3)); + addbyte(cpu_state_offset(new_npxc)); +} + static int ZERO_EXTEND_W_B(int reg) { addbyte(0x0f); /*MOVZX regl, regb*/ diff --git a/src/codegen_x86.c b/src/codegen_x86.c index 6a688b407..7d2a7a9f9 100644 --- a/src/codegen_x86.c +++ b/src/codegen_x86.c @@ -563,6 +563,11 @@ void codegen_init() mem_store_addr_ea_b = gen_MEM_STORE_ADDR_EA_B(); block_pos = 1024; mem_store_addr_ea_q = gen_MEM_STORE_ADDR_EA_Q(); + + asm( + "fstcw %0\n" + : "=m" (cpu_state.old_npxc) + ); } void codegen_reset() diff --git a/src/disc.c b/src/disc.c index 034334cd6..12b3568f4 100644 --- a/src/disc.c +++ b/src/disc.c @@ -91,7 +91,7 @@ void disc_load(int drive, char *fn) p = get_extension(fn); if (!p) return; // setejecttext(drive, fn); - pclog("Loading :%i %s %s\n", drive, fn,p); + // pclog("Loading :%i %s %s\n", drive, fn,p); f = fopen(fn, "rb"); if (!f) return; fseek(f, -1, SEEK_END); @@ -101,7 +101,7 @@ void disc_load(int drive, char *fn) { if (!strcasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) { - pclog("Loading as %s\n", p); + // pclog("Loading as %s (UI write protected = %s)\n", p, ui_writeprot[drive] ? "yes" : "no"); driveloaders[drive] = c; loaders[c].load(drive, fn); drive_empty[drive] = 0; diff --git a/src/disc.h b/src/disc.h index 19a5371b7..24cdc968f 100644 --- a/src/disc.h +++ b/src/disc.h @@ -108,3 +108,34 @@ extern int drive_type[2]; #define BYTE_TYPE_AM 0x03 #define BYTE_TYPE_DATA 0x04 #define BYTE_TYPE_CRC 0x05 + +typedef union { + uint16_t word; + uint8_t bytes[2]; +} crc_t; + +void disc_calccrc(int drive, uint8_t byte, crc_t *crc_var); + +typedef struct +{ + uint8_t (*disk_flags)(int drive); + uint8_t (*side_flags)(int drive); + void (*writeback)(int drive); + void (*set_sector)(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n); + uint8_t (*read_data)(int drive, int side, uint16_t pos); + void (*write_data)(int drive, int side, uint16_t pos, uint8_t data); + int (*format_conditions)(int drive); + uint8_t check_crc; +} d86f_handler_t; + +d86f_handler_t d86f_handler[2]; + +void d86f_common_handlers(int drive); + +int d86f_is_40_track(int drive); + +uint8_t* d86f_track_data(int drive, int side); +uint8_t* d86f_track_layout(int drive, int side); + +uint16_t d86f_prepare_pretrack(int drive, int side, int iso, int write_data); +uint16_t d86f_prepare_sector(int drive, int side, int pos, uint8_t *id_buf, uint8_t *data_buf, int data_len, int write_data, int gap2, int gap3); diff --git a/src/disc_86f.c b/src/disc_86f.c index 1911947f2..322a10569 100644 --- a/src/disc_86f.c +++ b/src/disc_86f.c @@ -40,11 +40,6 @@ static uint16_t CRCTable[256]; static int d86f_drive; -typedef union { - uint16_t word; - uint8_t bytes[2]; -} crc_t; - typedef struct { uint8_t c; @@ -80,10 +75,10 @@ static struct uint32_t index_count; uint8_t state; uint8_t fill; - uint16_t track_pos; - uint16_t datac; - uint16_t id_pos; - uint16_t section_pos; + uint32_t track_pos; + uint32_t datac; + uint32_t id_pos; + uint32_t section_pos; crc_t calc_crc; crc_t track_crc; uint8_t track_byte; @@ -96,12 +91,100 @@ static struct uint8_t old_track_data_byte; uint8_t cur_track; uint8_t side_flag_bytes; + uint8_t wait_state; + uint8_t id_am_counter; + uint8_t id_counter; + uint8_t id_match; + uint8_t data_am_counter; } d86f[2]; +uint8_t* d86f_track_data(int drive, int side) +{ + return d86f[drive].track_data[side]; +} + +uint8_t* d86f_track_layout(int drive, int side) +{ + return d86f[drive].track_layout[side]; +} + +uint8_t d86f_side_flags(int drive); +int d86f_is_mfm(int drive); +void d86f_writeback(int drive); +void d86f_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n); +uint8_t d86f_poll_read_data(int drive, int side, uint16_t pos); +void d86f_poll_write_data(int drive, int side, uint16_t pos, uint8_t data); +int d86f_format_conditions(int drive); + +uint8_t d86f_disk_flags(int drive) +{ + return d86f[drive].disk_flags; +} + +uint8_t null_disk_flags(int drive) +{ + return 0x09; +} + +uint8_t null_side_flags(int drive) +{ + return 0x0A; +} + +void null_writeback(int drive) +{ + return; +} + +void null_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + return; +} + +uint8_t null_poll_read_data(int drive, int side, uint16_t pos) +{ + return 0xf6; +} + +void null_poll_write_data(int drive, int side, uint16_t pos, uint8_t data) +{ + return; +} + +int null_format_conditions(int drive) +{ + return 1; +} + +void d86f_unregister(int drive) +{ + d86f_handler[drive].disk_flags = null_disk_flags; + d86f_handler[drive].side_flags = null_side_flags; + d86f_handler[drive].writeback = null_writeback; + d86f_handler[drive].set_sector = null_set_sector; + d86f_handler[drive].read_data = null_poll_read_data; + d86f_handler[drive].write_data = null_poll_write_data; + d86f_handler[drive].format_conditions = null_format_conditions; + d86f_handler[drive].check_crc = 0; + d86f[drive].version = 0x0063; /* Proxied formats report as version 0.99. */ +} + +void d86f_register_86f(int drive) +{ + d86f_handler[drive].disk_flags = d86f_disk_flags; + d86f_handler[drive].side_flags = d86f_side_flags; + d86f_handler[drive].writeback = d86f_writeback; + d86f_handler[drive].set_sector = d86f_set_sector; + d86f_handler[drive].read_data = d86f_poll_read_data; + d86f_handler[drive].write_data = d86f_poll_write_data; + d86f_handler[drive].format_conditions = d86f_format_conditions; + d86f_handler[drive].check_crc = 1; +} + /* Needed for formatting! */ int d86f_is_40_track(int drive) { - return (d86f[drive].disk_flags & 1) ? 0 : 1; + return (d86f_handler[drive].disk_flags(drive) & 1) ? 0 : 1; } int d86f_realtrack(int drive, int track) @@ -138,9 +221,15 @@ static void d86f_setupcrc(uint16_t poly, uint16_t rvalue) } } +void disc_calccrc(int drive, uint8_t byte, crc_t *crc_var) +{ + crc_var->word = (crc_var->word << 8) ^ CRCTable[(crc_var->word >> 8)^byte]; +} + static void d86f_calccrc(int drive, uint8_t byte) { - d86f[drive].calc_crc.word = (d86f[drive].calc_crc.word << 8) ^ CRCTable[(d86f[drive].calc_crc.word >> 8)^byte]; + // d86f[drive].calc_crc.word = (d86f[drive].calc_crc.word << 8) ^ CRCTable[(d86f[drive].calc_crc.word >> 8)^byte]; + disc_calccrc(drive, byte, &(d86f[drive].calc_crc)); } void d86f_init() @@ -149,26 +238,86 @@ void d86f_init() memset(d86f, 0, sizeof(d86f)); d86f_setupcrc(0x1021, 0xcdb4); + + // d86f_unregister(0); + // d86f_unregister(1); } int d86f_get_sides(int drive) { - return (d86f[drive].disk_flags & 8) ? 2 : 1; + return (d86f_handler[drive].disk_flags(drive) & 8) ? 2 : 1; +} + +int d86f_get_rpm_mode(int drive) +{ + if (d86f[drive].version != 0x0115) return 0; + return (d86f_handler[drive].disk_flags(drive) & 0x60) >> 5; } int d86f_get_array_size(int drive) { - int pos = 25002; + int pos = 0; + int rm = 0; + rm = d86f_get_rpm_mode(drive); switch (d86f_hole(drive)) { case 0: + default: pos = 7500; + if (d86f[drive].version != 0x0115) return pos; + switch (rm) + { + case 1: + pos = 7575; + break; + case 2: + pos = 7614; + break; + case 3: + pos = 7653; + break; + default: + pos = 7500; + break; + } break; case 1: pos = 12500; + if (d86f[drive].version != 0x0115) return pos; + switch (rm) + { + case 1: + pos = 12626; + break; + case 2: + pos = 12690; + break; + case 3: + pos = 12755; + break; + default: + pos = 12500; + break; + } break; case 2: pos = 50000; + if (d86f[drive].version != 0x0115) return pos; + switch (rm) + { + case 1: + pos = 50505; + break; + case 2: + pos = 50761; + break; + case 3: + pos = 51020; + break; + default: + pos = 50000; + break; + } break; } return pos; @@ -176,7 +325,8 @@ int d86f_get_array_size(int drive) int d86f_valid_bit_rate(int drive) { - int rate = fdc_get_bit_rate(); + int rate = 0; + rate = fdc_get_bit_rate(); switch (d86f_hole(drive)) { case 0: /* DD */ @@ -192,6 +342,19 @@ int d86f_valid_bit_rate(int drive) return 1; } +void d86f_common_handlers(int drive) +{ + drives[drive].readsector = d86f_readsector; + drives[drive].writesector = d86f_writesector; + drives[drive].readaddress = d86f_readaddress; + drives[drive].hole = d86f_hole; + drives[drive].byteperiod = d86f_byteperiod; + drives[drive].poll = d86f_poll; + drives[drive].format = d86f_format; + drives[drive].realtrack = d86f_realtrack; + drives[drive].stop = d86f_stop; +} + void d86f_load(int drive, char *fn) { uint32_t magic = 0; @@ -202,6 +365,8 @@ void d86f_load(int drive, char *fn) uint8_t temp = 0; + d86f_unregister(drive); + writeprot[drive] = 0; d86f[drive].f = fopen(fn, "rb+"); if (!d86f[drive].f) @@ -211,6 +376,10 @@ void d86f_load(int drive, char *fn) return; writeprot[drive] = 1; } + if (ui_writeprot[drive]) + { + writeprot[drive] = 1; + } fwriteprot[drive] = writeprot[drive]; fseek(d86f[drive].f, 0, SEEK_END); @@ -236,7 +405,7 @@ void d86f_load(int drive, char *fn) fread(&(d86f[drive].version), 2, 1, d86f[drive].f); - if ((d86f[drive].version != 0x0100) && (d86f[drive].version != 0x010A) && (d86f[drive].version != 0x0114)) + if ((d86f[drive].version != 0x0100) && (d86f[drive].version != 0x010A) && (d86f[drive].version != 0x0114) && (d86f[drive].version != 0x0115)) { /* File is not of a recognized format version abort. */ pclog("86F: Unrecognized file version: %i.%02i\n", d86f[drive].version >> 8, d86f[drive].version & 0xFF); @@ -276,7 +445,7 @@ void d86f_load(int drive, char *fn) /* Load track 0 flags as default. */ d86f[drive].side_flag_bytes = d86f_get_sides(drive); - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { if ((d86f[drive].version == 0x010A) && (d86f_get_sides(drive) == 1)) { @@ -303,27 +472,22 @@ void d86f_load(int drive, char *fn) fseek(d86f[drive].f, 0, SEEK_SET); + d86f_register_86f(drive); + drives[drive].seek = d86f_seek; - drives[drive].readsector = d86f_readsector; - drives[drive].writesector = d86f_writesector; - drives[drive].readaddress = d86f_readaddress; - drives[drive].hole = d86f_hole; - drives[drive].byteperiod = d86f_byteperiod; - drives[drive].poll = d86f_poll; - drives[drive].format = d86f_format; - drives[drive].realtrack = d86f_realtrack; - drives[drive].stop = d86f_stop; + d86f_common_handlers(drive); } int d86f_hole(int drive) { - return (d86f[drive].disk_flags >> 1) & 3; + return (d86f_handler[drive].disk_flags(drive) >> 1) & 3; } -uint8_t d86f_flags(int drive) +uint8_t d86f_side_flags(int drive) { - int side = fdd_get_head(drive); - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + int side = 0; + side = fdd_get_head(drive); + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { return d86f[drive].side_flags[side]; } @@ -335,9 +499,13 @@ uint8_t d86f_flags(int drive) uint8_t d86f_track_flags(int drive) { - uint8_t tf = d86f_flags(drive); - uint8_t rr = tf & 0x27; - uint8_t dr = fdd_get_flags(drive) & 7; + uint8_t tf = 0; + uint8_t rr = 0; + uint8_t dr = 0; + + tf = d86f_handler[drive].side_flags(drive); + rr = tf & 0x27; + dr = fdd_get_flags(drive) & 7; tf &= ~0x27; switch (rr) @@ -404,9 +572,34 @@ int d86f_is_mfm(int drive) uint16_t d86f_get_raw_size(int drive) { double rate = 0.0; - int mfm = d86f_is_mfm(drive); - double rpm = (d86f_track_flags(drive) & 0x20) ? 360.0 : 300.0; + int mfm = 0; + double rpm = 300.0; + double rpm_diff = 0.0; double size = 6250.0; + + mfm = d86f_is_mfm(drive); + rpm = (d86f_track_flags(drive) & 0x20) ? 360.0 : 300.0; + rpm_diff = rpm * 0.005; + + if (d86f[drive].version == 0x0115) + { + switch (d86f_get_rpm_mode(drive)) + { + case 0: + rpm_diff *= 2.0; + break; + case 1: + rpm_diff *= 3.0; + break; + case 2: + rpm_diff *= 4.0; + break; + default: + rpm_diff = 0.0; + break; + } + rpm -= rpm_diff; + } switch (d86f_track_flags(drive) & 7) { case 0: @@ -424,6 +617,9 @@ uint16_t d86f_get_raw_size(int drive) case 5: rate = 2000.0; break; + default: + rate = 250.0; + break; } if (!mfm) rate /= 2.0; size = (size / 250.0) * rate; @@ -433,17 +629,18 @@ uint16_t d86f_get_raw_size(int drive) void d86f_seek(int drive, int track) { - int sides = d86f_get_sides(drive); + int sides; int side; int full_size = 25000; int store_size = 50000; int flag_bytes = 2; - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + sides = d86f_get_sides(drive); + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { full_size = d86f_get_array_size(drive); store_size = full_size << 1; if (d86f[drive].side_flag_bytes == 2) flag_bytes++; - if (d86f[drive].version == 0x0114) flag_bytes += 4; + if ((d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) flag_bytes += 4; } if (d86f_is_40_track(drive) && fdd_doublestep_40(drive)) @@ -461,7 +658,7 @@ void d86f_seek(int drive, int track) { /* Track does not exist in the image, initialize it as unformatted. */ d86f[drive].track_in_file = 0; - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { for (side = 0; side < d86f_get_sides(drive); side++) { @@ -479,14 +676,14 @@ void d86f_seek(int drive, int track) fseek(d86f[drive].f, d86f[drive].track_offset[track], SEEK_SET); - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { for (side = 0; side < d86f[drive].side_flag_bytes; side++) { fread(&(d86f[drive].side_flags[side]), 1, 1, d86f[drive].f); } - if (d86f[drive].version == 0x0114) + if ((d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { for (side = 0; side < d86f[drive].side_flag_bytes; side++) { @@ -516,33 +713,37 @@ void d86f_writeback(int drive) int full_size = 25000; int store_size = 50000; int flag_bytes = 2; - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { full_size = d86f_get_array_size(drive); store_size = full_size << 1; if (d86f[drive].side_flag_bytes == 2) flag_bytes++; - if (d86f[drive].version == 0x0114) flag_bytes += 4; + if ((d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) flag_bytes += 4; } if (!d86f[drive].f) + { return; + } if (!d86f[drive].track_in_file) + { return; /*Should never happen*/ + } fseek(d86f[drive].f, 7, SEEK_SET); fwrite(d86f[drive].track_offset, 1, 1024, d86f[drive].f); fseek(d86f[drive].f, d86f[drive].track_offset[track], SEEK_SET); - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { for (side = 0; side < d86f[drive].side_flag_bytes; side++) { fwrite(&(d86f[drive].side_flags[side]), 1, 1, d86f[drive].f); } - if (d86f[drive].version == 0x0114) + if ((d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { for (side = 0; side < d86f[drive].side_flag_bytes; side++) { @@ -579,10 +780,17 @@ void d86f_reset(int drive, int side) static int d86f_get_bitcell_period(int drive) { double rate = 0.0; - int mfm = (d86f_track_flags(drive) & 8) ? 1 : 0; - double rpm = (d86f_track_flags(drive) & 0x20) ? 360.0 : 300.0; + int mfm = 0; + int tflags = 0; + double rpm = 0; double size = 8000.0; - switch (d86f_track_flags(drive) & 7) + + tflags = d86f_track_flags(drive); + + mfm = (tflags & 8) ? 1 : 0; + rpm = (tflags & 0x20) ? 360.0 : 300.0; + + switch (tflags & 7) { case 0: rate = 500.0; @@ -631,9 +839,11 @@ void d86f_readsector(int drive, int sector, int track, int side, int rate, int s else d86f[drive].req_sector.id.r = sector; + d86f[drive].rw_sector_id.dword = 0xFFFFFFFF; + d86f[drive].last_sector.dword = 0xFFFFFFFF; d86f[drive].req_sector.id.n = sector_size; d86f[drive].index_count = 0; - + d86f[drive].wait_state = 1; d86f[drive].state = STATE_READ_FIND_SECTOR; } @@ -646,17 +856,27 @@ void d86f_writesector(int drive, int sector, int track, int side, int rate, int // pclog("d86f_writesector: drive=%c: fdc_period=%i img_period=%i rate=%i chrn=%08X\n", drive + 0x41, fdc_get_bitcell_period(), d86f_get_bitcell_period(drive), rate, d86f[drive].req_sector.dword); + if (writeprot[drive] || swwp) + { + // pclog("Write protected\n"); + fdc_writeprotect(); + return; + } + if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) { - pclog("Wrong side\n"); + // pclog("Wrong side\n"); fdc_notfound(); d86f[drive].state = STATE_IDLE; d86f[drive].index_count = 0; return; } + d86f[drive].rw_sector_id.dword = 0xFFFFFFFF; + d86f[drive].last_sector.dword = 0xFFFFFFFF; d86f_drive = drive; d86f[drive].index_count = 0; + d86f[drive].wait_state = 1; d86f[drive].state = STATE_WRITE_FIND_SECTOR; } @@ -675,77 +895,260 @@ void d86f_readaddress(int drive, int track, int side, int rate) return; } + d86f[drive].rw_sector_id.dword = 0xFFFFFFFF; + d86f[drive].last_sector.dword = 0xFFFFFFFF; d86f_drive = drive; d86f[drive].index_count = 0; + d86f[drive].wait_state = 1; d86f[drive].state = STATE_READ_FIND_ADDRESS; } +uint16_t d86f_prepare_pretrack(int drive, int side, int iso, int write_data) +{ + uint16_t i; + + int mfm = 0; + int real_gap0_len = 0; + int sync_len = 0; + int real_gap1_len = 0; + + mfm = d86f_is_mfm(drive); + real_gap0_len = mfm ? 80 : 40; + sync_len = mfm ? 12 : 6; + real_gap1_len = mfm ? 50 : 26; + + d86f[drive].index_hole_pos[side] = 0; + + memset(d86f[drive].track_layout[side], BYTE_GAP4, d86f_get_raw_size(drive)); + if (write_data) memset(d86f[drive].track_data[side], mfm ? 0x4E : 0xFF, d86f_get_raw_size(drive)); + i = 0; + + if (!iso) + { + memset(d86f[drive].track_layout[side] + i, BYTE_GAP0, real_gap0_len); + if (write_data) memset(d86f[drive].track_data[side] + i, mfm ? 0x4E : 0xFF, real_gap0_len); + i += real_gap0_len; + memset(d86f[drive].track_layout[side] + i, BYTE_I_SYNC, sync_len); + if (write_data) memset(d86f[drive].track_data[side] + i, 0, sync_len); + i += sync_len; + if (mfm) + { + memset(d86f[drive].track_layout[side] + i, BYTE_IAM_SYNC, 3); + if (write_data) memset(d86f[drive].track_data[side] + i, 0xC2, 3); + i += 3; + } + memset(d86f[drive].track_layout[side] + i, BYTE_IAM, 1); + if (write_data) memset(d86f[drive].track_data[side] + i, 0xFC, 1); + i++; + } + memset(d86f[drive].track_layout[side] + i, BYTE_GAP1, real_gap1_len); + if (write_data) memset(d86f[drive].track_data[side] + i, mfm ? 0x4E : 0xFF, real_gap1_len); + i += real_gap1_len; + + return i; +} + +void d86f_calccrc_buf(int drive, uint8_t *buf, uint16_t len) +{ + uint16_t i = 0; + + for (i = 0; i < len; i++) + { + d86f_calccrc(drive, buf[i]); + } +} + +static void *d86f_memset(void *str, int c, size_t n, size_t s, uint16_t rs) +{ + void *temp; + + size_t wrap_n[2]; + uint8_t *wrap_str[2]; + + if ((n + s - 1) >= rs) + { + /* This is going to wrap around, so we need to split the data in two. */ + wrap_n[0] = ((rs - 1) - s) + 1; + wrap_n[1] = n - wrap_n[0]; + wrap_str[0] = (uint8_t *) str; + wrap_str[1] = wrap_str[0] - s; + temp = memset(wrap_str[0], c, wrap_n[0]); + temp = memset(wrap_str[1], c, wrap_n[1]); + } + else + { + /* No wrap around, do a standard memcpy. */ + temp = memset(str, c, n); + } + return temp; +} + +static void *d86f_memcpy(void *str1, const void *str2, size_t n, size_t s, uint16_t rs) +{ + void *temp; + + size_t wrap_n[2]; + uint8_t *wrap_str1[2]; + uint8_t *wrap_str2[2]; + + if ((n + s - 1) >= rs) + { + /* This is going to wrap around, so we need to split the data in two. */ + wrap_n[0] = ((rs - 1) - s) + 1; + wrap_n[1] = n - wrap_n[0]; + wrap_str1[0] = (uint8_t *) str1; + wrap_str2[0] = (uint8_t *) str2; + wrap_str1[1] = wrap_str1[0] - s; + wrap_str2[1] = wrap_str2[0] + wrap_n[0]; + temp = memcpy(wrap_str1[0], wrap_str2[0], wrap_n[0]); + temp = memcpy(wrap_str1[1], wrap_str2[1], wrap_n[1]); + } + else + { + /* No wrap around, do a standard memcpy. */ + temp = memcpy(str1, str2, n); + } + return temp; +} + +uint16_t d86f_prepare_sector(int drive, int side, int pos, uint8_t *id_buf, uint8_t *data_buf, int data_len, int write_data, int gap2, int gap3) +{ + uint16_t i = pos; + uint16_t j = 0; + uint16_t rs = 0; + + uint8_t am[4] = { 0xA1, 0xA1, 0xA1 }; + + int real_gap2_len = gap2; + int real_gap3_len = gap3; + int mfm = 0; + int sync_len = 0; + + rs = d86f_get_raw_size(drive); + + mfm = d86f_is_mfm(drive); + sync_len = mfm ? 12 : 6; + + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_ID_SYNC, sync_len, i, rs); + if (write_data) d86f_memset(d86f[drive].track_data[side] + i, 0, sync_len, i, rs); + i += sync_len; + i %= rs; + if (mfm) + { + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_IDAM_SYNC, 3, i, rs); + if (write_data) + { + d86f[drive].calc_crc.word = 0xffff; + d86f_memset(d86f[drive].track_data[side] + i, 0xA1, 3, i, rs); + d86f_calccrc_buf(drive, am, 3); + } + i += 3; + i %= rs; + } + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_IDAM, 1, i, rs); + if (write_data) + { + if (!mfm) d86f[drive].calc_crc.word = 0xffff; + d86f_memset(d86f[drive].track_data[side] + i, 0xFE, 1, i, rs); + d86f_calccrc(drive, 0xFE); + } + i++; + i %= rs; + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_ID, 4, i, rs); + if (write_data) + { + d86f_memcpy(d86f[drive].track_data[side] + i, id_buf, 4, i, rs); + d86f_calccrc_buf(drive, id_buf, 4); + // if ((id_buf[0] == 4) && (id_buf[1] == 0) && (id_buf[2] == 19) && (id_buf[3] == 2)) pclog("Prepare (%i %i %i %i): ID CRC %04X\n", id_buf[0], id_buf[1], id_buf[2], id_buf[3], d86f[drive].calc_crc); + } + i += 4; + i %= rs; + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_ID_CRC, 2, i, rs); + if (write_data) + { + d86f[drive].track_data[side][i] = d86f[drive].calc_crc.bytes[1]; + d86f[drive].track_data[side][(i + 1) % rs] = d86f[drive].calc_crc.bytes[0]; + } + i += 2; + i %= rs; + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_GAP2, real_gap2_len, i, rs); + if (write_data) d86f_memset(d86f[drive].track_data[side] + i, mfm ? 0x4E : 0xFF, real_gap2_len, i, rs); + i += real_gap2_len; + i %= rs; + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_DATA_SYNC, sync_len, i, rs); + if (write_data) d86f_memset(d86f[drive].track_data[side] + i, 0, sync_len, i, rs); + i += sync_len; + i %= rs; + if (mfm) + { + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_DATAAM_SYNC, 3, i, rs); + if (write_data) + { + d86f[drive].calc_crc.word = 0xffff; + d86f_memset(d86f[drive].track_data[side] + i, 0xA1, 3, i, rs); + d86f_calccrc_buf(drive, am, 3); + } + i += 3; + i %= rs; + } + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_DATAAM, 1, i, rs); + if (write_data) + { + if (!mfm) d86f[drive].calc_crc.word = 0xffff; + d86f_memset(d86f[drive].track_data[side] + i, 0xFB, 1, i, rs); + d86f_calccrc(drive, 0xFB); + } + i++; + i %= rs; + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_DATA, data_len, i, rs); + if (write_data) + { + d86f_memcpy(d86f[drive].track_data[side] + i, data_buf, data_len, i, rs); + d86f_calccrc_buf(drive, data_buf, data_len); + // if ((id_buf[0] == 4) && (id_buf[1] == 0) && (id_buf[2] == 19) && (id_buf[3] == 2)) pclog("Prepare (%i %i %i %i): Data CRC %04X\n", id_buf[0], id_buf[1], id_buf[2], id_buf[3], d86f[drive].calc_crc); + } + i += data_len; + i %= rs; + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_DATA_CRC, 2, i, rs); + if (write_data) + { + d86f[drive].track_data[side][i] = d86f[drive].calc_crc.bytes[1]; + d86f[drive].track_data[side][(i + 1) % rs] = d86f[drive].calc_crc.bytes[0]; + } + i += 2; + i %= rs; + d86f_memset(d86f[drive].track_layout[side] + i, BYTE_GAP3, real_gap3_len, i, rs); + d86f_memset(d86f[drive].track_data[side] + i, mfm ? 0x4E : 0xFF, real_gap3_len, i, rs); + i += real_gap3_len; + i %= rs; + + return i; +} + void d86f_prepare_track_layout(int drive, int side) { - int i = 0; - int j = 0; - int perp_wg = fdc_get_perp() & 3; - int real_gap0_len = d86f_is_mfm(drive) ? 80 : 40; - int sync_len = d86f_is_mfm(drive) ? 12 : 6; - int am_len = d86f_is_mfm(drive) ? 4 : 1; - int real_gap1_len = d86f_is_mfm(drive) ? 50 : 26; - int real_gap2_len = (perp_wg == 3) ? 41 : 22; - int real_gap3_len = fdc_get_gap(); + uint16_t i = 0; + uint16_t j = 0; + uint16_t sc = 0; + uint16_t dtl = 0; + int real_gap2_len = 0; + int real_gap3_len = 0; + sc = fdc_get_format_sectors(); + dtl = 128 << fdc_get_format_n(); + real_gap2_len = fdc_get_gap2(drive ^ fdd_swap); + real_gap3_len = fdc_get_gap(); - memset(d86f[drive].track_layout[side], BYTE_GAP4, d86f_get_raw_size(drive)); - i = 0; + i = d86f_prepare_pretrack(drive, side, 0, 0); - memset(d86f[drive].track_layout[side] + i, BYTE_GAP0, real_gap0_len); - i += real_gap0_len; - memset(d86f[drive].track_layout[side] + i, BYTE_I_SYNC, sync_len); - i += sync_len; - if (d86f_is_mfm(drive)) + for (j = 0; j < sc; j++) { - memset(d86f[drive].track_layout[side] + i, BYTE_IAM_SYNC, 3); - i += 3; + i = d86f_prepare_sector(drive, side, i, NULL, NULL, dtl, 0, real_gap2_len, real_gap3_len); } - memset(d86f[drive].track_layout[side] + i, BYTE_IAM, 1); - i++; - memset(d86f[drive].track_layout[side] + i, BYTE_GAP1, real_gap1_len); - i += real_gap1_len; +} - if ((d86f[drive].version == 0x0100) || (d86f[drive].version == 0x010A)) - { - d86f[drive].track_layout[side][0] |= BYTE_INDEX_HOLE; - } - for (j = 0; j < fdc_get_format_sectors(); j++) - { - memset(d86f[drive].track_layout[side] + i, BYTE_ID_SYNC, sync_len); - i += sync_len; - if (d86f_is_mfm(drive)) - { - memset(d86f[drive].track_layout[side] + i, BYTE_IDAM_SYNC, 3); - i += 3; - } - memset(d86f[drive].track_layout[side] + i, BYTE_IDAM, 1); - i++; - memset(d86f[drive].track_layout[side] + i, BYTE_ID, 4); - i += 4; - memset(d86f[drive].track_layout[side] + i, BYTE_ID_CRC, 2); - i += 2; - memset(d86f[drive].track_layout[side] + i, BYTE_GAP2, real_gap2_len); - i += real_gap2_len; - memset(d86f[drive].track_layout[side] + i, BYTE_DATA_SYNC, sync_len); - i += sync_len; - if (d86f_is_mfm(drive)) - { - memset(d86f[drive].track_layout[side] + i, BYTE_DATAAM_SYNC, 3); - i += 3; - } - memset(d86f[drive].track_layout[side] + i, BYTE_DATAAM, 1); - i++; - memset(d86f[drive].track_layout[side] + i, BYTE_DATA, (128 << fdc_get_format_n())); - i += (128 << fdc_get_format_n()); - memset(d86f[drive].track_layout[side] + i, BYTE_DATA_CRC, 2); - i += 2; - memset(d86f[drive].track_layout[side] + i, BYTE_GAP3, real_gap3_len); - i += real_gap3_len; - } +int d86f_format_conditions(int drive) +{ + return d86f_valid_bit_rate(drive); } int d86f_can_format(int drive) @@ -754,8 +1157,7 @@ int d86f_can_format(int drive) temp = !writeprot[drive]; temp = temp && !swwp; temp = temp && fdd_can_read_medium(drive ^ fdd_swap); - temp = temp && d86f_valid_bit_rate(drive); - pclog("Bit rate is %svalid\n", d86f_valid_bit_rate(drive) ? "" : "not "); + temp = temp && d86f_handler[drive].format_conditions(drive); /* Allows proxied formats to add their own extra conditions to formatting. */ return temp; } @@ -764,12 +1166,12 @@ void d86f_format(int drive, int track, int side, int rate, uint8_t fill) int full_size = 25000; int store_size = 50000; int flag_bytes = 2; - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { full_size = d86f_get_array_size(drive); store_size = full_size << 1; if (d86f[drive].side_flag_bytes == 2) flag_bytes++; - if (d86f[drive].version == 0x0114) flag_bytes += 4; + if ((d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) flag_bytes += 4; } d86f[drive].req_sector.id.c = d86f[drive].cur_track; @@ -777,8 +1179,15 @@ void d86f_format(int drive, int track, int side, int rate, uint8_t fill) if ((side && (d86f_get_sides(drive) == 1)) || !(d86f_can_format(drive))) { - if (side && (d86f_get_sides(drive) == 1)) pclog("Wrong side\n"); - if (!(d86f_can_format(drive))) pclog("Can't format\n"); + /* if (side && (d86f_get_sides(drive) == 1)) pclog("Wrong side\n"); + if (!(d86f_can_format(drive))) + { + if(writeprot[drive]) pclog("Drive is write-protected\n"); + if (swwp) pclog("Software write-protect is enabled\n"); + if (!fdd_can_read_medium(drive ^ fdd_swap)) pclog("Drive can't read medium\n");; + pclog("Extra conditions: %i\n", d86f_handler[drive].format_conditions(drive)); + pclog("Hole: %i, rate: %i\n", d86f_hole(drive), fdc_get_bit_rate()); + } */ fdc_notfound(); d86f[drive].state = STATE_IDLE; d86f[drive].index_count = 0; @@ -787,7 +1196,7 @@ void d86f_format(int drive, int track, int side, int rate, uint8_t fill) if ((d86f[drive].cur_track < 0) || (d86f[drive].cur_track > 256)) { - pclog("Track below 0 or above 256\n"); + // pclog("Track below 0 or above 256\n"); fdc_writeprotect(); d86f[drive].state = STATE_IDLE; d86f[drive].index_count = 0; @@ -798,34 +1207,43 @@ void d86f_format(int drive, int track, int side, int rate, uint8_t fill) d86f[drive].fill = fill; d86f[drive].index_count = 0; /* Let's prepare the track space and layout before filling. */ - d86f[drive].track_flags &= 0xc0; - d86f[drive].track_flags |= (fdd_getrpm(drive ^ fdd_swap) == 360) ? 0x20 : 0; - d86f[drive].track_flags |= fdc_get_bit_rate(); - d86f[drive].track_flags |= fdc_is_mfm() ? 8 : 0; - if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114)) + if (d86f[drive].version != 0x0063) { - d86f[drive].side_flags[side] = d86f[drive].track_flags; - - if (d86f[drive].version == 0x0114) + d86f[drive].track_flags &= 0xc0; + d86f[drive].track_flags |= (fdd_getrpm(drive ^ fdd_swap) == 360) ? 0x20 : 0; + d86f[drive].track_flags |= fdc_get_bit_rate(); + d86f[drive].track_flags |= fdc_is_mfm() ? 8 : 0; + if ((d86f[drive].version == 0x010A) || (d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { - d86f[drive].index_hole_pos[side] = 0; + d86f[drive].side_flags[side] = d86f[drive].track_flags; + + if ((d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) + { + d86f[drive].index_hole_pos[side] = 0; + } } } memset(d86f[drive].track_data[side], 0xFF, full_size); - d86f_prepare_track_layout(drive, side); - - if (!d86f[drive].track_in_file) + /* For version 0.99 (= another format proxied to the 86F handler), the track layout is fixed. */ + if (d86f[drive].version != 0x0063) { - /* Track is absent from the file, let's add it. */ - d86f[drive].track_offset[d86f[drive].cur_track] = d86f[drive].file_size; - d86f[drive].file_size += store_size + flag_bytes; - if (d86f_get_sides(drive) == 2) + d86f_prepare_track_layout(drive, side); + + if (!d86f[drive].track_in_file) { - d86f[drive].file_size += store_size; + /* Track is absent from the file, let's add it. */ + d86f[drive].track_offset[d86f[drive].cur_track] = d86f[drive].file_size; + d86f[drive].file_size += store_size + flag_bytes; + if (d86f_get_sides(drive) == 2) + { + d86f[drive].file_size += store_size; + } + d86f[drive].track_in_file = 1; } - d86f[drive].track_in_file = 1; } + // pclog("Formatting track %i side %i\n", d86f[drive].cur_track, side); + d86f[drive].state = STATE_FORMAT_FIND; } @@ -867,12 +1285,11 @@ int d86f_can_read_address(int drive) return temp; } -int d86f_should_write_am(int drive) +int d86f_find_state_nf_ignore_id(int drive) { int temp; - temp = (d86f[drive].state == STATE_WRITE_FIND_SECTOR); - temp = temp && (d86f[drive].req_sector.dword == d86f[drive].last_sector.dword); - temp = temp && d86f_can_read_address(drive); + temp = temp || (d86f[drive].state == STATE_READ_FIND_FIRST_SECTOR); + temp = temp || (d86f[drive].state == STATE_READ_FIND_NEXT_SECTOR); return temp; } @@ -880,8 +1297,7 @@ int d86f_find_state_nf(int drive) { int temp; temp = (d86f[drive].state == STATE_READ_FIND_SECTOR); - temp = temp || (d86f[drive].state == STATE_READ_FIND_FIRST_SECTOR); - temp = temp || (d86f[drive].state == STATE_READ_FIND_NEXT_SECTOR); + temp = temp || d86f_find_state_nf_ignore_id(drive); temp = temp || (d86f[drive].state == STATE_WRITE_FIND_SECTOR); temp = temp || (d86f[drive].state == STATE_READ_FIND_ADDRESS); return temp; @@ -948,20 +1364,41 @@ int d86f_data_size(int drive) return temp; } +uint32_t d86f_get_pos(int drive) +{ + uint32_t pos; + if (d86f[drive].track_pos >= d86f[drive].section_pos) + { + pos = d86f[drive].track_pos - d86f[drive].section_pos; + } + else + { + /* A wrap arround has occurred, let's add the raw size to the position. */ + pos = d86f_get_raw_size(drive) + d86f[drive].track_pos; + pos -= d86f[drive].section_pos; + } + + return pos; +} + void d86f_poll_write_crc(int drive, int side) { if (d86f[drive].state != STATE_FORMAT) return; - d86f[drive].id_pos = d86f[drive].track_pos - d86f[drive].section_pos; + d86f[drive].id_pos = d86f_get_pos(drive); d86f[drive].track_data[side][d86f[drive].track_pos] = d86f[drive].track_data_byte = d86f[drive].calc_crc.bytes[d86f[drive].id_pos ^ 1]; } void d86f_poll_advancebyte(int drive, int side) { + if (d86f_handler[drive].side_flags == NULL) + { + fatal("NULL side flags handler\n"); + } d86f[drive].old_track_byte = d86f[drive].track_byte; d86f[drive].old_track_index = d86f[drive].track_index; d86f[drive].old_track_data_byte = d86f[drive].track_data_byte; - if (d86f[drive].version == 0x0114) + if ((d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { d86f[drive].old_track_fuzzy = d86f[drive].track_fuzzy; } @@ -974,8 +1411,9 @@ void d86f_poll_advancebyte(int drive, int side) d86f[drive].track_byte = d86f[drive].track_layout[side][d86f[drive].track_pos] & ~BYTE_INDEX_HOLE; d86f[drive].track_index = d86f[drive].track_layout[side][d86f[drive].track_pos] & BYTE_INDEX_HOLE; d86f[drive].track_data_byte = d86f[drive].track_data[side][d86f[drive].track_pos]; + d86f[drive].track_fuzzy = 0; } - else if (d86f[drive].version == 0x0114) + else if ((d86f[drive].version == 0x0114) || (d86f[drive].version == 0x0115)) { d86f[drive].track_byte = d86f[drive].track_layout[side][d86f[drive].track_pos] & ~BYTE_IS_FUZZY; d86f[drive].track_index = (d86f[drive].track_pos == d86f[drive].index_hole_pos[side]); @@ -990,6 +1428,13 @@ void d86f_poll_advancebyte(int drive, int side) d86f[drive].track_data_byte = d86f[drive].track_data[side][d86f[drive].track_pos]; } } + else if (d86f[drive].version == 0x0063) + { + d86f[drive].track_byte = d86f[drive].track_layout[side][d86f[drive].track_pos] & ~BYTE_INDEX_HOLE; + d86f[drive].track_index = (d86f[drive].track_pos == 0); + d86f[drive].track_data_byte = d86f[drive].track_data[side][d86f[drive].track_pos]; + d86f[drive].track_fuzzy = 0; + } } void d86f_poll_reset(int drive, int side) @@ -1019,15 +1464,10 @@ int d86f_poll_check_notfound(int drive) } } -void d86f_poll_finish(int drive, int side) -{ - d86f_poll_reset(drive, side); - d86f[drive].last_sector.dword = 0xFFFFFFFF; -} - int d86f_mark_index_hole(int drive) { - int temp = (d86f[drive].version == 0x0100); + int temp; + temp = (d86f[drive].version == 0x0100); temp = temp || (d86f[drive].version == 0x010A); return temp; } @@ -1039,6 +1479,21 @@ void d86f_poll_write(int drive, int side, uint8_t data, uint8_t type) if (!d86f[drive].track_pos && d86f_mark_index_hole(drive)) d86f[drive].track_layout[side][d86f[drive].track_pos] |= BYTE_INDEX_HOLE; } +void d86f_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + return; +} + +uint8_t d86f_poll_read_data(int drive, int side, uint16_t pos) +{ + return d86f[drive].track_data_byte; +} + +void d86f_poll_write_data(int drive, int side, uint16_t pos, uint8_t data) +{ + d86f_poll_write(drive, side, data, BYTE_DATA); +} + void d86f_poll_readwrite(int drive, int side) { int data; @@ -1047,7 +1502,8 @@ void d86f_poll_readwrite(int drive, int side) if (d86f_read_state_data(drive)) { max_len = d86f_data_size(drive); - data = d86f[drive].track_data_byte; + + data = d86f_handler[drive].read_data(drive, side, d86f[drive].datac); if (d86f[drive].datac < d86f_get_data_len(drive)) { fdc_data(data); @@ -1057,9 +1513,11 @@ void d86f_poll_readwrite(int drive, int side) else if (d86f[drive].state == STATE_WRITE_SECTOR) { max_len = d86f_data_size(drive); + if (d86f[drive].datac < d86f_get_data_len(drive)) { data = fdc_getdata(d86f[drive].datac == ((128 << ((uint32_t) d86f[drive].last_sector.id.n)) - 1)); + if (data == -1) { data = 0; @@ -1071,9 +1529,10 @@ void d86f_poll_readwrite(int drive, int side) } if (!disable_write) { - d86f_poll_write(drive, side, data, BYTE_DATA); + d86f_handler[drive].write_data(drive, side, d86f[drive].datac, data); } - d86f_calccrc(drive, d86f[drive].track_data_byte); + // d86f_calccrc(drive, d86f[drive].track_data_byte); + d86f_calccrc(drive, data & 0xff); } else if (d86f_read_state_crc(drive)) { @@ -1093,15 +1552,17 @@ void d86f_poll_readwrite(int drive, int side) max_len = fdc_get_gap(); if (d86f[drive].datac == (fdc_get_gap() - 1)) { - d86f_poll_finish(drive, side); - if (d86f[drive].track_crc.word != d86f[drive].calc_crc.word) + d86f_poll_reset(drive, side); + if ((d86f[drive].track_crc.word != d86f[drive].calc_crc.word) && d86f_handler[drive].check_crc) { - // pclog("d86f_poll(): Data CRC error (%i %i %i %i) (%04X %04X)\n", d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n, d86f[drive].track_crc.word, d86f[drive].calc_crc.word); + pclog("d86f_poll(): Data CRC error (%i %i %i %i) (%04X %04X)\n", d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n, d86f[drive].track_crc.word, d86f[drive].calc_crc.word); fdc_finishread(); fdc_datacrcerror(); + fatal("Deliberate fatal\n"); } else { + // pclog("Read finished (%i %i %i %i)\n", d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n); fdc_sector_finishread(); } return; @@ -1116,11 +1577,12 @@ void d86f_poll_readwrite(int drive, int side) } if (d86f[drive].datac == (max_len - 1)) { - d86f_poll_finish(drive, side); if (!disable_write) { - d86f_writeback(drive); + d86f_handler[drive].writeback(drive); } + d86f_poll_reset(drive, side); + // pclog("Write finished (%i %i %i %i)\n", d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n); fdc_sector_finishread(drive); return; } @@ -1136,9 +1598,48 @@ void d86f_poll_readwrite(int drive, int side) } } +int d86f_end_wait_state(int drive) +{ + int temp = 0; + int fdc_mfm = 0; + int disk_mfm = 0; + fdc_mfm = fdc_is_mfm(); + disk_mfm = d86f_is_mfm(drive); + temp = temp || ((d86f[drive].track_byte == BYTE_IDAM_SYNC) && fdc_mfm && disk_mfm); + temp = temp || ((d86f[drive].track_byte == BYTE_IDAM) && !fdc_mfm && !disk_mfm); + temp = temp && d86f_can_read_address(drive); /* This is so the wait state never ends if the data rate or encoding is wrong. */ + return temp; +} + +void d86f_poll_find_nf_wait(int drive, int side) +{ + if (d86f[drive].track_index) + { + // pclog("d86f_poll_find_nf(): Index pulse\n"); + index_pulse(drive); + d86f[drive].index_count++; + } + + d86f_poll_advancebyte(drive, side); + + if (d86f_poll_check_notfound(drive)) return; + + if (d86f[drive].track_byte != d86f[drive].old_track_byte) + { + if (d86f_end_wait_state(drive)) + { + d86f[drive].calc_crc.word = 0xffff; + d86f[drive].id_am_counter = d86f[drive].id_counter = d86f[drive].id_match = d86f[drive].data_am_counter = d86f[drive].wait_state = 0; + } + } +} + void d86f_poll_find_nf(int drive, int side) { - uint8_t data = 0; + uint8_t mfm = 0; + uint8_t am_len = 0; + mfm = fdc_is_mfm(); + am_len = mfm ? 4 : 1; if (d86f[drive].track_index) { @@ -1150,35 +1651,57 @@ void d86f_poll_find_nf(int drive, int side) switch(d86f[drive].track_byte) { case BYTE_DATAAM_SYNC: - if (d86f_should_write_am(drive)) + if ((d86f[drive].id_match) || d86f_find_state_nf_ignore_id(drive)) { - d86f_poll_write(drive, side, 0xA1, BYTE_DATAAM_SYNC); + d86f[drive].data_am_counter++; + + if (mfm) + { + d86f_calccrc(drive, d86f[drive].track_data_byte); + } } + break; case BYTE_IDAM_SYNC: - if (d86f_is_mfm(drive)) + d86f[drive].id_am_counter++; + + if (mfm) { d86f_calccrc(drive, d86f[drive].track_data_byte); } break; case BYTE_DATAAM: - if (d86f_should_write_am(drive)) + if ((d86f[drive].id_match) || d86f_find_state_nf_ignore_id(drive)) { - d86f_poll_write(drive, side, 0xFB, BYTE_DATAAM); + if ((d86f[drive].state == STATE_WRITE_FIND_SECTOR) && (d86f[drive].data_am_counter == (am_len - 1))) + { + d86f_poll_write(drive, side, 0xFB, BYTE_DATAAM); + } + + d86f[drive].data_am_counter++; + d86f[drive].id_match = 0; + + d86f_calccrc(drive, d86f[drive].track_data_byte); } + break; case BYTE_IDAM: + d86f[drive].id_am_counter++; d86f_calccrc(drive, d86f[drive].track_data_byte); break; case BYTE_ID: - d86f[drive].id_pos = d86f[drive].track_pos - d86f[drive].section_pos; - d86f[drive].rw_sector_id.byte_array[d86f[drive].id_pos] = d86f[drive].track_data_byte; + d86f[drive].id_pos = d86f_get_pos(drive); + d86f[drive].last_sector.byte_array[d86f[drive].id_pos] = d86f[drive].track_data_byte; d86f_calccrc(drive, d86f[drive].track_data_byte); + if (d86f[drive].id_am_counter == am_len) + { + d86f[drive].id_counter++; + } break; case BYTE_ID_CRC: - d86f[drive].id_pos = d86f[drive].track_pos - d86f[drive].section_pos; + d86f[drive].id_pos = d86f_get_pos(drive); d86f[drive].track_crc.bytes[d86f[drive].id_pos ^ 1] = d86f[drive].track_data_byte; break; } @@ -1195,52 +1718,64 @@ void d86f_poll_find_nf(int drive, int side) { case BYTE_IDAM_SYNC: case BYTE_DATAAM_SYNC: - if (d86f_is_mfm(drive)) + if (mfm) { d86f[drive].calc_crc.word = 0xffff; } break; case BYTE_IDAM: case BYTE_DATAAM: - if (!d86f_is_mfm(drive)) + if (!mfm) { d86f[drive].calc_crc.word = 0xffff; } break; case BYTE_GAP2: - if (d86f_can_read_address(drive)) + d86f[drive].id_match = 0; + d86f[drive].data_am_counter = 0; + if (d86f[drive].id_counter != 4) { - if ((d86f[drive].req_sector.dword == d86f[drive].rw_sector_id.dword) || (d86f[drive].state == STATE_READ_FIND_ADDRESS)) + d86f[drive].id_am_counter = d86f[drive].id_counter = 0; + break; + } + d86f[drive].id_am_counter = d86f[drive].id_counter = 0; + if ((d86f[drive].req_sector.dword == d86f[drive].last_sector.dword) || (d86f[drive].state == STATE_READ_FIND_ADDRESS)) + { + if ((d86f[drive].track_crc.word != d86f[drive].calc_crc.word) && d86f_handler[drive].check_crc) { - if (d86f[drive].track_crc.word != d86f[drive].calc_crc.word) + if (d86f[drive].state != STATE_READ_FIND_ADDRESS) { - if (d86f[drive].state != STATE_READ_FIND_ADDRESS) - { - // pclog("d86f_poll(): Header CRC error (%i %i %i %i) (%04X %04X)\n", d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n, d86f[drive].track_crc.word, d86f[drive].calc_crc.word); - fdc_finishread(); - fdc_headercrcerror(); - d86f[drive].state = STATE_IDLE; - d86f[drive].index_count = 0; - return; - } + pclog("d86f_poll(): Header CRC error (mfm=%i) (%i %i %i %i) (%04X %04X)\n", d86f_is_mfm(drive), d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n, d86f[drive].track_crc.word, d86f[drive].calc_crc.word); + fdc_finishread(); + fdc_headercrcerror(); + d86f[drive].state = STATE_IDLE; + d86f[drive].index_count = 0; + return; } else { - d86f[drive].last_sector.dword = d86f[drive].rw_sector_id.dword; - d86f[drive].rw_sector_id.dword = 0xFFFFFFFF; - - // pclog("Read sector ID in find state: %i %i %i %i (sought: %i, %i, %i, %i)\n", d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n, d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n); - - if ((d86f[drive].state == STATE_READ_FIND_ADDRESS) && (d86f[drive].last_sector.dword != 0xFFFFFFFF)) - { - // pclog("Reading sector ID (%i %i %i %i)...\n", d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n); - fdc_sectorid(d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n, 0, 0); - d86f[drive].state = STATE_IDLE; - d86f[drive].index_count = 0; - } + pclog("d86f_poll(): Header CRC error at read sector ID (mfm=%i) (%i %i %i %i) (%04X %04X)\n", d86f_is_mfm(drive), d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n, d86f[drive].track_crc.word, d86f[drive].calc_crc.word); } - } - } + } + else + { + if (d86f[drive].state != STATE_READ_FIND_ADDRESS) d86f[drive].id_match = 1; + + // pclog("Read sector ID in find state: %i %i %i %i (sought: %i, %i, %i, %i)\n", d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n, d86f[drive].req_sector.id.c, d86f[drive].req_sector.id.h, d86f[drive].req_sector.id.r, d86f[drive].req_sector.id.n); + + if (d86f[drive].state == STATE_READ_FIND_ADDRESS) + { + // pclog("Reading sector ID (%i %i %i %i)...\n", d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n); + fdc_sectorid(d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n, 0, 0); + d86f[drive].state = STATE_IDLE; + d86f[drive].index_count = 0; + } + else + { + d86f_handler[drive].set_sector(drive, side, d86f[drive].last_sector.id.c, d86f[drive].last_sector.id.h, d86f[drive].last_sector.id.r, d86f[drive].last_sector.id.n); + } + } + } break; case BYTE_DATA: d86f[drive].datac = 0; @@ -1248,17 +1783,17 @@ void d86f_poll_find_nf(int drive, int side) { case STATE_READ_FIND_SECTOR: case STATE_WRITE_FIND_SECTOR: - if ((d86f[drive].req_sector.dword == d86f[drive].last_sector.dword) && d86f_can_read_address(drive)) - { - d86f[drive].state++; - } - break; case STATE_READ_FIND_FIRST_SECTOR: case STATE_READ_FIND_NEXT_SECTOR: - if (d86f_can_read_address(drive)) + /* If the data address mark counter is anything other than 0, then either the ID matches or the FDC is in the ignore sector ID mode (ie. the READ TRACK command). + Also, the bitcell period, etc. are already checked during the wait state which is designed to never end in case of a mismatch. + Therefore, ensuring the data address mark acounter is at a correct length is all we need to do. */ + if (d86f[drive].data_am_counter == am_len) { d86f[drive].state++; } + /* Data address mark counter always reset to 0. */ + d86f[drive].data_am_counter = 0; break; } break; @@ -1272,7 +1807,7 @@ void d86f_poll_find_format(int drive, int side) if (d86f[drive].track_index) { - pclog("Index hole hit, formatting track...\n"); + // pclog("Index hole hit, formatting track...\n"); d86f[drive].state = STATE_FORMAT; return; } @@ -1307,7 +1842,7 @@ void d86f_poll_format(int drive, int side) } break; case BYTE_ID_SYNC: - d86f[drive].id_pos = d86f[drive].track_pos - d86f[drive].section_pos; + d86f[drive].id_pos = d86f_get_pos(drive); if (d86f[drive].id_pos <= 3) { @@ -1316,11 +1851,18 @@ void d86f_poll_format(int drive, int side) { data = 0; } - d86f[drive].format_sector_id.byte_array[d86f[drive].id_pos] = data & 0xff; + if (d86f[drive].version != 0063) + { + d86f[drive].format_sector_id.byte_array[d86f[drive].id_pos] = data & 0xff; + } // pclog("format_sector_id[%i] = %i\n", cur_id_pos, d86f[drive].format_sector_id.byte_array[d86f[drive].id_pos]); if (d86f[drive].id_pos == 3) { fdc_stop_id_request(); + if (d86f[drive].version != 0063) + { + d86f_handler[drive].set_sector(drive, side, d86f[drive].format_sector_id.id.c, d86f[drive].format_sector_id.id.h, d86f[drive].format_sector_id.id.r, d86f[drive].format_sector_id.id.n); + } // pclog("Formatting sector: %08X...\n", d86f[drive].format_sector_id.dword); } } @@ -1354,17 +1896,29 @@ void d86f_poll_format(int drive, int side) d86f_calccrc(drive, d86f[drive].track_data_byte); break; case BYTE_ID: - d86f[drive].id_pos = d86f[drive].track_pos - d86f[drive].section_pos; - if (!disable_write) + d86f[drive].id_pos = d86f_get_pos(drive); + if (d86f[drive].version != 0063) { - d86f[drive].track_data[side][d86f[drive].track_pos] = d86f[drive].track_data_byte = d86f[drive].format_sector_id.byte_array[d86f[drive].id_pos]; + if (!disable_write) + { + d86f[drive].track_data[side][d86f[drive].track_pos] = d86f[drive].track_data_byte = d86f[drive].format_sector_id.byte_array[d86f[drive].id_pos]; + } + } + else + { + d86f[drive].format_sector_id.byte_array[d86f[drive].id_pos] = d86f[drive].track_data_byte; + if (d86f[drive].id_pos == 3) + { + d86f_handler[drive].set_sector(drive, side, d86f[drive].format_sector_id.id.c, d86f[drive].format_sector_id.id.h, d86f[drive].format_sector_id.id.r, d86f[drive].format_sector_id.id.n); + } } d86f_calccrc(drive, d86f[drive].track_data_byte); break; case BYTE_DATA: + d86f[drive].id_pos = d86f_get_pos(drive); if (!disable_write) { - d86f[drive].track_data[side][d86f[drive].track_pos] = d86f[drive].track_data_byte = d86f[drive].fill; + d86f_handler[drive].write_data(drive, side, d86f[drive].id_pos, d86f[drive].fill); } d86f_calccrc(drive, d86f[drive].track_data_byte); break; @@ -1378,9 +1932,9 @@ void d86f_poll_format(int drive, int side) if (d86f[drive].track_index) { - pclog("Index hole hit again, format finished\n"); + // pclog("Index hole hit again, format finished\n"); d86f[drive].state = STATE_IDLE; - if (!disable_write) d86f_writeback(drive); + if (!disable_write) d86f_handler[drive].writeback(drive); fdc_sector_finishread(drive); d86f[drive].index_count = 0; return; @@ -1411,7 +1965,7 @@ void d86f_poll_format(int drive, int side) // pclog("Requesting next sector ID...\n"); fdc_request_next_sector_id(); break; - case BYTE_GAP2: + case BYTE_GAP2: d86f[drive].last_sector.dword = d86f[drive].format_sector_id.dword; break; case BYTE_DATA: @@ -1423,8 +1977,11 @@ void d86f_poll_format(int drive, int side) void d86f_poll() { - int drive = d86f_drive; - int side = fdd_get_head(drive); + // int drive = d86f_drive; + int drive = 0; + int side = 0; + drive = fdc_get_drive(); + side = fdd_get_head(drive); if (d86f[drive].state == STATE_FORMAT) { @@ -1440,7 +1997,14 @@ void d86f_poll() if (d86f_find_state_nf(drive)) { - d86f_poll_find_nf(drive, side); + if (d86f[drive].wait_state) + { + d86f_poll_find_nf_wait(drive, side); + } + else + { + d86f_poll_find_nf(drive, side); + } return; } diff --git a/src/disc_img.c b/src/disc_img.c index 254229524..79cf1fb75 100644 --- a/src/disc_img.c +++ b/src/disc_img.c @@ -23,7 +23,7 @@ static struct } img[2]; static uint8_t xdf_track0[3][3]; -static uint8_t xdf_spt[3]; +static uint8_t xdf_spt[3] = { 6, 8, 8 }; static uint8_t xdf_map[3][24][3]; static uint16_t xdf_track0_layout[3][92] = { { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, 0x8101, 0x8201, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, @@ -49,6 +49,7 @@ static uint16_t xdf_track0_layout[3][92] = { { 0x8100, 0x8200, 0x8300, 0x8400, 0 0x9901, 0x9A01, 0x9B01, 0x9C01, 0x9D01, 0x9E01, 0x9F01, 0xA001, 0xA101, 0xA201, 0xA301, 0xA401 }, }; +static uint16_t xdf_sector_pos[256]; /* First dimension is possible sector sizes (0 = 128, 7 = 16384), second is possible bit rates (250/360, 250, 300, 500/360, 500, 1000). */ /* Disks formatted at 250 kbps @ 360 RPM can be read with a 360 RPM single-RPM 5.25" drive by setting the rate to 250 kbps. @@ -152,46 +153,9 @@ static void add_to_map(uint8_t *arr, uint8_t p1, uint8_t p2, uint8_t p3) static int xdf_maps_initialized = 0; -static void initialize_xdf_maps() -{ - // XDF 5.25" 2HD - /* Adds, in this order: sectors per FAT, sectors per each side of track 0, difference between that and virtual sector number specified in BPB. */ - add_to_map(xdf_track0[0], 9, 17, 2); - xdf_spt[0] = 3; - /* Adds, in this order: side, sequential order (not used in PCem), sector size. */ - add_to_map(xdf_map[0][0], 0, 0, 3); - add_to_map(xdf_map[0][1], 0, 2, 6); - add_to_map(xdf_map[0][2], 1, 0, 2); - add_to_map(xdf_map[0][3], 0, 1, 2); - add_to_map(xdf_map[0][4], 1, 2, 6); - add_to_map(xdf_map[0][5], 1, 1, 3); - - // XDF 3.5" 2HD - add_to_map(xdf_track0[1], 11, 19, 4); - xdf_spt[1] = 4; - add_to_map(xdf_map[1][0], 0, 0, 3); - add_to_map(xdf_map[1][1], 0, 2, 4); - add_to_map(xdf_map[1][2], 1, 3, 6); - add_to_map(xdf_map[1][3], 0, 1, 2); - add_to_map(xdf_map[1][4], 1, 1, 2); - add_to_map(xdf_map[1][5], 0, 3, 6); - add_to_map(xdf_map[1][6], 1, 0, 4); - add_to_map(xdf_map[1][7], 1, 2, 3); - - // XDF 3.5" 2ED - add_to_map(xdf_track0[2], 22, 37, 9); - xdf_spt[2] = 4; - add_to_map(xdf_map[2][0], 0, 0, 3); - add_to_map(xdf_map[2][1], 0, 1, 4); - add_to_map(xdf_map[2][2], 0, 2, 5); - add_to_map(xdf_map[2][3], 0, 3, 7); - add_to_map(xdf_map[2][4], 1, 0, 3); - add_to_map(xdf_map[2][5], 1, 1, 4); - add_to_map(xdf_map[2][6], 1, 2, 5); - add_to_map(xdf_map[2][7], 1, 3, 7); - - xdf_maps_initialized = 1; -} +static uint16_t xdf_trackx_layout[3][8] = { { 0x8300, 0x8600, 0x8201, 0x8200, 0x8601, 0x8301}, + { 0x8300, 0x8400, 0x8601, 0x8200, 0x8201, 0x8600, 0x8401, 0x8301}, + { 0x8300, 0x8400, 0x8500, 0x8700, 0x8301, 0x8401, 0x8501, 0x8701} }; void img_load(int drive, char *fn) { @@ -208,8 +172,6 @@ void img_load(int drive, char *fn) char ext[4]; int fdi; - if (!xdf_maps_initialized) initialize_xdf_maps(); /* Initialize XDF maps, will need them to properly register sectors in tracks. */ - ext[0] = fn[strlen(fn) - 3] | 0x60; ext[1] = fn[strlen(fn) - 2] | 0x60; ext[2] = fn[strlen(fn) - 1] | 0x60; @@ -224,6 +186,10 @@ void img_load(int drive, char *fn) return; writeprot[drive] = 1; } + if (ui_writeprot[drive]) + { + writeprot[drive] = 1; + } fwriteprot[drive] = writeprot[drive]; if (strcmp(ext, "fdi") == 0) @@ -432,7 +398,6 @@ void img_load(int drive, char *fn) { case 19: /* High density XDF @ 360 rpm */ img[drive].xdf_type = 1; - raw_tsize[drive] = 10521; /* Rotate at 356.4 RPM in order to fit the data. */ break; case 23: /* High density XDF @ 300 rpm */ img[drive].xdf_type = 2; @@ -495,12 +460,6 @@ void img_load(int drive, char *fn) img[drive].byte_period = 16; } - if (img[drive].xdf_type) /* In case of XDF-formatted image, write-protect */ - { - writeprot[drive] = 1; - fwriteprot[drive] = writeprot[drive]; - } - drives[drive].seek = img_seek; drives[drive].readsector = disc_sector_readsector; drives[drive].writesector = disc_sector_writesector; @@ -546,9 +505,7 @@ void img_seek(int drive, int track) int side; int current_xdft = img[drive].xdf_type - 1; - uint8_t sectors_fat, effective_sectors, sector_gap; /* Needed for XDF */ - - int sector, current_pos, sh, sr, sside, total; + int sector, current_pos, sh, sr, sn, sside, total, max_pos; if (!img[drive].f) return; @@ -579,14 +536,11 @@ void img_seek(int drive, int track) if (img[drive].xdf_type) { - sectors_fat = xdf_track0[current_xdft][0]; - effective_sectors = xdf_track0[current_xdft][1]; - sector_gap = xdf_track0[current_xdft][2]; - total = img[drive].sectors; - + max_pos = (img[drive].sectors * 512); if (!track) { /* Track 0, register sectors according to track 0 layout. */ + total = img[drive].sectors; current_pos = 0; for (sector = 0; sector < (total << 1); sector++) { @@ -596,6 +550,7 @@ void img_seek(int drive, int track) { sh = xdf_track0_layout[current_xdft][sector] & 0xFF; sr = xdf_track0_layout[current_xdft][sector] >> 8; + xdf_sector_pos[(sh << 8) | sr] = current_pos; disc_sector_add(drive, sh, track, sh, sr, 2, img[drive].bitcell_period_300rpm, &img[drive].track_data[sside][current_pos]); @@ -605,25 +560,19 @@ void img_seek(int drive, int track) else { /* Non-zero track, this will have sectors of various sizes. */ - /* First, the "Side 0" buffer. */ + total = xdf_spt[current_xdft] >> 1; current_pos = 0; - for (sector = 0; sector < xdf_spt[current_xdft]; sector++) + for (sector = 0; sector < xdf_spt[current_xdft]; sector++) { - disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0], - xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2], - img[drive].bitcell_period_300rpm, - &img[drive].track_data[0][current_pos]); - current_pos += (128 << xdf_map[current_xdft][sector][2]); - } - /* Then, the "Side 1" buffer. */ - current_pos = 0; - for (sector = xdf_spt[current_xdft]; sector < (xdf_spt[current_xdft] << 1); sector++) - { - disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0], - xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2], - img[drive].bitcell_period_300rpm, - &img[drive].track_data[1][current_pos]); - current_pos += (128 << xdf_map[current_xdft][sector][2]); + sside = (sector >= total) ? 1 : 0; + sh = xdf_trackx_layout[current_xdft][sector] & 0xFF; + sr = xdf_trackx_layout[current_xdft][sector] >> 8; + sn = sr & 7; + disc_sector_add(drive, sh, track, sh, sr, sn, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[sside][current_pos]); + current_pos += (128 << sn); + current_pos %= max_pos; } } } @@ -648,19 +597,19 @@ void img_writeback(int drive) if (!img[drive].f) return; - if (img[drive].xdf_type) - return; /*Should never happen*/ + // if (img[drive].xdf_type) + // return; /*Should never happen*/ if (img[drive].sides == 2) { - fseek(img[drive].f, img[drive].base + (disc_track[drive] * img[drive].sectors * img[drive].sector_size * 2), SEEK_SET); + fseek(img[drive].f, img[drive].base + (disc_track[drive] * img[drive].sectors * img[drive].sector_size * 2), SEEK_SET); fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); fwrite(img[drive].track_data[1], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); } else - { + { fseek(img[drive].f, img[drive].base + (disc_track[drive] * img[drive].sectors * img[drive].sector_size), SEEK_SET); - fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); } } diff --git a/src/disc_img_86box.c b/src/disc_img_86box.c new file mode 100644 index 000000000..c6dd73175 --- /dev/null +++ b/src/disc_img_86box.c @@ -0,0 +1,598 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#include "ibm.h" +#include "fdc.h" +#include "fdd.h" +#include "disc.h" +#include "disc_img.h" +#include "disc_sector.h" + +static struct +{ + FILE *f; + uint8_t track_data[2][50000]; + int sectors, tracks, sides; + uint8_t sector_size; + int rate; + int xdf_type; /* 0 = not XDF, 1-5 = one of the five XDF types */ + int dmf; + int hole; + int track; + uint32_t base; + uint8_t gap2_size; + uint8_t gap3_size; + uint8_t disk_flags; + uint8_t track_flags; + uint8_t sector_pos_side[2][256]; + uint16_t sector_pos[2][256]; + uint8_t current_sector_pos_side; + uint16_t current_sector_pos; +} img[2]; + +static uint8_t dmf_r[21] = { 12, 2, 13, 3, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 19, 9, 20, 10, 21, 11, 1 }; +static uint8_t xdf_spt[2] = { 6, 8 }; +static uint8_t xdf_logical_sectors[2][2] = { { 38, 6 }, { 46, 8 } }; +static uint8_t xdf_physical_sectors[2][2] = { { 16, 3 }, { 19, 4 } }; +static uint8_t xdf_gap3_sizes[2][2] = { { 60, 69 }, { 60, 50 } }; +static uint16_t xdf_trackx_spos[2][8] = { { 0xA7F, 0xF02, 0x11B7, 0xB66, 0xE1B, 0x129E }, { 0x302, 0x7E2, 0xA52, 0x12DA, 0x572, 0xDFA, 0x106A, 0x154A } }; + +typedef struct +{ + uint8_t h; + uint8_t r; +} xdf_id_t; + +typedef union +{ + uint16_t word; + xdf_id_t id; +} xdf_sector_t; + +/* XDF: Layout of the sectors in the image. */ +xdf_sector_t xdf_img_layout[2][2][46] = { { { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, + 0x8101, 0x8201, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, + 0x0700, 0x0800, 0, + 0x8301, 0x8401, 0x8501, 0x8601, 0x8701, 0x8801, 0x8901, 0x8A01, + 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0x9001, 0, 0, + 0, 0, 0 }, + { 0x8300, 0x8600, 0x8201, 0x8200, 0x8601, 0x8301 } + }, /* 5.25" 2HD */ + { { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, + 0x8900, 0x8A00, 0x8B00, 0x8101, 0x0100, 0x0200, 0x0300, 0x0400, + 0x0500, 0x0600, 0x0700, 0x0800, 0, 0, 0, + 0x8201, 0x8301, 0x8401, 0x8501, 0x8601, 0x8701, 0x8801, 0x8901, + 0x8A01, 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0, 0, + 0, 0, 0, 0x9001, 0x9101, 0x9201, 0x9301 }, + { 0x8300, 0x8400, 0x8601, 0x8200, 0x8201, 0x8600, 0x8401, 0x8301 } + } /* 3.5" 2HD */ + }; + +/* XDF: Layout of the sectors on the disk's track. */ +xdf_sector_t xdf_disk_layout[2][2][38] = { { { 0x0100, 0x0200, 0x8100, 0x8800, 0x8200, 0x0300, 0x8300, 0x0400, + 0x8400, 0x0500, 0x8500, 0x0600, 0x8600, 0x0700, 0x8700, 0x0800, + 0x8D01, 0x8501, 0x8E01, 0x8601, 0x8F01, 0x8701, 0x9001, 0x8801, + 0x8101, 0x8901, 0x8201, 0x8A01, 0x8301, 0x8B01, 0x8401, 0x8C01 }, + { 0x8300, 0x8200, 0x8600, 0x8201, 0x8301, 0x8601 } + }, /* 5.25" 2HD */ + { { 0x0100, 0x8A00, 0x8100, 0x8B00, 0x8200, 0x0200, 0x8300, 0x0300, + 0x8400, 0x0400, 0x8500, 0x0500, 0x8600, 0x0600, 0x8700, 0x0700, + 0x8800, 0x0800, 0x8900, + 0x9001, 0x8701, 0x9101, 0x8801, 0x9201, 0x8901, 0x9301, 0x8A01, + 0x8101, 0x8B01, 0x8201, 0x8C01, 0x8301, 0x8D01, 0x8401, 0x8E01, + 0x8501, 0x8F01, 0x8601 }, + { 0x8300, 0x8200, 0x8400, 0x8600, 0x8401, 0x8201, 0x8301, 0x8601 }, + }, /* 3.5" 2HD */ + }; + +/* First dimension is possible sector sizes (0 = 128, 7 = 16384), second is possible bit rates (250/360, 250, 300, 500/360, 500, 1000). */ +/* Disks formatted at 250 kbps @ 360 RPM can be read with a 360 RPM single-RPM 5.25" drive by setting the rate to 250 kbps. + Disks formatted at 300 kbps @ 300 RPM can be read with any 300 RPM single-RPM drive by setting the rate rate to 300 kbps. */ +static uint8_t maximum_sectors[8][6] = { { 26, 31, 38, 53, 64, 118 }, /* 128 */ + { 15, 19, 23, 32, 38, 73 }, /* 256 */ + { 7, 10, 12, 17, 21, 41 }, /* 512 */ + { 3, 5, 6, 9, 11, 22 }, /* 1024 */ + { 2, 2, 3, 4, 5, 11 }, /* 2048 */ + { 1, 1, 1, 2, 2, 5 }, /* 4096 */ + { 0, 0, 0, 1, 1, 3 }, /* 8192 */ + { 0, 0, 0, 0, 0, 1 } }; /* 16384 */ + +static uint8_t xdf_sectors[8][6] = { { 0, 0, 0, 0, 0, 0 }, /* 128 */ + { 0, 0, 0, 0, 0, 0 }, /* 256 */ + { 0, 0, 0, 19, 23, 0 }, /* 512 */ + { 0, 0, 0, 0, 0, 0 }, /* 1024 */ + { 0, 0, 0, 0, 0, 0 }, /* 2048 */ + { 0, 0, 0, 0, 0, 0 }, /* 4096 */ + { 0, 0, 0, 0, 0, 0 }, /* 8192 */ + { 0, 0, 0, 0, 0, 0 } }; /* 16384 */ + +static uint8_t xdf_types[8][6] = { { 0, 0, 0, 0, 0, 0 }, /* 128 */ + { 0, 0, 0, 0, 0, 0 }, /* 256 */ + { 0, 0, 0, 1, 2, 0 }, /* 512 */ + { 0, 0, 0, 0, 0, 0 }, /* 1024 */ + { 0, 0, 0, 0, 0, 0 }, /* 2048 */ + { 0, 0, 0, 0, 0, 0 }, /* 4096 */ + { 0, 0, 0, 0, 0, 0 }, /* 8192 */ + { 0, 0, 0, 0, 0, 0 } }; /* 16384 */ + +static double bit_rates_300[6] = { (250.0 * 300.0) / 360.0, 250.0, 300.0, (500.0 * 300.0) / 360.0, 500.0, 1000.0 }; + +static uint8_t rates[6] = { 2, 2, 1, 4, 0, 3 }; + +static uint8_t holes[6] = { 0, 0, 0, 1, 1, 2 }; + +static int gap3_sizes[5][8][256] = { [0][1][16] = 0x54, + [0][2][18] = 0x6C, + [0][2][19] = 0x48, + [0][2][20] = 0x2A, + // [0][2][21] = 0x0C, + [0][2][21] = 0x08, /* Microsoft DMFWRITE.EXE uses this, 0x0C is used by FDFORMAT. */ + // [0][2][23] = 0x7A, + [0][2][23] = 0x01, + // [0][2][24] = 0x38, + [2][1][10] = 0x32, + [2][1][11] = 0x0C, + [2][1][15] = 0x36, + [2][1][16] = 0x32, + [2][2][8] = 0x58, + [2][2][9] = 0x50, + [2][2][10] = 0x2E, + [2][2][11] = 0x02, + [2][2][21] = 0x1C, + [2][3][4] = 0xF0, + [2][3][5] = 0x74, + [3][2][36] = 0x53, + [3][2][39] = 0x20, + // [3][2][46] = 0x0E, + [3][2][46] = 0x01, + // [3][2][48] = 0x51, + [4][1][32] = 0x36, + [4][2][15] = 0x54, + [4][2][17] = 0x23, + // [4][2][19] = 0x29, + [4][2][19] = 0x01, + [4][3][8] = 0x74, + [4][3][9] = 0x74, + [4][3][10] = 0x74 +}; + +/* Needed for formatting! */ +int img_realtrack(int drive, int track) +{ + if ((img[drive].tracks <= 43) && fdd_doublestep_40(drive)) + track /= 2; + + return track; +} + +void img_writeback(int drive); + +static int sector_size_code(int sector_size) +{ + switch(sector_size) + { + case 128: + return 0; + case 256: + return 1; + default: + case 512: + return 2; + case 1024: + return 3; + case 2048: + return 4; + case 4096: + return 5; + case 8192: + return 6; + case 16384: + return 7; + } +} + +static int img_sector_size_code(int drive) +{ + return sector_size_code(img[drive].sector_size); +} + +void img_init() +{ + memset(img, 0, sizeof(img)); +// adl[0] = adl[1] = 0; +} + +void d86f_register_img(int drive); + +void img_load(int drive, char *fn) +{ + int size; + double bit_rate_300; + uint16_t bpb_bps; + uint16_t bpb_total; + uint8_t bpb_mid; /* Media type ID. */ + uint8_t bpb_sectors; + uint8_t bpb_sides; + uint32_t bpt; + uint8_t max_spt; /* Used for XDF detection. */ + int temp_rate; + char ext[4]; + int fdi; + int i; + + ext[0] = fn[strlen(fn) - 3] | 0x60; + ext[1] = fn[strlen(fn) - 2] | 0x60; + ext[2] = fn[strlen(fn) - 1] | 0x60; + ext[3] = 0; + + writeprot[drive] = 0; + img[drive].f = fopen(fn, "rb+"); + if (!img[drive].f) + { + img[drive].f = fopen(fn, "rb"); + if (!img[drive].f) + return; + writeprot[drive] = 1; + } + if (ui_writeprot[drive]) + { + writeprot[drive] = 1; + } + fwriteprot[drive] = writeprot[drive]; + + d86f_unregister(drive); + + if (strcmp(ext, "fdi") == 0) + { + /* This is a Japanese FDI image, so let's read the header */ + pclog("img_load(): File is a Japanese FDI image...\n"); + fseek(img[drive].f, 0x10, SEEK_SET); + fread(&bpb_bps, 1, 2, img[drive].f); + fseek(img[drive].f, 0x0C, SEEK_SET); + fread(&size, 1, 4, img[drive].f); + bpb_total = size / bpb_bps; + fseek(img[drive].f, 0x08, SEEK_SET); + fread(&(img[drive].base), 1, 4, img[drive].f); + fseek(img[drive].f, img[drive].base + 0x15, SEEK_SET); + bpb_mid = fgetc(img[drive].f); + if (bpb_mid < 0xF0) bpb_mid = 0xF0; + fseek(img[drive].f, 0x14, SEEK_SET); + bpb_sectors = fgetc(img[drive].f); + fseek(img[drive].f, 0x18, SEEK_SET); + bpb_sides = fgetc(img[drive].f); + + fdi = 1; + } + else + { + /* Read the BPB */ + pclog("img_load(): File is a raw image...\n"); + fseek(img[drive].f, 0x0B, SEEK_SET); + fread(&bpb_bps, 1, 2, img[drive].f); + fseek(img[drive].f, 0x13, SEEK_SET); + fread(&bpb_total, 1, 2, img[drive].f); + fseek(img[drive].f, 0x15, SEEK_SET); + bpb_mid = fgetc(img[drive].f); + fseek(img[drive].f, 0x18, SEEK_SET); + bpb_sectors = fgetc(img[drive].f); + fseek(img[drive].f, 0x1A, SEEK_SET); + bpb_sides = fgetc(img[drive].f); + + img[drive].base = 0; + fdi = 0; + + fseek(img[drive].f, -1, SEEK_END); + size = ftell(img[drive].f) + 1; + } + + img[drive].sides = 2; + img[drive].sector_size = 2; + + img[drive].hole = 0; + + pclog("BPB reports %i sides and %i bytes per sector\n", bpb_sides, bpb_bps); + + if (((bpb_sides < 1) || (bpb_sides > 2) || (bpb_bps < 128) || (bpb_bps > 2048)) && !fdi) + { + /* The BPB is giving us a wacky number of sides and/or bytes per sector, therefore it is most probably + not a BPB at all, so we have to guess the parameters from file size. */ + + if (size <= (160*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; img[drive].sides = 1; } + else if (size <= (180*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; img[drive].sides = 1; } + else if (size <= (320*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; } + else if (size <= (360*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; } /*Double density*/ + else if (size <= (640*1024)) { img[drive].sectors = 8; img[drive].tracks = 80; } /*Double density 640k*/ + else if (size < (1024*1024)) { img[drive].sectors = 9; img[drive].tracks = 80; } /*Double density*/ + else if (size <= 1228800) { img[drive].sectors = 15; img[drive].tracks = 80; } /*High density 1.2MB*/ + else if (size <= 1261568) { img[drive].sectors = 8; img[drive].tracks = 77; img[drive].sector_size = 3; } /*High density 1.25MB Japanese format*/ + else if (size <= (0x1A4000-1)) { img[drive].sectors = 18; img[drive].tracks = 80; } /*High density (not supported by Tandy 1000)*/ + else if (size <= 1556480) { img[drive].sectors = 19; img[drive].tracks = 80; } /*High density (not supported by Tandy 1000)*/ + else if (size <= 1638400) { img[drive].sectors = 10; img[drive].tracks = 80; img[drive].sector_size = 3; } /*High density (not supported by Tandy 1000)*/ + else if (size == 1884160) { img[drive].sectors = 23; img[drive].tracks = 80; } /*XDF format - used by OS/2 Warp*/ + else if (size <= 2000000) { img[drive].sectors = 21; img[drive].tracks = 80; } /*DMF format - used by Windows 95 - changed by OBattler to 2000000, ie. the real unformatted capacity @ 500 kbps and 300 rpm */ + else if (size <= 2949120) { img[drive].sectors = 36; img[drive].tracks = 80; } /*E density*/ + else if (size <= 3358720) { img[drive].sectors = 41; img[drive].tracks = 80; } /*E density, maximum possible size*/ + else + { + pclog("Image is bigger than can fit on an ED floppy, ejecting...\n"); + fclose(img[drive].f); + return; + } + } + else + { + /* The BPB readings appear to be valid, so let's set the values. */ + if (fdi) + { + /* The image is a Japanese FDI, therefore we read the number of tracks from the header. */ + fseek(img[drive].f, 0x1C, SEEK_SET); + fread(&(img[drive].tracks), 1, 4, img[drive].f); + } + else + { + /* Number of tracks = number of total sectors divided by sides times sectors per track. */ + img[drive].tracks = ((uint32_t) bpb_total) / (((uint32_t) bpb_sides) * ((uint32_t) bpb_sectors)); + } + /* The rest we just set directly from the BPB. */ + img[drive].sectors = bpb_sectors; + img[drive].sides = bpb_sides; + /* The sector size. */ + img[drive].sector_size = sector_size_code(bpb_bps); + + temp_rate = 0xFF; + } + + for (i = 0; i < 6; i++) + { + if ((img[drive].sectors <= maximum_sectors[img[drive].sector_size][i]) || (img[drive].sectors == xdf_sectors[img[drive].sector_size][i])) + { + bit_rate_300 = bit_rates_300[i]; + temp_rate = rates[i]; + img[drive].disk_flags = holes[i] << 1; + img[drive].xdf_type = (img[drive].sectors == xdf_sectors[img[drive].sector_size][i]) ? xdf_types[img[drive].sector_size][i] : 0; + if ((bit_rate_300 == 500.0) && (img[drive].sectors == 21) && (img[drive].sector_size == 2) && (img[drive].tracks == 80) && (img[drive].sides == 2)) + { + /* This is a DMF floppy, set the flag so we know to interleave the sectors. */ + img[drive].dmf = 1; + } + else + { + img[drive].dmf = 0; + } + + pclog("Image parameters: bit rate 300: %f, temporary rate: %i, hole: %i, XDF type: %i\n", bit_rate_300, temp_rate, img[drive].disk_flags >> 1, img[drive].xdf_type); + break; + } + } + + if (temp_rate == 0xFF) + { + pclog("Image is bigger than can fit on an ED floppy, ejecting...\n"); + fclose(img[drive].f); + return; + } + + img[drive].gap2_size = (temp_rate == 3) ? 41 : 22; + if (img[drive].dmf) + { + img[drive].gap3_size = 8; + } + else + { + img[drive].gap3_size = gap3_sizes[temp_rate][img[drive].sector_size][img[drive].sectors]; + } + if (!img[drive].gap3_size) + { + pclog("ERROR: Floppy image of unknown format was inserted into drive %c:!\n", drive + 0x41); + fclose(img[drive].f); + return; + } + + if (img[drive].tracks > 43) img[drive].disk_flags |= 1; /* If the image has more than 43 tracks, then the tracks are thin (96 tpi). */ + if (img[drive].sides == 2) img[drive].disk_flags |= 8; /* If the has 2 sides, mark it as such. */ + + img[drive].track_flags = 0x08; /* IMG files are always assumed to be MFM-encoded. */ + img[drive].track_flags |= temp_rate & 3; /* Data rate. */ + if (temp_rate & 4) img[drive].track_flags |= 0x20; /* RPM. */ + + pclog("Disk flags: %i, track flags: %i\n", img[drive].disk_flags, img[drive].track_flags); + + d86f_register_img(drive); + + drives[drive].seek = img_seek; + + d86f_common_handlers(drive); +} + +void img_close(int drive) +{ + if (img[drive].f) + fclose(img[drive].f); + img[drive].f = NULL; +} + +#define xdf_img_sector xdf_img_layout[current_xdft][!is_t0][sector] +#define xdf_disk_sector xdf_disk_layout[current_xdft][!is_t0][array_sector] + +void img_seek(int drive, int track) +{ + int side; + int current_xdft = img[drive].xdf_type - 1; + + uint8_t id[4] = { 0, 0, 0, 0 }; + + int is_t0, sector, current_pos, img_pos, sh, sr, sn, sside, total, max_pos, bytes, array_sector, buf_side, buf_pos; + + int ssize = 128 << ((int) img[drive].sector_size); + + if (!img[drive].f) + return; + + if (d86f_is_40_track(drive) && fdd_doublestep_40(drive)) + track /= 2; + + img[drive].track = track; + + is_t0 = (track == 0) ? 1 : 0; + + fseek(img[drive].f, img[drive].base + (track * img[drive].sectors * ssize * img[drive].sides), SEEK_SET); + for (side = 0; side < img[drive].sides; side++) + { + fread(img[drive].track_data[side], img[drive].sectors * ssize, 1, img[drive].f); + } + + if (!img[drive].xdf_type) + { + for (side = 0; side < img[drive].sides; side++) + { + current_pos = d86f_prepare_pretrack(drive, side, 0, 1); + + for (sector = 0; sector < img[drive].sectors; sector++) + { + sr = img[drive].dmf ? (dmf_r[sector]) : (sector + 1); + id[0] = track; + id[1] = side; + id[2] = sr; + id[3] = img[drive].sector_size; + img[drive].sector_pos_side[side][sr] = side; + img[drive].sector_pos[side][sr] = (sr - 1) * ssize; + // if (img[drive].dmf) pclog("DMF: %i %i %i %i | %i %04X\n", id[0], id[1], id[2], id[3], side, (sr - 1) * ssize); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, &img[drive].track_data[side][(sr - 1) * ssize], ssize, 1, img[drive].gap2_size, img[drive].gap3_size); + } + } + } + else + { + total = img[drive].sectors; + img_pos = 0; + sside = 0; + + /* Pass 1, get sector positions in the image. */ + for (sector = 0; sector < xdf_logical_sectors[current_xdft][!is_t0]; sector++) + { + if (is_t0) + { + img_pos = (sector % total) << 9; + sside = (sector >= total) ? 1 : 0; + } + + if (xdf_img_sector.word) + { + img[drive].sector_pos_side[xdf_img_sector.id.h][xdf_img_sector.id.r] = sside; + img[drive].sector_pos[xdf_img_sector.id.h][xdf_img_sector.id.r] = img_pos; + // pclog("Side: %i, Position: %04X\n", sside, img_pos); + } + + if (!is_t0) + { + img_pos += (128 << (xdf_img_sector.id.r & 7)); + if (img_pos >= (total << 9)) sside = 1; + img_pos %= (total << 9); + } + } + + /* Pass 2, prepare the actual track. */ + for (side = 0; side < img[drive].sides; side++) + { + current_pos = d86f_prepare_pretrack(drive, side, 0, 1); + + for (sector = 0; sector < xdf_physical_sectors[current_xdft][!is_t0]; sector++) + { + array_sector = (side * xdf_physical_sectors[current_xdft][!is_t0]) + sector; + // pclog("Sector %i, array sector %i\n", sector, array_sector); + + buf_side = img[drive].sector_pos_side[xdf_disk_sector.id.h][xdf_disk_sector.id.r]; + buf_pos = img[drive].sector_pos[xdf_disk_sector.id.h][xdf_disk_sector.id.r]; + + // pclog("Side: %i, Position: %04X\n", buf_side, buf_pos); + + id[0] = track; + id[1] = xdf_disk_sector.id.h; + id[2] = xdf_disk_sector.id.r; + + if (is_t0) + { + id[3] = 2; + // pclog("XDF Track 0: Registering sector: %i %i %i %i\n", id[0], id[1], id[2], id[3]); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, &img[drive].track_data[buf_side][buf_pos], ssize, 1, img[drive].gap2_size, xdf_gap3_sizes[current_xdft][!is_t0]); + } + else + { + id[3] = id[2] & 7; + // pclog("XDF Track X: Registering sector: %i %i %i %i\n", id[0], id[1], id[2], id[3]); + ssize = (128 << id[3]); + current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[current_xdft][array_sector], id, &img[drive].track_data[buf_side][buf_pos], ssize, 1, img[drive].gap2_size, xdf_gap3_sizes[current_xdft][!is_t0]); + } + } + } + } + + // pclog("Seeked to track: %i\n", img[drive].track); +} + +void img_writeback(int drive) +{ + int side; + int ssize = 128 << ((int) img[drive].sector_size); + + if (!img[drive].f) + return; + + fseek(img[drive].f, img[drive].base + (img[drive].track * img[drive].sectors * ssize * img[drive].sides), SEEK_SET); + for (side = 0; side < img[drive].sides; side++) + { + fwrite(img[drive].track_data[side], img[drive].sectors * ssize, 1, img[drive].f); + } +} + +int img_xdf_type(int drive) +{ + return img[drive].xdf_type; +} + +uint8_t img_disk_flags(int drive) +{ + return img[drive].disk_flags; +} + +uint8_t img_side_flags(int drive) +{ + return img[drive].track_flags; +} + +void img_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + img[drive].current_sector_pos_side = img[drive].sector_pos_side[h][r]; + img[drive].current_sector_pos = img[drive].sector_pos[h][r]; + return; +} + +uint8_t img_poll_read_data(int drive, int side, uint16_t pos) +{ + return img[drive].track_data[img[drive].current_sector_pos_side][img[drive].current_sector_pos + pos]; +} + +void img_poll_write_data(int drive, int side, uint16_t pos, uint8_t data) +{ + img[drive].track_data[img[drive].current_sector_pos_side][img[drive].current_sector_pos + pos] = data; +} + +int img_format_conditions(int drive) +{ + int temp = (fdc_get_format_sectors() == img[drive].sectors); + temp = temp && (fdc_get_format_n() == img[drive].sector_size); + temp = temp && (img[drive].xdf_type == 0); + return temp; +} + +void d86f_register_img(int drive) +{ + d86f_handler[drive].disk_flags = img_disk_flags; + d86f_handler[drive].side_flags = img_side_flags; + d86f_handler[drive].writeback = img_writeback; + d86f_handler[drive].set_sector = img_set_sector; + d86f_handler[drive].read_data = img_poll_read_data; + d86f_handler[drive].write_data = img_poll_write_data; + d86f_handler[drive].format_conditions = img_format_conditions; + d86f_handler[drive].check_crc = 1; +} diff --git a/src/disc_sector_86box.c b/src/disc_sector_86box.c index 2d5a2979c..a6b45598c 100644 --- a/src/disc_sector_86box.c +++ b/src/disc_sector_86box.c @@ -101,6 +101,7 @@ static int get_bitcell_period(int drive) void disc_sector_readsector(int drive, int sector, int track, int side, int rate, int sector_size) { // pclog("disc_sector_readsector: fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate, sector, track, side); + // pclog("disc_sector_readsector: fdc_period=%i img_period=%i rate=%i c=%i h=%i r=%i n=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate, track, side, sector, sector_size); disc_sector_track[drive] = track; disc_sector_side[drive] = side; @@ -120,6 +121,12 @@ void disc_sector_writesector(int drive, int sector, int track, int side, int rat { // pclog("disc_sector_writesector: fdc_period=%i img_period=%i rate=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate); + if (writeprot[drive] || swwp) + { + fdc_writeprotect(); + return; + } + disc_sector_track[drive] = track; disc_sector_side[drive] = side; disc_sector_drive = drive; @@ -171,8 +178,6 @@ int media_type = 0; #define GAP3_LEN_VARIABLE 0x1B -int gap3_sizes[3][2] = { {74, 36}, {77, 77}, {60, 60} }; - int disc_sector_get_gap3_size(int drive, int side, int track) { if (!img_xdf_type(drive)) @@ -183,7 +188,7 @@ int disc_sector_get_gap3_size(int drive, int side, int track) switch (track) { case 0: - return gap3_sizes[img_xdf_type(drive) - 1][side]; + return 60; default: return GAP3_LEN_VARIABLE; } @@ -333,6 +338,7 @@ int disc_sector_can_format(int drive) temp = temp && !swwp; temp = temp && disc_sector_can_read_address(drive); temp = temp && (fdc_get_format_sectors() == disc_sector_count[drive][disc_sector_side[drive]]); + temp = temp && (!img_xdf_type(drive)); return temp; } diff --git a/src/dma.c b/src/dma.c index 358d226d5..278d528a8 100644 --- a/src/dma.c +++ b/src/dma.c @@ -246,12 +246,23 @@ uint8_t _dma_read(uint32_t addr) return mem_readb_phys(addr); } +uint16_t _dma_readw(uint32_t addr) +{ + return mem_readw_phys(addr); +} + void _dma_write(uint32_t addr, uint8_t val) { mem_writeb_phys(addr, val); mem_invalidate_range(addr, addr); } +void _dma_writew(uint32_t addr, uint16_t val) +{ + mem_writew_phys(addr, val); + mem_invalidate_range(addr, addr + 1); +} + int dma_channel_read(int channel) { uint16_t temp; @@ -300,8 +311,12 @@ int dma_channel_read(int channel) if ((dma16.mode[channel] & 0xC) != 8) return DMA_NODATA; +#if 0 temp = _dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16)) | (_dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1) << 8); +#endif + + temp = _dma_readw((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16)); if (dma16.mode[channel] & 0x20) dma16.ac[channel]--; else dma16.ac[channel]++; @@ -325,6 +340,18 @@ int dma_channel_read(int channel) } } +void dma_channel_dump() +{ + int i = 0; + FILE *f; + f = fopen("dma.dmp", "wb"); + for (i = 0; i < (21 * 512); i++) + { + fputc(mem_readb_phys((dma.page[2] << 16) + dma16.ac[2] + i), f); + } + fclose(f); +} + int dma_channel_write(int channel, uint16_t val) { if (dma.command & 0x04) @@ -368,8 +395,12 @@ int dma_channel_write(int channel, uint16_t val) if ((dma16.mode[channel] & 0xC) != 4) return DMA_NODATA; +#if 0 _dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16), val); _dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1, val >> 8); +#endif + + _dma_writew((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16), val); if (dma16.mode[channel]&0x20) dma16.ac[channel]--; else dma16.ac[channel]++; diff --git a/src/fdc.c b/src/fdc.c index 029e04cf7..ce8ac6052 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -14,6 +14,8 @@ extern int64_t motoron; +int ui_writeprot[2] = {0, 0}; + static int fdc_reset_stat = 0; /*FDC*/ typedef struct FDC @@ -66,12 +68,11 @@ typedef struct FDC int drv2en; uint8_t fifobuf[16]; - int seek_params; /* Needed for relative seek. */ - int gap, dtl; int format_sectors; int max_track; + int mfm; } FDC; static FDC fdc; @@ -102,13 +103,39 @@ void fdc_reset() // pclog("Reset FDC\n"); } +int fdc_get_drive() +{ + return fdc.drive; +} + int fdc_get_bitcell_period(); int fdc_get_perp() { + if (!AT || fdc.pcjr || fdc.ps1) return 0; + return fdc.perp; } +int fdc_get_bit_rate(); + +int fdc_get_gap2(int drive) +{ + int auto_gap2 = 22; + + if (!AT || fdc.pcjr || fdc.ps1) return 22; + + if (fdc.perp & 3) + { + return ((fdc.perp & 3) == 3) ? 41 : 22; + } + else + { + auto_gap2 = (fdc_get_bit_rate() >= 3) ? 41 : 22; + return (fdc.perp & (4 << drive)) ? auto_gap2 : 22; + } +} + int fdc_get_format_n() { return fdc.format_n; @@ -116,7 +143,7 @@ int fdc_get_format_n() int fdc_is_mfm() { - return (fdc.command & 0x40) ? 1 : 0; + return fdc.mfm ? 1 : 0; } double fdc_get_hut() @@ -371,7 +398,7 @@ void fdc_update_rate(int drive) } fdc.bitcell_period = 1000000 / bit_rate*2; /*Bitcell period in ns*/ - pclog("fdc_update_rate: rate=%i bit_rate=%i bitcell_period=%i\n", fdc.rate, bit_rate, fdc.bitcell_period); + // pclog("fdc_update_rate: rate=%i bit_rate=%i bitcell_period=%i\n", fdc.rate, bit_rate, fdc.bitcell_period); } int fdc_get_bit_rate() @@ -506,15 +533,18 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) disctime = 128 * (1 << TIMER_SHIFT); timer_update_outstanding(); discint=-1; + fdc.perp &= 0xfc; fdc_reset(); } timer_process(); motoron = (val & 0xf0) ? 1 : 0; timer_update_outstanding(); fdc.drive = val & 3; + disc_drivesel = fdc.drive & 1; + disc_set_drivesel(fdc.drive & 1); } fdc.dor=val; -// printf("DOR now %02X\n",val); + // printf("DOR now %02X\n",val); return; case 3: /* TDR */ @@ -531,6 +561,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) disctime = 128 * (1 << TIMER_SHIFT); timer_update_outstanding(); discint=-1; + fdc.perp &= 0xfc; fdc_reset(); } return; @@ -575,6 +606,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.ptot=8; fdc.stat=0x90; fdc.pos=0; + fdc.mfm=(fdc.command&0x40)?1:0; break; case 3: /*Specify*/ fdc.pnum=0; @@ -592,6 +624,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.ptot=8; fdc.stat=0x90; fdc.pos=0; + fdc.mfm=(fdc.command&0x40)?1:0; // readflash=1; break; case 6: /*Read data*/ @@ -599,6 +632,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.ptot=8; fdc.stat=0x90; fdc.pos=0; + fdc.mfm=(fdc.command&0x40)?1:0; break; case 7: /*Recalibrate*/ fdc.pnum=0; @@ -619,6 +653,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.ptot=1; fdc.stat=0x90; fdc.pos=0; + fdc.mfm=(fdc.command&0x40)?1:0; break; case 0x0d: /*Format track*/ fdc.pnum=0; @@ -626,6 +661,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.stat=0x90; fdc.pos=0; fdc.format_state = 0; + fdc.mfm=(fdc.command&0x40)?1:0; break; case 15: /*Seek*/ fdc.pnum=0; @@ -645,6 +681,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_callback(); break; case 0x12: /*Set perpendicular mode*/ + if (!AT || fdc.pcjr || fdc.ps1) goto bad_command; fdc.pnum=0; fdc.ptot=1; fdc.stat=0x90; @@ -739,8 +776,16 @@ bad_command: case 0x12: fdc.stat=0x80; - fdc.perp = fdc.params[0]; - pclog("PERPENDICULAR: Set to: %02X\n", fdc.perp); + if (fdc.params[0] & 0x80) + { + fdc.perp = fdc.params[0] & 0x3f; + } + else + { + fdc.perp &= 0xfc; + fdc.perp |= (fdc.params[0] & 0x03); + } + // pclog("PERPENDICULAR: Set to: %02X\n", fdc.perp); disctime = 0; return; @@ -822,7 +867,7 @@ bad_command: fdc.gap = fdc.params[3]; fdc.dtl = 4000000; fdc.format_sectors = fdc.params[2]; - pclog("Formatting with %i sectors per track\n", fdc.format_sectors); + // pclog("Formatting with %i sectors per track\n", fdc.format_sectors); fdc.format_n = fdc.params[1]; fdc.format_state = 1; fdc.pos = 0; @@ -834,9 +879,9 @@ bad_command: fdc.head = (fdc.params[0] & 4) ? 1 : 0; fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); disctime = 0; - if (fdc.seek_params & 0x80) + if (fdc.command & 0x80) { - if (fdc.seek_params & 0x40) + if (fdc.command & 0x40) { /* Relative seek inwards. */ fdc_seek(fdc.drive, fdc.params[1]); @@ -846,12 +891,13 @@ bad_command: /* Relative seek outwards. */ fdc_seek(fdc.drive, -fdc.params[1]); } + disctime = ((int) fdc.params[1]) * 10 * TIMER_USEC; } else { fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + disctime = ((int) (fdc.params[1] - fdc.track[fdc.drive])) * 10 * TIMER_USEC; } - disctime = 790 * TIMER_USEC; fdc.st0 &= 0x30; break; @@ -1130,7 +1176,7 @@ void fdc_callback() case 7: /*Recalibrate*/ fdc.track[fdc.drive]=0; // if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0; - if (fdc.drive <= 1) + if (fdc.params[0] <= 1) fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdd_get_head(fdc.drive ^ fdd_swap)?4:0); else fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdd_get_head(fdc.drive ^ fdd_swap)?4:0); @@ -1147,9 +1193,15 @@ void fdc_callback() fdc.stat = (fdc.stat & 0xf) | 0xd0; if (fdc_reset_stat) + { + disc_stop(4 - fdc_reset_stat); fdc.res[9] = 0xc0 | (4 - fdc_reset_stat) | (fdd_get_head(fdc.drive ^ fdd_swap) ? 4 : 0); + } else + { + disc_stop(fdc.drive); fdc.res[9] = fdc.st0; + } fdc.res[10] = fdc.track[fdc.drive]; if (!fdc_reset_stat) fdc.st0 = 0x80; @@ -1198,7 +1250,7 @@ void fdc_callback() fdc.track[fdc.drive]=fdc.params[1]; // if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0; // printf("Seeked to track %i %i\n",fdc.track[fdc.drive], fdc.drive); - if (fdc.drive <= 1) + if (fdc.params[0] <= 1) fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdd_get_head(fdc.drive ^ fdd_swap)?4:0); else fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdd_get_head(fdc.drive ^ fdd_swap)?4:0); @@ -1232,16 +1284,6 @@ void fdc_callback() disctime = 0; return; -#if 0 - case 0x12: - fdc.perp = fdc.params[0]; - pclog("PERPENDICULAR: Set to: %02X\n", fdc.perp); - fdc.stat = 0x80; - disctime = 0; -// picint(0x40); - return; -#endif - case 0x13: /*Configure*/ fdc.config = fdc.params[1]; fdc.pretrk = fdc.params[2]; @@ -1550,6 +1592,7 @@ void fdc_add() fdc.pcjr = 0; fdc.ps1 = 0; fdc.max_track = 79; + fdc.perp = 0; } void fdc_add_for_superio() @@ -1567,6 +1610,7 @@ void fdc_add_pcjr() fdc.pcjr = 1; fdc.ps1 = 0; fdc.max_track = 79; + fdc.perp = 0; } void fdc_remove() diff --git a/src/fdc.h b/src/fdc.h index 6424ea315..be0af77ea 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -31,6 +31,7 @@ void fdc_update_densel_force(int densel_force); void fdc_update_drvrate(int drive, int drvrate); void fdc_update_drv2en(int drv2en); +int fdc_get_drive(); int fdc_get_perp(); int fdc_get_format_n(); int fdc_is_mfm(); @@ -39,6 +40,7 @@ double fdc_get_hlt(); void fdc_request_next_sector_id(); void fdc_stop_id_request(); int fdc_get_gap(); +int fdc_get_gap2(int drive); int fdc_get_dtl(); int fdc_get_format_sectors(); diff --git a/src/ibm.h b/src/ibm.h index 83671ee3f..62613f602 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -167,6 +167,8 @@ struct uint16_t MM_w4[8]; MMX_REG MM[8]; + + uint16_t old_npxc, new_npxc; } cpu_state; #define cycles cpu_state._cycles @@ -575,6 +577,8 @@ extern uint32_t atapi_get_cd_volume(int channel); extern int ide_ter_enabled; +extern int ui_writeprot[2]; + void pclog(const char *format, ...); extern int nmi; diff --git a/src/mem.c b/src/mem.c index b1f20d4f0..c578aa9e2 100644 --- a/src/mem.c +++ b/src/mem.c @@ -1552,6 +1552,16 @@ uint8_t mem_readb_phys(uint32_t addr) return 0xff; } +uint16_t mem_readw_phys(uint32_t addr) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_read_w[addr >> 14]) + return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + void mem_writeb_phys(uint32_t addr, uint8_t val) { mem_logical_addr = 0xffffffff; @@ -1560,6 +1570,14 @@ void mem_writeb_phys(uint32_t addr, uint8_t val) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); } +void mem_writew_phys(uint32_t addr, uint16_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_w[addr >> 14]) + _mem_write_w[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + uint8_t mem_read_ram(uint32_t addr, void *priv) { // if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMb %08X\n", addr); diff --git a/src/pc.c b/src/pc.c index 7a89e25fc..705689980 100644 --- a/src/pc.c +++ b/src/pc.c @@ -96,6 +96,7 @@ void fatal(const char *format, ...) va_end(ap); fflush(stdout); savenvr(); + saveconfig(); dumppic(); dumpregs(); fflush(stdout); @@ -360,6 +361,7 @@ void resetpc_cad() void resetpchard() { savenvr(); + saveconfig(); device_close_all(); device_init(); @@ -618,13 +620,18 @@ void loadconfig(char *fn) video_speed = config_get_int(NULL, "video_speed", 3); sound_card_current = config_get_int(NULL, "sndcard", SB2); + // d86f_unregister(0); + // d86f_unregister(1); + p = (char *)config_get_string(NULL, "disc_a", ""); if (p) strcpy(discfns[0], p); else strcpy(discfns[0], ""); + ui_writeprot[0] = config_get_int(NULL, "disc_a_writeprot", 0); p = (char *)config_get_string(NULL, "disc_b", ""); if (p) strcpy(discfns[1], p); else strcpy(discfns[1], ""); + ui_writeprot[1] = config_get_int(NULL, "disc_b_writeprot", 0); mem_size = config_get_int(NULL, "mem_size", 4096); if (mem_size < (models[model].is_at ? models[model].min_ram*1024 : models[model].min_ram)) @@ -746,7 +753,9 @@ void saveconfig() config_set_int(NULL, "cache", cache); config_set_int(NULL, "cga_composite", cga_comp); config_set_string(NULL, "disc_a", discfns[0]); + config_set_int(NULL, "disc_a_writeprot", ui_writeprot[0]); config_set_string(NULL, "disc_b", discfns[1]); + config_set_int(NULL, "disc_b_writeprot", ui_writeprot[1]); config_set_int(NULL, "mem_size", mem_size); config_set_int(NULL, "cdrom_drive", cdrom_drive); config_set_int(NULL, "cdrom_enabled", cdrom_enabled); diff --git a/src/pc.rc b/src/pc.rc index 9023ff12f..210f77dc7 100644 --- a/src/pc.rc +++ b/src/pc.rc @@ -19,9 +19,11 @@ BEGIN POPUP "&Disc" BEGIN MENUITEM "Change drive &A:...", IDM_DISC_A + MENUITEM "Change drive A (&Write-protected):...", IDM_DISC_A_WP MENUITEM "Change drive &B:...", IDM_DISC_B + MENUITEM "Change drive B (W&rite-protected):...", IDM_DISC_B_WP MENUITEM "&Eject drive A:", IDM_EJECT_A - MENUITEM "Eject drive B:", IDM_EJECT_B + MENUITEM "E&ject drive B:", IDM_EJECT_B MENUITEM "&Configure hard discs...",IDM_HDCONF END POPUP "&Settings" diff --git a/src/pc87306.c b/src/pc87306.c index c8eb2cc2a..b3d44957b 100644 --- a/src/pc87306.c +++ b/src/pc87306.c @@ -33,22 +33,24 @@ void pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) uint8_t uart_int1() { - return ((pc87306_regs[0x1C] >> 2) & 1) ? 3 : 4; + return ((pc87306_regs[0x1C] >> 2) & 1) ? 4 : 3; } uint8_t uart_int2() { - return ((pc87306_regs[0x1C] >> 6) & 1) ? 3 : 4; + return ((pc87306_regs[0x1C] >> 6) & 1) ? 4 : 3; } uint8_t uart1_int() { - return (pc87306_regs[0x1C] & 1) ? uart_int1() : 4; + temp = ((pc87306_regs[1] >> 2) & 1) ? 3 : 4; /* 0 = IRQ 4, 1 = IRQ 3 */ + return (pc87306_regs[0x1C] & 1) ? uart_int1() : temp; } uint8_t uart2_int() { - return (pc87306_regs[0x1C] & 1) ? uart_int2() : 3; + temp = ((pc87306_regs[1] >> 4) & 1) ? 3 : 4; /* 0 = IRQ 4, 1 = IRQ 3 */ + return (pc87306_regs[0x1C] & 1) ? uart_int2() : temp; } void serial1_handler() @@ -178,7 +180,7 @@ process_value: if (val & 2) { serial1_handler(); - if (mouse_always_serial) mouse_serial_init(); + // if (mouse_always_serial) mouse_serial_init(); } if (val & 4) serial2_handler(); @@ -218,7 +220,7 @@ process_value: if (pc87306_regs[0] & 2) { serial1_handler(); - if (mouse_always_serial) mouse_serial_init(); + // if (mouse_always_serial) mouse_serial_init(); } if (pc87306_regs[0] & 4) serial2_handler(); break; @@ -237,7 +239,7 @@ process_value: if (pc87306_regs[0] & 2) { serial1_handler(); - if (mouse_always_serial) mouse_serial_init(); + // if (mouse_always_serial) mouse_serial_init(); } if (pc87306_regs[0] & 4) serial2_handler(); } diff --git a/src/piix.c b/src/piix.c index ef16f17fe..dbf66a0fc 100644 --- a/src/piix.c +++ b/src/piix.c @@ -519,6 +519,7 @@ void piix_init(int card) card_piix_ide[0x0d] = 0x00; card_piix_ide[0x0e] = 0x00; card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ + card_piix_ide[0x3C] = 14; /* Default IRQ */ card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; diff --git a/src/resources.h b/src/resources.h index 57cb349e7..159a9d7e7 100644 --- a/src/resources.h +++ b/src/resources.h @@ -10,6 +10,8 @@ #define IDM_EJECT_A 40012 #define IDM_EJECT_B 40013 #define IDM_HDCONF 40014 +#define IDM_DISC_A_WP 40015 +#define IDM_DISC_B_WP 40016 #define IDM_CONFIG 40020 #define IDM_CONFIG_LOAD 40021 #define IDM_CONFIG_SAVE 40022 diff --git a/src/win.c b/src/win.c index 5f84610fb..cba7a2018 100644 --- a/src/win.c +++ b/src/win.c @@ -805,6 +805,7 @@ int WINAPI WinMain (HINSTANCE hThisInstance, // pclog("Quited? %i\n",quited); // pclog("Closepc\n"); savenvr(); + saveconfig(); if (save_window_pos && window_remember) saveconfig(); closepc(); @@ -974,6 +975,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM pause=1; Sleep(100); savenvr(); + saveconfig(); resetpc(); pause=0; break; @@ -982,6 +984,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM pause=1; Sleep(100); savenvr(); + saveconfig(); resetpchard(); pause=0; break; @@ -989,6 +992,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM pause=1; Sleep(100); savenvr(); + saveconfig(); resetpc_cad(); pause=0; break; @@ -996,17 +1000,21 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; case IDM_DISC_A: + case IDM_DISC_A_WP: if (!getfile(hwnd,"Disc image (*.12;*.144;*.360;*.720;*.86F;*.DSK;*.IMG;*.IMA;*.FDI;*.FLP;*.XDF;*.VFD)\0*.12;*.144;*.360;*.720;*.86F;*.DSK;*.IMG;*.IMA;*.FDI;*.FLP;*.XDF;*.VFD\0All files (*.*)\0*.*\0",discfns[0])) { disc_close(0); + ui_writeprot[0] = (LOWORD(wParam) == IDM_DISC_A_WP) ? 1 : 0; disc_load(0, openfilestring); saveconfig(); } break; case IDM_DISC_B: + case IDM_DISC_B_WP: if (!getfile(hwnd,"Disc image (*.12;*.144;*.360;*.720;*.86F;*.DSK;*.IMG;*.IMA;*.FDI;*.FLP;*.XDF;*.VFD)\0*.12;*.144;*.360;*.720;*.86F;*.DSK;*.IMG;*.IMA;*.FDI;*.FLP;*.XDF;*.VFD\0All files (*.*)\0*.*\0",discfns[1])) { disc_close(1); + ui_writeprot[1] = (LOWORD(wParam) == IDM_DISC_B_WP) ? 1 : 0; disc_load(1, openfilestring); saveconfig(); } diff --git a/src/x87_ops_misc.h b/src/x87_ops_misc.h index b7c3c5e34..894271330 100644 --- a/src/x87_ops_misc.h +++ b/src/x87_ops_misc.h @@ -32,6 +32,7 @@ static int opFINIT(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); cpu_state.npxs = 0; *(uint64_t *)cpu_state.tag = 0x0303030303030303ll; cpu_state.TOP = 0; @@ -96,6 +97,7 @@ static int FSTOR() case 0x000: /*16-bit real mode*/ case 0x001: /*16-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -104,6 +106,7 @@ static int FSTOR() case 0x100: /*32-bit real mode*/ case 0x101: /*32-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -676,6 +679,7 @@ static int FLDENV() case 0x000: /*16-bit real mode*/ case 0x001: /*16-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -683,6 +687,7 @@ static int FLDENV() case 0x100: /*32-bit real mode*/ case 0x101: /*32-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -716,6 +721,7 @@ static int opFLDCW_a16(uint32_t fetchdat) tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); CLOCK_CYCLES(4); return 0; } @@ -728,6 +734,7 @@ static int opFLDCW_a32(uint32_t fetchdat) tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); CLOCK_CYCLES(4); return 0; }