diff --git a/src/cpu/fpu.c b/src/cpu/fpu.c new file mode 100644 index 000000000..2d74b256a --- /dev/null +++ b/src/cpu/fpu.c @@ -0,0 +1,101 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * FPU type handler. + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" + + +#ifdef ENABLE_FPU_LOG +int fpu_do_log = ENABLE_FPU_LOG; + + +void +fpu_log(const char *fmt, ...) +{ + va_list ap; + + if (fpu_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define fpu_log(fmt, ...) +#endif + + +int +fpu_get_type(const cpu_family_t *cpu_family, int cpu, const char *internal_name) +{ + const CPU *cpu_s = &cpu_family->cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + int fpu_type = fpus[0].type; + int c = 0; + + while (fpus[c].internal_name) { + if (!strcmp(internal_name, fpus[c].internal_name)) + fpu_type = fpus[c].type; + c++; + } + + return fpu_type; +} + + +const char * +fpu_get_internal_name(const cpu_family_t *cpu_family, int cpu, int type) +{ + const CPU *cpu_s = &cpu_family->cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + int c = 0; + + while (fpus[c].internal_name) { + if (fpus[c].type == type) + return fpus[c].internal_name; + c++; + } + + return fpus[0].internal_name; +} + + +const char * +fpu_get_name_from_index(const cpu_family_t *cpu_family, int cpu, int c) +{ + const CPU *cpu_s = &cpu_family->cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + + return fpus[c].name; +} + + +int +fpu_get_type_from_index(const cpu_family_t *cpu_family, int cpu, int c) +{ + const CPU *cpu_s = &cpu_family->cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + + return fpus[c].type; +} diff --git a/src/cpu/x86.c b/src/cpu/x86.c new file mode 100644 index 000000000..321ebedda --- /dev/null +++ b/src/cpu/x86.c @@ -0,0 +1,315 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Functions common to all emulated x86 CPU's. + * + * Authors: Andrew Jenner, + * Miran Grca, + * + * Copyright 2015-2020 Andrew Jenner. + * Copyright 2016-2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include "x86.h" +#include <86box/machine.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/nmi.h> +#include <86box/pic.h> +#include <86box/ppi.h> +#include <86box/timer.h> + +/* The opcode of the instruction currently being executed. */ +uint8_t opcode; + +/* The tables to speed up the setting of the Z, N, and P cpu_state.flags. */ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ +uint16_t zero = 0; + +/* MOD and R/M stuff. */ +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; +uint32_t rmdat; + +/* XT CPU multiplier. */ +uint64_t xt_cpu_multi; + +/* Variables for handling the non-maskable interrupts. */ +int nmi = 0, nmi_auto_clear = 0; + +/* Was the CPU ever reset? */ +int x86_was_reset = 0; + +/* Is the TRAP flag on? */ +int trap = 0; + +/* The current effective address's segment. */ +uint32_t easeg; + + +#ifdef ENABLE_X86_LOG +void dumpregs(int); + +int x86_do_log = ENABLE_X86_LOG; +int indump = 0; + + +static void +x808x_log(const char *fmt, ...) +{ + va_list ap; + + if (x808x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} + + +void +dumpregs(int force) +{ + int c; + char *seg_names[4] = { "ES", "CS", "SS", "DS" }; + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) + return; + + x808x_log("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", + cpu_state.pc, CS, DS, ES, SS, cpu_state.flags); + x808x_log("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); + for (c = 0; c < 4; c++) { + x808x_log("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_names[c], _opseg[c]->base, _opseg[c]->limit, + _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->limit_high); + } + if (is386) { + x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_fs, cpu_state.seg_fs.limit, cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high); + x808x_log("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + gs, cpu_state.seg_gs.limit, cpu_state.seg_gs.access, cpu_state.seg_gs.limit_low, cpu_state.seg_gs.limit_high); + x808x_log("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); + x808x_log("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); + x808x_log("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); + x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + x808x_log("386 in %s mode: %i-bit data, %-i-bit stack\n", + (msw & 1) ? ((cpu_state.eflags & VM_FLAG) ? "V86" : "protected") : "real", + (use32) ? 32 : 16, (stack32) ? 32 : 16); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); + x808x_log("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n", + EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP); + } else { + x808x_log("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); + x808x_log("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n", + AX, BX, CX, DX, DI, SI, BP, SP); + } + x808x_log("Entries in readlookup : %i writelookup : %i\n", readlnum, writelnum); + x87_dumpregs(); + indump = 0; +} +#else +#define x808x_log(fmt, ...) +#endif + + +/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ +static void +makemod1table(void) +{ + mod1add[0][0] = &BX; + mod1add[0][1] = &BX; + mod1add[0][2] = &BP; + mod1add[0][3] = &BP; + mod1add[0][4] = &SI; + mod1add[0][5] = &DI; + mod1add[0][6] = &BP; + mod1add[0][7] = &BX; + mod1add[1][0] = &SI; + mod1add[1][1] = &DI; + mod1add[1][2] = &SI; + mod1add[1][3] = &DI; + mod1add[1][4] = &zero; + mod1add[1][5] = &zero; + mod1add[1][6] = &zero; + mod1add[1][7] = &zero; + mod1seg[0] = &ds; + mod1seg[1] = &ds; + mod1seg[2] = &ss; + mod1seg[3] = &ss; + mod1seg[4] = &ds; + mod1seg[5] = &ds; + mod1seg[6] = &ss; + mod1seg[7] = &ds; +} + + +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P cpu_state.flags. */ +static void +makeznptable(void) +{ + int c, d, e; + for (c = 0; c < 256; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable8[c] = 0; + else + znptable8[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); +#endif + if (!c) + znptable8[c] |= Z_FLAG; + if (c & 0x80) + znptable8[c] |= N_FLAG; + } + + for (c = 0; c < 65536; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable16[c] = 0; + else + znptable16[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) + x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); +#endif + if (!c) + znptable16[c] |= Z_FLAG; + if (c & 0x8000) + znptable16[c] |= N_FLAG; + } +} + + +/* Common reset function. */ +static void +reset_common(int hard) +{ + /* Make sure to gracefully leave SMM. */ + if (in_smm) + leave_smm(); + +#ifdef ENABLE_808X_LOG + if (hard) + x808x_log("x86 reset\n"); +#endif + + use32 = 0; + cpu_cur_status = 0; + stack32 = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw = 0; + if (hascache) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + cpu_state.eflags = 0; + cgate32 = 0; + if (is286) { + if (AT) { + loadcs(0xF000); + cpu_state.pc = 0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } else { + loadcs(0xFFFF); + cpu_state.pc = 0; + rammask = 0xfffff; + } + } + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + cpu_state.flags = 2; + trap = 0; + + EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; + + if (hard) { + makeznptable(); + resetreadlookup(); + makemod1table(); + cpu_set_edx(); + mmu_perm = 4; + } + x86seg_reset(); +#ifdef USE_DYNAREC + if (hard) + codegen_reset(); +#endif + if (!hard) + flushmmucache(); + x86_was_reset = 1; + cpu_alt_reset = 0; + + cpu_ven_reset(); + + in_smm = smi_latched = 0; + smi_line = smm_in_hlt = 0; + smi_block = 0; + + if (hard) { + smbase = is_am486 ? 0x00060000 : 0x00030000; + ppi_reset(); + } + in_sys = 0; + + shadowbios = shadowbios_write = 0; + alt_access = cpu_end_block_after_ins = 0; + + if (!is286) + reset_808x(hard); +} + + +/* Hard reset. */ +void +resetx86(void) +{ + reset_common(1); + + soft_reset_mask = 0; +} + + +/* Soft reset. */ +void +softresetx86(void) +{ + if (soft_reset_mask) + return; + + reset_common(0); +} diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 143b0bb60..d2126f299 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -1059,8 +1059,9 @@ write_output(atkbd_t *dev, uint8_t val) if ((dev->output_port ^ val) & 0x01) { /*Reset*/ if (! (val & 0x01)) { /* Pin 0 selected. */ - resetx86(); /*Pulse reset!*/ + softresetx86(); /*Pulse reset!*/ cpu_set_edx(); + smbase = is_am486 ? 0x00060000 : 0x00030000; } } /* Mask off the A20 stuff because we use mem_a20_key directly for that. */