From 713bce1205160ec4779cca3313ad57b63638c47e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 15 Jul 2017 12:46:44 +0200 Subject: [PATCH] Applied all relevant mainline PCem commits (VME emulation, AT ESDI controller). --- src/CPU/386_dynarec.c | 32 ++ src/CPU/808x.c | 2 +- src/CPU/codegen_ops_misc.h | 4 + src/CPU/cpu.c | 60 ++- src/CPU/cpu.h | 32 +- src/CPU/x86_ops_flag.h | 118 ++++- src/CPU/x86_ops_int.h | 64 ++- src/CPU/x86_ops_ret.h | 80 ++-- src/Makefile.mingw | 2 +- src/WIN/win_settings.c | 24 +- src/esdi_at.c | 853 +++++++++++++++++++++++++++++++++++++ src/esdi_at.h | 1 + src/hdd.c | 2 + src/hdd_esdi.c | 8 +- src/hdd_image.c | 77 ++++ src/hdd_image.h | 3 + src/ibm.h | 6 + src/rom.c | 2 +- src/rom.h | 4 + 19 files changed, 1250 insertions(+), 124 deletions(-) create mode 100644 src/esdi_at.c create mode 100644 src/esdi_at.h diff --git a/src/CPU/386_dynarec.c b/src/CPU/386_dynarec.c index c59110cd6..a2a36cfa1 100644 --- a/src/CPU/386_dynarec.c +++ b/src/CPU/386_dynarec.c @@ -265,6 +265,38 @@ void x86_int_sw(int num) CPU_BLOCK_END(); } +int x86_int_sw_rm(int num) +{ + uint32_t addr; + uint16_t new_pc, new_cs; + + flags_rebuild(); + cycles -= timing_int; + + addr = num << 2; + new_pc = readmemw(0, addr); + new_cs = readmemw(0, addr + 2); + + if (cpu_state.abrt) return 1; + + writememw(ss,((SP-2)&0xFFFF),flags); if (cpu_state.abrt) {pclog("abrt5\n"); return 1; } + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); if (cpu_state.abrt) {pclog("abrt6\n"); return 1; } + SP-=6; + + eflags &= ~VIF_FLAG; + flags &= ~T_FLAG; + cpu_state.pc = new_pc; + loadcs(new_cs); + oxpc=cpu_state.pc; + + cycles -= timing_int_rm; + trap = 0; + CPU_BLOCK_END(); + + return 0; +} + void x86illegal() { x86_int(6); diff --git a/src/CPU/808x.c b/src/CPU/808x.c index faa951409..dcc95132f 100644 --- a/src/CPU/808x.c +++ b/src/CPU/808x.c @@ -547,7 +547,7 @@ void dumpregs(int force) if (is386) { printf("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); - printf("CR0=%08X CR2=%08X CR3=%08X\n",cr0,cr2,cr3); + printf("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n",cr0,cr2,cr3, cr4); } printf("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); for (c=0;c<1024*1024;c++) diff --git a/src/CPU/codegen_ops_misc.h b/src/CPU/codegen_ops_misc.h index e5d4f59dd..d3039c81a 100644 --- a/src/CPU/codegen_ops_misc.h +++ b/src/CPU/codegen_ops_misc.h @@ -16,11 +16,15 @@ static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 static uint32_t ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { + if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) + return 0; CLEAR_BITS((uintptr_t)&flags, I_FLAG); return op_pc; } static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { + if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) + return 0; SET_BITS((uintptr_t)&flags, I_FLAG); return op_pc; } diff --git a/src/CPU/cpu.c b/src/CPU/cpu.c index 0f12a59f1..6e4b1eb93 100644 --- a/src/CPU/cpu.c +++ b/src/CPU/cpu.c @@ -71,6 +71,7 @@ OpFn *x86_opcodes_df_a32; enum { CPUID_FPU = (1 << 0), + CPUID_VME = (1 << 1), CPUID_TSC = (1 << 4), CPUID_MSR = (1 << 5), CPUID_CMPXCHG8B = (1 << 8), @@ -90,6 +91,7 @@ int cpu_busspeed; int cpu_hasrdtsc; int cpu_hasMMX, cpu_hasMSR; int cpu_hasCR4; +int cpu_hasVME; int cpu_use_dynarec; int cpu_cyrix_alignment; @@ -365,8 +367,8 @@ CPU cpus_i486[] = {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6}, - {"iDX4/75", CPU_i486DX, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9}, /*CPUID available on DX4, >= 75 MHz*/ - {"iDX4/100", CPU_i486DX,10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ + {"iDX4/75", CPU_iDX4, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9}, /*CPUID available on DX4, >= 75 MHz*/ + {"iDX4/100", CPU_iDX4, 10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ {"Pentium OverDrive/63", CPU_PENTIUM, 6, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7}, {"Pentium OverDrive/83", CPU_PENTIUM, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8}, {"", -1, 0, 0, 0} @@ -991,6 +993,10 @@ void cpu_set() timing_misaligned = 3; break; + case CPU_iDX4: + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; case CPU_i486SX: case CPU_i486DX: x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); @@ -1204,7 +1210,8 @@ void cpu_set() cpu_hasMMX = 0; cpu_hasMSR = 1; cpu_hasCR4 = 1; - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; codegen_timing_set(&codegen_timing_pentium); break; @@ -1244,7 +1251,8 @@ void cpu_set() cpu_hasMMX = 1; cpu_hasMSR = 1; cpu_hasCR4 = 1; - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; codegen_timing_set(&codegen_timing_pentium); break; @@ -1443,7 +1451,8 @@ void cpu_set() cpu_hasMMX = 1; cpu_hasMSR = 1; cpu_hasCR4 = 1; - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; codegen_timing_set(&codegen_timing_pentium); break; @@ -1476,7 +1485,8 @@ void cpu_set() cpu_hasMMX = 0; cpu_hasMSR = 1; cpu_hasCR4 = 1; - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; codegen_timing_set(&codegen_timing_686); break; @@ -1510,7 +1520,8 @@ void cpu_set() cpu_hasMMX = 1; cpu_hasMSR = 1; cpu_hasCR4 = 1; - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; codegen_timing_set(&codegen_timing_686); break; #endif @@ -1544,7 +1555,8 @@ void cpu_set() cpu_hasMMX = 1; cpu_hasMSR = 1; cpu_hasCR4 = 1; - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE | CR4_OSFXSR; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE | CR4_OSFXSR; codegen_timing_set(&codegen_timing_686); break; @@ -1575,6 +1587,24 @@ void cpu_CPUID() EAX = 0; break; + case CPU_iDX4: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME; + } + else + EAX = 0; + break; + case CPU_Am486SX: if (!EAX) { @@ -1651,7 +1681,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; } else EAX = 0; @@ -1739,7 +1769,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; } else if (EAX == 0x80000000) { @@ -1750,7 +1780,7 @@ void cpu_CPUID() { EAX = CPUID + 0x100; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP; } else if (EAX == 0x80000002) { @@ -1801,7 +1831,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; } else EAX = 0; @@ -1896,7 +1926,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_CMOV; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_CMOV; } else if (EAX == 2) { @@ -1917,7 +1947,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_CMOV; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_CMOV; } else if (EAX == 2) { @@ -1941,7 +1971,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; } else if (EAX == 2) { diff --git a/src/CPU/cpu.h b/src/CPU/cpu.h index b792b36b8..a786adf3c 100644 --- a/src/CPU/cpu.h +++ b/src/CPU/cpu.h @@ -44,26 +44,27 @@ extern int cpu, cpu_manufacturer; #define CPU_i486DX 11 #define CPU_Am486DX 12 #define CPU_Cx486DX 13 -#define CPU_Cx5x86 14 +#define CPU_iDX4 14 +#define CPU_Cx5x86 15 /*586 class CPUs*/ -#define CPU_WINCHIP 15 -#define CPU_PENTIUM 16 -#define CPU_PENTIUMMMX 17 -#define CPU_Cx6x86 18 -#define CPU_Cx6x86MX 19 -#define CPU_Cx6x86L 20 -#define CPU_CxGX1 21 -#define CPU_K5 22 -#define CPU_5K86 23 -#define CPU_K6 24 +#define CPU_WINCHIP 16 +#define CPU_PENTIUM 17 +#define CPU_PENTIUMMMX 18 +#define CPU_Cx6x86 19 +#define CPU_Cx6x86MX 20 +#define CPU_Cx6x86L 21 +#define CPU_CxGX1 22 +#define CPU_K5 23 +#define CPU_5K86 24 +#define CPU_K6 25 /*686 class CPUs*/ -#define CPU_PENTIUMPRO 25 +#define CPU_PENTIUMPRO 26 /* -#define CPU_PENTIUM2 26 -#define CPU_PENTIUM2D 27 */ -#define CPU_PENTIUM2D 26 +#define CPU_PENTIUM2 27 +#define CPU_PENTIUM2D 28 */ +#define CPU_PENTIUM2D 27 #define MANU_INTEL 0 #define MANU_AMD 1 @@ -144,6 +145,7 @@ extern int cpu_hasrdtsc; extern int cpu_hasMSR; extern int cpu_hasMMX; extern int cpu_hasCR4; +extern int cpu_hasVME; #define CR4_TSD (1 << 2) #define CR4_DE (1 << 3) diff --git a/src/CPU/x86_ops_flag.h b/src/CPU/x86_ops_flag.h index 9f70330f9..7205af152 100644 --- a/src/CPU/x86_ops_flag.h +++ b/src/CPU/x86_ops_flag.h @@ -27,8 +27,16 @@ static int opCLI(uint32_t fetchdat) { if (!IOPLp) { - x86gpf(NULL,0); - return 1; + if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + eflags &= ~VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } } else flags &= ~I_FLAG; @@ -57,8 +65,22 @@ static int opSTI(uint32_t fetchdat) { if (!IOPLp) { - x86gpf(NULL,0); - return 1; + if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + if (eflags & VIP_FLAG) + { + x86gpf(NULL,0); + return 1; + } + else + eflags |= VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } } else flags |= I_FLAG; @@ -94,11 +116,27 @@ static int opPUSHF(uint32_t fetchdat) { if ((eflags & VM_FLAG) && (IOPL < 3)) { - x86gpf(NULL,0); - return 1; + if (cr4 & CR4_VME) + { + uint16_t temp; + + flags_rebuild(); + temp = (flags & ~I_FLAG) | 0x3000; + if (eflags & VIF_FLAG) + temp |= I_FLAG; + PUSH_W(temp); + } + else + { + x86gpf(NULL,0); + return 1; + } } - flags_rebuild(); - PUSH_W(flags); + else + { + flags_rebuild(); + PUSH_W(flags); + } CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); return cpu_state.abrt; @@ -111,8 +149,9 @@ static int opPUSHFD(uint32_t fetchdat) x86gpf(NULL, 0); return 1; } - if (CPUID) tempw = eflags & 0x24; - else tempw = eflags & 4; + if (cpu_CR4_mask & CR4_VME) tempw = eflags & 0x3c; + else if (CPUID) tempw = eflags & 0x24; + else tempw = eflags & 4; flags_rebuild(); PUSH_L(flags | (tempw << 16)); CLOCK_CYCLES(4); @@ -151,15 +190,49 @@ static int opPOPF(uint32_t fetchdat) if ((eflags & VM_FLAG) && (IOPL < 3)) { - x86gpf(NULL, 0); - return 1; - } - - tempw = POP_W(); if (cpu_state.abrt) return 1; + if (cr4 & CR4_VME) + { + uint32_t old_esp = ESP; - if (!(CPL) || !(msw & 1)) flags = (tempw & 0x7fd5) | 2; - else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; - else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + tempw = POP_W(); + if (cpu_state.abrt) + { + + ESP = old_esp; + return 1; + } + + if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (eflags & VIP_FLAG))) + { + ESP = old_esp; + x86gpf(NULL, 0); + return 1; + } + if (tempw & I_FLAG) + eflags |= VIF_FLAG; + else + eflags &= ~VIF_FLAG; + flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + } + else + { + x86gpf(NULL, 0); + return 1; + } + } + else + { + tempw = POP_W(); + if (cpu_state.abrt) + return 1; + + if (!(CPL) || !(msw & 1)) + flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) + flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else + flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + } flags_extract(); CLOCK_CYCLES(5); @@ -185,11 +258,12 @@ static int opPOPFD(uint32_t fetchdat) else if (IOPLp) flags = (flags & 0x3000) | (templ & 0x4fd5) | 2; else flags = (flags & 0x3200) | (templ & 0x4dd5) | 2; - templ &= is486 ? 0x240000 : 0; + templ &= is486 ? 0x3c0000 : 0; templ |= ((eflags&3) << 16); - if (CPUID) eflags = (templ >> 16) & 0x27; - else if (is486) eflags = (templ >> 16) & 7; - else eflags = (templ >> 16) & 3; + if (cpu_CR4_mask & CR4_VME) eflags = (templ >> 16) & 0x3f; + else if (CPUID) eflags = (templ >> 16) & 0x27; + else if (is486) eflags = (templ >> 16) & 7; + else eflags = (templ >> 16) & 3; flags_extract(); diff --git a/src/CPU/x86_ops_int.h b/src/CPU/x86_ops_int.h index e488ae83a..354bcd59b 100644 --- a/src/CPU/x86_ops_int.h +++ b/src/CPU/x86_ops_int.h @@ -29,47 +29,39 @@ static int opINT1(uint32_t fetchdat) static int opINT(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - uint8_t temp; - - /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ + uint8_t temp = getbytef(); + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { + if (cr4 & CR4_VME) + { + uint16_t t; + uint8_t d; + + cpl_override = 1; + t = readmemw(tr.base, 0x66) - 32; + cpl_override = 0; + if (cpu_state.abrt) return 1; + + t += (temp >> 3); + if (t <= tr.limit) + { + cpl_override = 1; + d = readmemb(tr.base, t);// + (temp >> 3)); + cpl_override = 0; + if (cpu_state.abrt) return 1; + + if (!(d & (1 << (temp & 7)))) + { + x86_int_sw_rm(temp); + PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); + return 1; + } + } + } x86gpf(NULL,0); return 1; } - temp = getbytef(); -// /*if (temp == 0x10 && AH == 0xe) */pclog("INT %02X : %04X %04X %04X %04X %c %04X:%04X\n", temp, AX, BX, CX, DX, (AL < 32) ? ' ' : AL, CS, pc); -// if (CS == 0x0028 && pc == 0xC03813C0) -// output = 3; -/* if (pc == 0x8028009A) - output = 3; - if (pc == 0x80282B6F) - { - __times++; - if (__times == 2) - fatal("WRONG\n"); - } - if (pc == 0x802809CE) - fatal("RIGHT\n");*/ -// if (CS == 0x0028 && pc == 0x80037FE9) -// output = 3; -//if (CS == 0x9087 && pc == 0x3763) -// fatal("Here\n"); -//if (CS==0x9087 && pc == 0x0850) -// output = 1; - -/* if (output && pc == 0x80033008) - { - __times++; - if (__times == 2) - fatal("WRONG\n"); - }*/ -/* if (output && pc == 0x80D8) - { - __times++; - if (__times == 2) - fatal("RIGHT\n"); - }*/ x86_int_sw(temp); PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); diff --git a/src/CPU/x86_ops_ret.h b/src/CPU/x86_ops_ret.h index 0bc88e466..72998c0f6 100644 --- a/src/CPU/x86_ops_ret.h +++ b/src/CPU/x86_ops_ret.h @@ -141,35 +141,67 @@ static int opIRET(uint32_t fetchdat) if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { - x86gpf(NULL,0); - return 1; - } - if (msw&1) - { - optype = IRET; - pmodeiret(0); - optype = 0; - } - else - { - uint16_t new_cs; - oxpc = cpu_state.pc; - if (stack32) + if (cr4 & CR4_VME) { - cpu_state.pc = readmemw(ss, ESP); - new_cs = readmemw(ss, ESP + 2); - flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; - ESP += 6; + uint16_t new_pc, new_cs, new_flags; + + new_pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + new_flags = readmemw(ss, ((SP + 4) & 0xffff)); + if (cpu_state.abrt) + return 1; + + if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (eflags & VIP_FLAG))) + { + x86gpf(NULL, 0); + return 1; + } + SP += 6; + if (new_flags & I_FLAG) + eflags |= VIF_FLAG; + else + eflags &= ~VIF_FLAG; + flags = (flags & 0x3300) | (new_flags & 0x4cd5) | 2; + loadcs(new_cs); + cpu_state.pc = new_pc; + + cycles -= timing_iret_rm; } else { - cpu_state.pc = readmemw(ss, SP); - new_cs = readmemw(ss, ((SP + 2) & 0xffff)); - flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; - SP += 6; + x86gpf(NULL,0); + return 1; + } + } + else + { + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; } - loadcs(new_cs); - cycles -= timing_iret_rm; } flags_extract(); nmi_enable = 1; diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 481bfc275..3870b99c8 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -165,7 +165,7 @@ DEVOBJ = bugger.o lpt.o serial.o \ mouse.o mouse_serial.o mouse_ps2.o mouse_bus.o \ fdd.o fdc.o fdi2raw.o \ hdd.o hdd_image.o \ - mfm_at.o mfm_xebec.o hdd_esdi.o ide.o xtide.o piix.o \ + esdi_at.o mfm_at.o mfm_xebec.o hdd_esdi.o ide.o xtide.o piix.o \ disc.o \ disc_86f.o disc_fdi.o disc_imd.o disc_img.o \ disc_random.o disc_td0.o \ diff --git a/src/WIN/win_settings.c b/src/WIN/win_settings.c index a6f504a92..c8adb02af 100644 --- a/src/WIN/win_settings.c +++ b/src/WIN/win_settings.c @@ -2538,6 +2538,7 @@ static BOOL CALLBACK win_settings_hard_disks_add_proc(HWND hdlg, UINT message, W char *big_buf; int b = 0; uint64_t r = 0; + int j = 0; switch (message) { @@ -2852,24 +2853,31 @@ hdd_add_file_open_error: fseeko64(f, 0, SEEK_END); size = ftello64(f); fclose(f); - if (((size % 17) == 0) && (size <= 133693440)) + if (((size % 17) == 0) && (size <= 142606336)) { spt = 17; if (size <= 26738688) { hpc = 4; } - else if (size <= 53477376) + else if (((size % 3072) == 0) && (size <= 53477376)) { hpc = 6; } - else if (size <= 71303168) - { - hpc = 8; - } else { - hpc = 15; + for (j = 0; j < 16; j++) + { + if (((size % (i << 9)) == 0) && (size <= ((i * 17) << 19))) + { + break; + } + if (i == 5) + { + i++; + } + } + hpc = i; } } else @@ -2907,7 +2915,7 @@ hdd_add_file_open_error: chs_enabled = 1; no_update = 0; - } + } else { fclose(f); diff --git a/src/esdi_at.c b/src/esdi_at.c new file mode 100644 index 000000000..11d5c048c --- /dev/null +++ b/src/esdi_at.c @@ -0,0 +1,853 @@ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include + +#include "ibm.h" +#include "device.h" +#include "hdd_image.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "rom.h" +#include "timer.h" + +#include "esdi_at.h" + + +#define IDE_TIME (TIMER_USEC*10) + +#define STAT_ERR 0x01 +#define STAT_INDEX 0x02 +#define STAT_CORRECTED_DATA 0x04 +#define STAT_DRQ 0x08 /* Data request */ +#define STAT_DSC 0x10 +#define STAT_SEEK_COMPLETE 0x20 +#define STAT_READY 0x40 +#define STAT_BUSY 0x80 + +#define ERR_DAM_NOT_FOUND 0x01 /*Data Address Mark not found*/ +#define ERR_TR000 0x02 /*Track 0 not found*/ +#define ERR_ABRT 0x04 /*Command aborted*/ +#define ERR_ID_NOT_FOUND 0x10 /*ID not found*/ +#define ERR_DATA_CRC 0x40 /*Data CRC error*/ +#define ERR_BAD_BLOCK 0x80 /*Bad Block detected*/ + +#define CMD_NOP 0x00 +#define CMD_RESTORE 0x10 +#define CMD_READ 0x20 +#define CMD_WRITE 0x30 +#define CMD_VERIFY 0x40 +#define CMD_FORMAT 0x50 +#define CMD_SEEK 0x70 +#define CMD_DIAGNOSE 0x90 +#define CMD_SET_PARAMETERS 0x91 +#define CMD_READ_PARAMETERS 0xec + +extern char ide_fn[4][512]; + +typedef struct esdi_drive_t +{ + int cfg_spt; + int cfg_hpc; + int current_cylinder; + int real_spt; + int real_hpc; + int real_tracks; + int present; + int hdc_num; +} esdi_drive_t; + +typedef struct esdi_t +{ + uint8_t status; + uint8_t error; + int secount,sector,cylinder,head,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + + int drive_sel; + int reset; + uint16_t buffer[256]; + int irqstat; + + int callback; + + esdi_drive_t drives[2]; + + rom_t bios_rom; +} esdi_t; + +uint16_t esdi_readw(uint16_t port, void *p); +void esdi_writew(uint16_t port, uint16_t val, void *p); + +static inline void esdi_irq_raise(esdi_t *esdi) +{ + if (!(esdi->fdisk&2)) + picint(1 << 14); + + esdi->irqstat=1; +} + +static inline void esdi_irq_lower(esdi_t *esdi) +{ + picintc(1 << 14); +} + +void esdi_irq_update(esdi_t *esdi) +{ + if (esdi->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(esdi->fdisk & 2)) + picint(1 << 14); +} + +/* + * Return the sector offset for the current register values + */ +int esdi_get_sector(esdi_t *esdi, off64_t *addr) +{ + esdi_drive_t *drive = &esdi->drives[esdi->drive_sel]; + int heads = drive->cfg_hpc; + int sectors = drive->cfg_spt; + + if (esdi->head > heads) + { + pclog("esdi_get_sector: past end of configured heads\n"); + return 1; + } + if (esdi->sector >= sectors+1) + { + pclog("esdi_get_sector: past end of configured sectors\n"); + return 1; + } + + if (drive->cfg_spt == drive->real_spt && drive->cfg_hpc == drive->real_hpc) + { + *addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) * + sectors) + (esdi->sector - 1); + } + else + { + /*When performing translation, the firmware seems to leave 1 + sector per track inaccessible (spare sector)*/ + int c, h, s; + *addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) * + sectors) + (esdi->sector - 1); + + s = *addr % (drive->real_spt - 1); + h = (*addr / (drive->real_spt - 1)) % drive->real_hpc; + c = (*addr / (drive->real_spt - 1)) / drive->real_hpc; + + *addr = ((((off64_t) c * drive->real_hpc) + h) * + drive->real_spt) + s; + } + + return 0; +} + +/** + * Move to the next sector using CHS addressing + */ +void esdi_next_sector(esdi_t *esdi) +{ + esdi_drive_t *drive = &esdi->drives[esdi->drive_sel]; + + esdi->sector++; + if (esdi->sector == (drive->cfg_spt + 1)) + { + esdi->sector = 1; + esdi->head++; + if (esdi->head == drive->cfg_hpc) + { + esdi->head = 0; + esdi->cylinder++; + if (drive->current_cylinder < drive->real_tracks) + drive->current_cylinder++; + } + } +} + +void esdi_write(uint16_t port, uint8_t val, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + + switch (port) + { + case 0x1F0: /* Data */ + esdi_writew(port, val | (val << 8), p); + return; + + case 0x1F1: /* Write precompenstation */ + esdi->cylprecomp = val; + return; + + case 0x1F2: /* Sector count */ + esdi->secount = val; + return; + + case 0x1F3: /* Sector */ + esdi->sector = val; + return; + + case 0x1F4: /* Cylinder low */ + esdi->cylinder = (esdi->cylinder & 0xFF00) | val; + return; + + case 0x1F5: /* Cylinder high */ + esdi->cylinder = (esdi->cylinder & 0xFF) | (val << 8); + return; + + case 0x1F6: /* Drive/Head */ + esdi->head = val & 0xF; + esdi->drive_sel = (val & 0x10) ? 1 : 0; + if (esdi->drives[esdi->drive_sel].present) + esdi->status = 0; + else + esdi->status = STAT_READY | STAT_DSC; + return; + + case 0x1F7: /* Command register */ + esdi_irq_lower(esdi); + esdi->command = val; + esdi->error = 0; + + switch (val & 0xf0) + { + case CMD_RESTORE: + esdi->command &= ~0x0f; /*Mask off step rate*/ + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_SEEK: + esdi->command &= ~0x0f; /*Mask off step rate*/ + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + default: + switch (val) + { + case CMD_NOP: + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_READ: case CMD_READ+1: + case CMD_READ+2: case CMD_READ+3: + esdi->command &= ~3; + if (val & 2) + fatal("Read with ECC\n"); + case 0xa0: + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_WRITE: case CMD_WRITE+1: + case CMD_WRITE+2: case CMD_WRITE+3: + esdi->command &= ~3; + if (val & 2) + fatal("Write with ECC\n"); + esdi->status = STAT_DRQ | STAT_DSC; + esdi->pos=0; + break; + + case CMD_VERIFY: case CMD_VERIFY+1: + esdi->command &= ~1; + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 200 * IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_FORMAT: + esdi->status = STAT_DRQ; + esdi->pos=0; + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 30*IDE_TIME; + timer_update_outstanding(); + break; + + case CMD_DIAGNOSE: /* Execute Drive Diagnostics */ + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + case 0xe0: /*???*/ + case CMD_READ_PARAMETERS: + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + + default: + pclog("Bad esdi command %02X\n", val); + case 0xe8: /*???*/ + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 200*IDE_TIME; + timer_update_outstanding(); + break; + } + } + break; + + case 0x3F6: /* Device control */ + if ((esdi->fdisk & 4) && !(val & 4)) + { + timer_process(); + esdi->callback = 500*IDE_TIME; + timer_update_outstanding(); + esdi->reset = 1; + esdi->status = STAT_BUSY; + } + if (val & 4) + { + /*Drive held in reset*/ + timer_process(); + esdi->callback = 0; + timer_update_outstanding(); + esdi->status = STAT_BUSY; + } + esdi->fdisk = val; + esdi_irq_update(esdi); + return; + } +} + +void esdi_writew(uint16_t port, uint16_t val, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + + esdi->buffer[esdi->pos >> 1] = val; + esdi->pos += 2; + + if (esdi->pos >= 512) + { + esdi->pos = 0; + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 6*IDE_TIME; + timer_update_outstanding(); + } +} + +uint8_t esdi_read(uint16_t port, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + uint8_t temp = 0xff; + + switch (port) + { + case 0x1F0: /* Data */ + temp = esdi_readw(port, esdi) & 0xff; + break; + + case 0x1F1: /* Error */ + temp = esdi->error; + break; + + case 0x1F2: /* Sector count */ + temp = (uint8_t)esdi->secount; + break; + + case 0x1F3: /* Sector */ + temp = (uint8_t)esdi->sector; + break; + + case 0x1F4: /* Cylinder low */ + temp = (uint8_t)(esdi->cylinder&0xFF); + break; + + case 0x1F5: /* Cylinder high */ + temp = (uint8_t)(esdi->cylinder>>8); + break; + + case 0x1F6: /* Drive/Head */ + temp = (uint8_t)(esdi->head | (esdi->drive_sel ? 0x10 : 0) | 0xa0); + break; + + case 0x1F7: /* Status */ + esdi_irq_lower(esdi); + temp = esdi->status; + break; + } + + return temp; +} + +uint16_t esdi_readw(uint16_t port, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + uint16_t temp; + + temp = esdi->buffer[esdi->pos >> 1]; + esdi->pos += 2; + + if (esdi->pos >= 512) + { + esdi->pos=0; + esdi->status = STAT_READY | STAT_DSC; + if (esdi->command == CMD_READ || esdi->command == 0xa0) + { + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) + { + esdi_next_sector(esdi); + esdi->status = STAT_BUSY; + timer_process(); + esdi->callback = 6*IDE_TIME; + timer_update_outstanding(); + } + } + } + + return temp; +} + +void esdi_callback(void *p) +{ + esdi_t *esdi = (esdi_t *)p; + esdi_drive_t *drive = &esdi->drives[esdi->drive_sel]; + off64_t addr; + + esdi->callback = 0; + if (esdi->reset) + { + esdi->status = STAT_READY | STAT_DSC; + esdi->error = 1; + esdi->secount = 1; + esdi->sector = 1; + esdi->head = 0; + esdi->cylinder = 0; + esdi->reset = 0; + return; + } + switch (esdi->command) + { + case CMD_RESTORE: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + drive->current_cylinder = 0; + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_SEEK: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_READ: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + if (esdi_get_sector(esdi, &addr)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + if (hdd_image_read_ex(drive->hdc_num, addr, 1, (uint8_t *) esdi->buffer)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + esdi->pos = 0; + esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + update_status_bar_icon(SB_HDD | HDD_BUS_RLL, 1); + } + break; + + case CMD_WRITE: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + if (esdi_get_sector(esdi, &addr)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + if (hdd_image_write_ex(drive->hdc_num, addr, 1, (uint8_t *) esdi->buffer)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + esdi_irq_raise(esdi); + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) + { + esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; + esdi->pos = 0; + esdi_next_sector(esdi); + } + else + esdi->status = STAT_READY | STAT_DSC; + update_status_bar_icon(SB_HDD | HDD_BUS_RLL, 1); + } + break; + + case CMD_VERIFY: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + if (esdi_get_sector(esdi, &addr)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + if (hdd_image_read_ex(drive->hdc_num, addr, 1, (uint8_t *) esdi->buffer)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + update_status_bar_icon(SB_HDD | HDD_BUS_RLL, 1); + esdi_next_sector(esdi); + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) + esdi->callback = 6*IDE_TIME; + else + { + esdi->pos = 0; + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + } + break; + + case CMD_FORMAT: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + if (esdi_get_sector(esdi, &addr)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + if (hdd_image_zero_ex(drive->hdc_num, addr, esdi->secount)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + update_status_bar_icon(SB_HDD | HDD_BUS_RLL, 1); + } + break; + + case CMD_DIAGNOSE: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + esdi->error = 1; /*No error detected*/ + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + drive->cfg_spt = esdi->secount; + drive->cfg_hpc = esdi->head+1; + pclog("Parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc); + if (!esdi->secount) + fatal("secount=0\n"); + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_NOP: + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + break; + + case 0xe0: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + switch (esdi->cylinder >> 8) + { + case 0x31: + esdi->cylinder = drive->real_tracks; + break; + case 0x33: + esdi->cylinder = drive->real_hpc; + break; + case 0x35: + esdi->cylinder = 0x200; + break; + case 0x36: + esdi->cylinder = drive->real_spt; + break; + default: + pclog("EDSI Bad read config %02x\n", esdi->cylinder >> 8); + } + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case 0xa0: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + memset(esdi->buffer, 0, 512); + memset(&esdi->buffer[3], 0xff, 512-6); + esdi->pos = 0; + esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_READ_PARAMETERS: + if (!drive->present) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + memset(esdi->buffer, 0, 512); + + esdi->buffer[0] = 0x44; /* general configuration */ + esdi->buffer[1] = drive->real_tracks; /* number of non-removable cylinders */ + esdi->buffer[2] = 0; /* number of removable cylinders */ + esdi->buffer[3] = drive->real_hpc; /* number of heads */ + esdi->buffer[5] = esdi->buffer[4] * drive->real_spt; /* number of unformatted bytes/sector */ + esdi->buffer[4] = 600; /* number of unformatted bytes/track */ + esdi->buffer[6] = drive->real_spt; /* number of sectors */ + esdi->buffer[7] = 0; /*minimum bytes in inter-sector gap*/ + esdi->buffer[8] = 0; /* minimum bytes in postamble */ + esdi->buffer[9] = 0; /* number of words of vendor status */ + /* controller info */ + esdi->buffer[20] = 2; /* controller type */ + esdi->buffer[21] = 1; /* sector buffer size, in sectors */ + esdi->buffer[22] = 0; /* ecc bytes appended */ + esdi->buffer[27] = 'W' | ('D' << 8); + esdi->buffer[28] = '1' | ('0' << 8); + esdi->buffer[29] = '0' | ('7' << 8); + esdi->buffer[30] = 'V' | ('-' << 8); + esdi->buffer[31] = 'S' | ('E' << 8); + esdi->buffer[32] = '1'; + esdi->buffer[47] = 0; /* sectors per interrupt */ + esdi->buffer[48] = 0;/* can use double word read/write? */ + esdi->pos = 0; + esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + default: + pclog("ESDI Callback on unknown command %02x\n", esdi->command); + case 0xe8: + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + break; + } + + update_status_bar_icon(SB_HDD | HDD_BUS_RLL, 0); +} + +static void esdi_rom_write(uint32_t addr, uint8_t val, void *p) +{ + rom_t *rom = (rom_t *)p; + + addr &= rom->mask; + + if (addr >= 0x1f00 && addr < 0x2000) + rom->rom[addr] = val; +} + +static void loadhd(esdi_t *esdi, int hdc_num, int d, const wchar_t *fn) +{ + esdi_drive_t *drive = &esdi->drives[d]; + int ret = 0; + + ret = hdd_image_load(hdc_num); + + if (!ret) + { + drive->present = 0; + return; + } + + drive->cfg_spt = drive->real_spt = hdc[hdc_num].spt; + drive->cfg_hpc = drive->real_hpc = hdc[hdc_num].hpc; + drive->real_tracks = hdc[hdc_num].tracks; + drive->hdc_num = hdc_num; + drive->present = 1; +} + +void *wd1007vse1_init() +{ + int i = 0; + int c = 0; + + esdi_t *esdi = malloc(sizeof(esdi_t)); + memset(esdi, 0, sizeof(esdi_t)); + + esdi->drives[0].present = esdi->drives[1].present = 0; + + for (i = 0; i < HDC_NUM; i++) + { + if ((hdc[i].bus == HDD_BUS_RLL) && (hdc[i].rll_channel < RLL_NUM)) + { + loadhd(esdi, i, hdc[i].rll_channel, hdc[i].fn); + c++; + if (c >= RLL_NUM) break; + } + } + + esdi->status = STAT_READY | STAT_DSC; + esdi->error = 1; /*No errors*/ + + rom_init(&esdi->bios_rom, L"roms/62-000279-061.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_set_handler(&esdi->bios_rom.mapping, + rom_read, rom_readw, rom_readl, + esdi_rom_write, NULL, NULL); + + io_sethandler(0x01f0, 0x0001, esdi_read, esdi_readw, NULL, esdi_write, esdi_writew, NULL, esdi); + io_sethandler(0x01f1, 0x0007, esdi_read, NULL, NULL, esdi_write, NULL, NULL, esdi); + io_sethandler(0x03f6, 0x0001, NULL, NULL, NULL, esdi_write, NULL, NULL, esdi); + + timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi); + + return esdi; +} + +void wd1007vse1_close(void *p) +{ + esdi_t *esdi = (esdi_t *)p; + esdi_drive_t *drive; + + int d; + + esdi->drives[0].present = esdi->drives[1].present = 0; + + for (d = 0; d < 2; d++) + { + drive = &esdi->drives[d]; + + hdd_image_close(drive->hdc_num); + } + + free(esdi); +} + +static int wd1007vse1_available() +{ + return rom_present(L"roms/62-000279-061.bin"); +} + +device_t wd1007vse1_device = +{ + "Western Digital WD1007V-SE1 (ESDI)", + DEVICE_AT, + wd1007vse1_init, + wd1007vse1_close, + wd1007vse1_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/esdi_at.h b/src/esdi_at.h new file mode 100644 index 000000000..fa66ace21 --- /dev/null +++ b/src/esdi_at.h @@ -0,0 +1 @@ +extern device_t wd1007vse1_device; diff --git a/src/hdd.c b/src/hdd.c index 7fdb21d95..6afd3d96d 100644 --- a/src/hdd.c +++ b/src/hdd.c @@ -4,6 +4,7 @@ #include "hdd.h" #include "model.h" +#include "esdi_at.h" #include "hdd_esdi.h" #include "mfm_at.h" #include "mfm_xebec.h" @@ -30,6 +31,7 @@ static struct {"DTC 5150X", "dtc5150x", &dtc_5150x_device, 1}, {"Fixed Disk Adapter (Xebec)", "mfm_xebec", &mfm_xebec_device, 1}, {"IBM ESDI Fixed Disk Adapter (MCA)", "esdi_mca", &hdd_esdi_device, 1}, + {"Western Digital WD1007V-SE1 (ESDI)","wd1007vse1", &wd1007vse1_device, 0}, {"XTIDE", "xtide", &xtide_device, 0}, {"XTIDE (AT)", "xtide_at", &xtide_at_device, 0}, {"XTIDE (PS/2)", "xtide_ps2",&xtide_ps2_device,0}, diff --git a/src/hdd_esdi.c b/src/hdd_esdi.c index 4f31c8836..88d74f4d0 100644 --- a/src/hdd_esdi.c +++ b/src/hdd_esdi.c @@ -819,6 +819,8 @@ static void *esdi_init() rom_init_interleaved(&esdi->bios_rom, L"roms/90x8970.bin", L"roms/90x8969.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); mem_mapping_disable(&esdi->bios_rom.mapping); + esdi->drives[0].present = esdi->drives[1].present = 0; + for (i = 0; i < HDC_NUM; i++) { if ((hdc[i].bus == HDD_BUS_RLL) && (hdc[i].rll_channel < RLL_NUM)) @@ -846,11 +848,15 @@ static void *esdi_init() static void esdi_close(void *p) { esdi_t *esdi = (esdi_t *)p; + esdi_drive_t *drive; + int d; + esdi->drives[0].present = esdi->drives[1].present = 0; + for (d = 0; d < 2; d++) { - esdi_drive_t *drive = &esdi->drives[d]; + drive = &esdi->drives[d]; hdd_image_close(drive->hdc_num); } diff --git a/src/hdd_image.c b/src/hdd_image.c index ff047fc80..bf0b45b11 100644 --- a/src/hdd_image.c +++ b/src/hdd_image.c @@ -361,6 +361,33 @@ void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer fread(buffer, 1, count, hdd_images[id].file); } +uint32_t hdd_sectors(uint8_t id) +{ + fseeko64(hdd_images[id].file, 0, SEEK_END); + return (uint32_t) (ftello64(hdd_images[id].file) >> 9); +} + +int hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + { + transfer_sectors = sectors - sector; + } + + hdd_image_seek(id, sector); + memset(buffer, 0, transfer_sectors << 9); + fread(buffer, 1, transfer_sectors << 9, hdd_images[id].file); + + if (count != transfer_sectors) + { + return 1; + } + return 0; +} + void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { count <<= 9; @@ -369,6 +396,27 @@ void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffe fwrite(buffer, 1, count, hdd_images[id].file); } +int hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + { + transfer_sectors = sectors - sector; + } + + hdd_image_seek(id, sector); + memset(buffer, 0, transfer_sectors << 9); + fwrite(buffer, 1, transfer_sectors << 9, hdd_images[id].file); + + if (count != transfer_sectors) + { + return 1; + } + return 0; +} + void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) { int i = 0; @@ -386,6 +434,35 @@ void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) free(b); } +int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) +{ + int i = 0; + uint8_t *b; + + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + { + transfer_sectors = sectors - sector; + } + + b = (uint8_t *) malloc(512); + memset(b, 0, 512); + + hdd_image_seek(id, sector); + for (i = 0; i < transfer_sectors; i++) + { + fwrite(b, 1, 512, hdd_images[id].file); + } + + if (count != transfer_sectors) + { + return 1; + } + return 0; +} + uint32_t hdd_image_get_last_sector(uint8_t id) { return hdd_images[id].last_sector; diff --git a/src/hdd_image.h b/src/hdd_image.h index e972894fe..f0b3b08b5 100644 --- a/src/hdd_image.h +++ b/src/hdd_image.h @@ -1,8 +1,11 @@ extern int hdd_image_load(int id); extern void hdd_image_seek(uint8_t id, uint32_t sector); extern void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); +extern int hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); extern void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); +extern int hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); extern void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count); +extern int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count); extern uint32_t hdd_image_get_last_sector(uint8_t id); extern uint8_t hdd_image_get_type(uint8_t id); extern void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt); diff --git a/src/ibm.h b/src/ibm.h index cb2ed92a8..b23faa0dc 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -256,9 +256,14 @@ extern uint32_t dr[8]; #define V_FLAG 0x0800 #define NT_FLAG 0x4000 #define VM_FLAG 0x0002 /*In EFLAGS*/ +#define VIF_FLAG 0x0008 /*In EFLAGS*/ +#define VIP_FLAG 0x0010 /*In EFLAGS*/ #define WP_FLAG 0x10000 /*In CR0*/ +#define CR4_VME (1 << 0) +#define CR4_PVI (1 << 1) + #define IOPL ((flags>>12)&3) #define IOPLp ((!(msw&1)) || (CPL<=IOPL)) @@ -775,6 +780,7 @@ extern void softresetx86(void); extern void speedchanged(void); extern void trc_reset(uint8_t val); extern void x86_int_sw(int num); +extern int x86_int_sw_rm(int num); extern void x86gpf(char *s, uint16_t error); extern void x86np(char *s, uint16_t error); extern void x86ss(char *s, uint16_t error); diff --git a/src/rom.c b/src/rom.c index 732d0cecd..4114ee243 100644 --- a/src/rom.c +++ b/src/rom.c @@ -59,7 +59,7 @@ int rom_present(wchar_t *fn) } -static uint8_t rom_read(uint32_t addr, void *p) +uint8_t rom_read(uint32_t addr, void *p) { rom_t *rom = (rom_t *)p; #ifdef ROM_TRACE diff --git a/src/rom.h b/src/rom.h index 35b8ef78f..39016d69f 100644 --- a/src/rom.h +++ b/src/rom.h @@ -15,3 +15,7 @@ typedef struct rom_t int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, wchar_t *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags); + +uint8_t rom_read(uint32_t addr, void *p); +uint16_t rom_readw(uint32_t addr, void *p); +uint32_t rom_readl(uint32_t addr, void *p);