Split the 286/386 interpreter away from the 486+ one (the 286/386 interpreter does not use the pccache's, readlookup's, and writelookup's as the emulated CPU's are too slow for them to be required, and also has more accurate FPU timings), also added a LPT status read function for future-proofing.

This commit is contained in:
OBattler
2023-08-08 19:39:52 +02:00
parent 5f72dc7d56
commit b1c5cbaf47
23 changed files with 3759 additions and 144 deletions

View File

@@ -12,17 +12,22 @@
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include "x86.h"
#include "x86_ops.h"
#include "x87.h"
#include <86box/io.h>
#include <86box/nmi.h>
#include <86box/mem.h>
#include <86box/pic.h>
#include <86box/timer.h>
#include <86box/pit.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/machine.h>
#include <86box/gdbstub.h>
#ifndef OPS_286_386
#define OPS_286_386
#endif
#include "386_common.h"
#ifdef USE_NEW_DYNAREC
# include "codegen.h"
@@ -33,54 +38,7 @@
extern int codegen_flags_changed;
int tempc, oldcpl, optype, inttype, oddeven = 0;
int timetolive;
uint16_t oldcs;
uint32_t oldds, oldss, olddslimit, oldsslimit,
olddslimitw, oldsslimitw;
uint32_t oxpc;
uint32_t rmdat32;
uint32_t backupregs[16];
x86seg _oldds;
#if 1
int opcode_length[256] = { 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, /* 0x0x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x1x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x2x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x3x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x4x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x5x */
1, 1, 3, 3, 1, 1, 1, 1, 3, 3, 2, 3, 1, 1, 1, 1, /* 0x6x */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x7x */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x8x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, /* 0x9x */
3, 3, 3, 3, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, /* 0xax */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xbx */
3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 3, 1, 1, 2, 1, 1, /* 0xcx */
3, 3, 3, 3, 2, 2, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xdx */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 1, 1, 1, 1, /* 0xex */
1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3 }; /* 0xfx */
#else
int opcode_length[256] = { 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, /* 0x0x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x1x */
3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 1, /* 0x2x */
3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 1, /* 0x3x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x4x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x5x */
1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 1, 1, 1, 1, /* 0x6x */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x7x */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x8x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, /* 0x9x */
3, 3, 3, 3, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, /* 0xax */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xbx */
3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 3, 1, 1, 2, 1, 1, /* 0xcx */
3, 3, 3, 3, 2, 2, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xdx */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 1, 1, 1, 1, /* 0xex */
3, 1, 3, 3, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3 }; /* 0xfx */
#endif
static int fpu_cycles = 0;
#ifdef ENABLE_386_LOG
int x386_do_log = ENABLE_386_LOG;
@@ -103,9 +61,6 @@ x386_log(const char *fmt, ...)
#undef CPU_BLOCK_END
#define CPU_BLOCK_END()
#include "x86_flags.h"
/*
#define getbytef() \
((uint8_t) (fetchdat)); \
cpu_state.pc++
@@ -118,11 +73,141 @@ x386_log(const char *fmt, ...)
#define getword2f() \
((uint16_t) (fetchdat >> 8)); \
cpu_state.pc += 2
*/
#define OP_TABLE(name) ops_##name
static __inline void
fetch_ea_32_long(uint32_t rmdat)
{
eal_r = eal_w = NULL;
easeg = cpu_state.ea_seg->base;
if (cpu_rm == 4) {
uint8_t sib = rmdat >> 8;
#if 0
switch (cpu_mod) {
case 0:
cpu_state.eaaddr = cpu_state.regs[sib & 7].l;
cpu_state.pc++;
break;
case 1:
cpu_state.pc++;
cpu_state.eaaddr = ((uint32_t) (int8_t) getbyte()) + cpu_state.regs[sib & 7].l;
break;
case 2:
cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l;
cpu_state.pc += 5;
break;
}
/*SIB byte present*/
if ((sib & 7) == 5 && !cpu_mod)
cpu_state.eaaddr = getlong();
else if ((sib & 6) == 4 && !cpu_state.ssegs) {
easeg = ss;
cpu_state.ea_seg = &cpu_state.seg_ss;
}
if (((sib >> 3) & 7) != 4)
cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6);
} else {
cpu_state.eaaddr = cpu_state.regs[cpu_rm].l;
if (cpu_mod) {
if (cpu_rm == 5 && !cpu_state.ssegs) {
easeg = ss;
cpu_state.ea_seg = &cpu_state.seg_ss;
}
if (cpu_mod == 1) {
cpu_state.eaaddr += ((uint32_t) (int8_t) (rmdat >> 8));
cpu_state.pc++;
} else {
cpu_state.eaaddr += getlong();
}
} else if (cpu_rm == 5) {
cpu_state.eaaddr = getlong();
}
}
if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) {
uint32_t addr = easeg + cpu_state.eaaddr;
if (readlookup2[addr >> 12] != (uintptr_t) -1)
eal_r = (uint32_t *) (readlookup2[addr >> 12] + addr);
if (writelookup2[addr >> 12] != (uintptr_t) -1)
eal_w = (uint32_t *) (writelookup2[addr >> 12] + addr);
}
}
static __inline void
fetch_ea_16_long(uint32_t rmdat)
{
eal_r = eal_w = NULL;
easeg = cpu_state.ea_seg->base;
if (!cpu_mod && cpu_rm == 6) {
cpu_state.eaaddr = getword();
} else {
switch (cpu_mod) {
case 0:
cpu_state.eaaddr = 0;
break;
case 1:
cpu_state.eaaddr = (uint16_t) (int8_t) (rmdat >> 8);
cpu_state.pc++;
break;
case 2:
cpu_state.eaaddr = getword();
break;
}
cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]);
if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) {
easeg = ss;
cpu_state.ea_seg = &cpu_state.seg_ss;
}
cpu_state.eaaddr &= 0xFFFF;
}
if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) {
uint32_t addr = easeg + cpu_state.eaaddr;
if (readlookup2[addr >> 12] != (uintptr_t) -1)
eal_r = (uint32_t *) (readlookup2[addr >> 12] + addr);
if (writelookup2[addr >> 12] != (uintptr_t) -1)
eal_w = (uint32_t *) (writelookup2[addr >> 12] + addr);
}
}
#define fetch_ea_16(rmdat) \
cpu_state.pc++; \
cpu_mod = (rmdat >> 6) & 3; \
cpu_reg = (rmdat >> 3) & 7; \
cpu_rm = rmdat & 7; \
if (cpu_mod != 3) { \
fetch_ea_16_long(rmdat); \
if (cpu_state.abrt) \
return 1; \
}
#define fetch_ea_32(rmdat) \
cpu_state.pc++; \
cpu_mod = (rmdat >> 6) & 3; \
cpu_reg = (rmdat >> 3) & 7; \
cpu_rm = rmdat & 7; \
if (cpu_mod != 3) { \
fetch_ea_32_long(rmdat); \
} \
if (cpu_state.abrt) \
return 1
#include "x86_flags.h"
#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32) \
do { \
if (cpu_prefetch_cycles) \
prefetch_run(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32); \
} while (0)
#define PREFETCH_PREFIX() \
do { \
if (cpu_prefetch_cycles) \
prefetch_prefixes++; \
} while (0)
#define PREFETCH_FLUSH() prefetch_flush()
#ifndef FPU_CYCLES
#define FPU_CYCLES
#endif
#define OP_TABLE(name) ops_2386_##name
# define CLOCK_CYCLES(c) \
{ \
if (fpu_cycles > 0) { \
@@ -137,18 +222,13 @@ x386_log(const char *fmt, ...)
# define CLOCK_CYCLES_FPU(c) cycles -= (c)
# define CONCURRENCY_CYCLES(c) fpu_cycles = (c)
#else
# define CLOCK_CYCLES(c) cycles -= (c)
# define CLOCK_CYCLES_FPU(c) cycles -= (c)
# define CONCURRENCY_CYCLES(c)
#endif
#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c)
#include "x86_ops.h"
#include "386_ops.h"
void
exec386(int cycs)
exec386_2386(int cycs)
{
int vector, tempi, cycdiff, oldcyc;
int cycle_period, ins_cycles;
@@ -184,7 +264,7 @@ exec386(int cycs)
if (!cpu_state.abrt) {
#ifdef ENABLE_386_LOG
if (in_smm)
x386_log("[%04X:%08X] %08X\n", CS, cpu_state.pc, fetchdat);
x386_2386_log("[%04X:%08X] %08X\n", CS, cpu_state.pc, fetchdat);
#endif
opcode = fetchdat & 0xFF;
fetchdat >>= 8;

View File

@@ -67,6 +67,38 @@ int soft_reset_mask = 0;
int smi_latched = 0;
int smm_in_hlt = 0, smi_block = 0;
int prefetch_prefixes = 0;
int tempc, oldcpl, optype, inttype, oddeven = 0;
int timetolive;
uint16_t oldcs;
uint32_t oldds, oldss, olddslimit, oldsslimit,
olddslimitw, oldsslimitw;
uint32_t oxpc;
uint32_t rmdat32;
uint32_t backupregs[16];
x86seg _oldds;
int opcode_length[256] = { 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, /* 0x0x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x1x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x2x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x3x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x4x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x5x */
1, 1, 3, 3, 1, 1, 1, 1, 3, 3, 2, 3, 1, 1, 1, 1, /* 0x6x */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x7x */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x8x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, /* 0x9x */
3, 3, 3, 3, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, /* 0xax */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xbx */
3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 3, 1, 1, 2, 1, 1, /* 0xcx */
3, 3, 3, 3, 2, 2, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xdx */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 1, 1, 1, 1, /* 0xex */
1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3 }; /* 0xfx */
uint32_t addr64, addr64_2;
uint32_t addr64a[8], addr64a_2[8];
@@ -321,6 +353,77 @@ x386_common_log(const char *fmt, ...)
# define x386_common_log(fmt, ...)
#endif
/*Prefetch emulation is a fairly simplistic model:
- All instruction bytes must be fetched before it starts.
- Cycles used for non-instruction memory accesses are counted and subtracted
from the total cycles taken
- Any remaining cycles are used to refill the prefetch queue.
Note that this is only used for 286 / 386 systems. It is disabled when the
internal cache on 486+ CPUs is enabled.
*/
static int prefetch_bytes = 0;
void
prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int reads_l, int writes, int writes_l, int ea32)
{
int mem_cycles = reads * cpu_cycles_read + reads_l * cpu_cycles_read_l + writes * cpu_cycles_write + writes_l * cpu_cycles_write_l;
if (instr_cycles < mem_cycles)
instr_cycles = mem_cycles;
prefetch_bytes -= prefetch_prefixes;
prefetch_bytes -= bytes;
if (modrm != -1) {
if (ea32) {
if ((modrm & 7) == 4) {
if ((modrm & 0x700) == 0x500)
prefetch_bytes -= 5;
else if ((modrm & 0xc0) == 0x40)
prefetch_bytes -= 2;
else if ((modrm & 0xc0) == 0x80)
prefetch_bytes -= 5;
} else {
if ((modrm & 0xc7) == 0x05)
prefetch_bytes -= 4;
else if ((modrm & 0xc0) == 0x40)
prefetch_bytes--;
else if ((modrm & 0xc0) == 0x80)
prefetch_bytes -= 4;
}
} else {
if ((modrm & 0xc7) == 0x06)
prefetch_bytes -= 2;
else if ((modrm & 0xc0) != 0xc0)
prefetch_bytes -= ((modrm & 0xc0) >> 6);
}
}
/* Fill up prefetch queue */
while (prefetch_bytes < 0) {
prefetch_bytes += cpu_prefetch_width;
cycles -= cpu_prefetch_cycles;
}
/* Subtract cycles used for memory access by instruction */
instr_cycles -= mem_cycles;
while (instr_cycles >= cpu_prefetch_cycles) {
prefetch_bytes += cpu_prefetch_width;
instr_cycles -= cpu_prefetch_cycles;
}
prefetch_prefixes = 0;
if (prefetch_bytes > 16)
prefetch_bytes = 16;
}
void
prefetch_flush(void)
{
prefetch_bytes = 0;
}
static __inline void
set_stack32(int s)
{

View File

@@ -22,6 +22,34 @@
#include <stddef.h>
#include <inttypes.h>
#ifdef OPS_286_386
#define readmemb_n(s,a,b) readmembl_no_mmut_2386((s)+(a),b)
#define readmemw_n(s,a,b) readmemwl_no_mmut_2386((s)+(a),b)
#define readmeml_n(s,a,b) readmemll_no_mmut_2386((s)+(a),b)
#define readmemb(s,a) readmembl_2386((s)+(a))
#define readmemw(s,a) readmemwl_2386((s)+(a))
#define readmeml(s,a) readmemll_2386((s)+(a))
#define readmemq(s,a) readmemql_2386((s)+(a))
#define writememb_n(s,a,b,v) writemembl_no_mmut_2386((s)+(a),b,v)
#define writememw_n(s,a,b,v) writememwl_no_mmut_2386((s)+(a),b,v)
#define writememl_n(s,a,b,v) writememll_no_mmut_2386((s)+(a),b,v)
#define writememb(s,a,v) writemembl_2386((s)+(a),v)
#define writememw(s,a,v) writememwl_2386((s)+(a),v)
#define writememl(s,a,v) writememll_2386((s)+(a),v)
#define writememq(s,a,v) writememql_2386((s)+(a),v)
#define do_mmut_rb(s,a,b) do_mmutranslate_2386((s)+(a), b, 1, 0)
#define do_mmut_rw(s,a,b) do_mmutranslate_2386((s)+(a), b, 2, 0)
#define do_mmut_rl(s,a,b) do_mmutranslate_2386((s)+(a), b, 4, 0)
#define do_mmut_rb2(s,a,b) do_mmutranslate_2386((s)+(a), b, 1, 0)
#define do_mmut_rw2(s,a,b) do_mmutranslate_2386((s)+(a), b, 2, 0)
#define do_mmut_rl2(s,a,b) do_mmutranslate_2386((s)+(a), b, 4, 0)
#define do_mmut_wb(s,a,b) do_mmutranslate_2386((s)+(a), b, 1, 1)
#define do_mmut_ww(s,a,b) do_mmutranslate_2386((s)+(a), b, 2, 1)
#define do_mmut_wl(s,a,b) do_mmutranslate_2386((s)+(a), b, 4, 1)
#else
#define readmemb_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) ? readmembl_no_mmut((s) + (a), b) : *(uint8_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))))
#define readmemw_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) ? readmemwl_no_mmut((s) + (a), b) : *(uint16_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a))))
#define readmeml_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) ? readmemll_no_mmut((s) + (a), b) : *(uint32_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a))))
@@ -97,6 +125,7 @@
#define do_mmut_wl(s, a, b) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) \
do_mmutranslate((s) + (a), b, 4, 1)
#endif
int checkio(uint32_t port, int mask);
@@ -191,6 +220,23 @@ int checkio(uint32_t port, int mask);
return 1; \
}
#ifdef OPS_286_386
/* TODO: Introduce functions to read exec. */
static __inline uint8_t fastreadb(uint32_t a)
{
return readmembl(a);
}
static __inline uint16_t fastreadw(uint32_t a)
{
return readmemwl(a);
}
static __inline uint32_t fastreadl(uint32_t a)
{
return readmemll(a);
}
#else
static __inline uint8_t
fastreadb(uint32_t a)
{
@@ -266,6 +312,7 @@ fastreadl(uint32_t a)
val |= (fastreadw(a + 2) << 16);
return val;
}
#endif
static __inline void *
get_ram_ptr(uint32_t a)
@@ -288,6 +335,37 @@ get_ram_ptr(uint32_t a)
extern int opcode_length[256];
#ifdef OPS_286_386
static __inline uint16_t
fastreadw_fetch(uint32_t a)
{
uint16_t val;
if ((a & 0xFFF) > 0xFFE) {
val = fastreadb(a);
if (opcode_length[val & 0xff] > 1)
val |= (fastreadb(a + 1) << 8);
return val;
}
return readmemwl(a);
}
static __inline uint32_t
fastreadl_fetch(uint32_t a)
{
uint32_t val;
if ((a & 0xFFF) > 0xFFC) {
val = fastreadw_fetch(a);
if (opcode_length[val & 0xff] > 2)
val |= (fastreadw(a + 2) << 16);
return val;
}
return readmemll(a);
}
#else
static __inline uint16_t
fastreadw_fetch(uint32_t a)
{
@@ -342,6 +420,7 @@ fastreadl_fetch(uint32_t a)
val |= (fastreadw(a + 2) << 16);
return val;
}
#endif
static __inline uint8_t
getbyte(void)
@@ -371,6 +450,67 @@ getquad(void)
return fastreadl(cs + (cpu_state.pc - 8)) | ((uint64_t) fastreadl(cs + (cpu_state.pc - 4)) << 32);
}
#ifdef OPS_286_386
static __inline uint8_t geteab()
{
if (cpu_mod == 3)
return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm&3].b.l;
return readmemb(easeg, cpu_state.eaaddr);
}
static __inline uint16_t geteaw()
{
if (cpu_mod == 3)
return cpu_state.regs[cpu_rm].w;
return readmemw(easeg, cpu_state.eaaddr);
}
static __inline uint32_t geteal()
{
if (cpu_mod == 3)
return cpu_state.regs[cpu_rm].l;
return readmeml(easeg, cpu_state.eaaddr);
}
static __inline uint64_t geteaq()
{
return readmemq(easeg, cpu_state.eaaddr);
}
static __inline uint8_t geteab_mem()
{
return readmemb(easeg,cpu_state.eaaddr);
}
static __inline uint16_t geteaw_mem()
{
return readmemw(easeg,cpu_state.eaaddr);
}
static __inline uint32_t geteal_mem()
{
return readmeml(easeg,cpu_state.eaaddr);
}
static __inline int seteaq_cwc(void)
{
CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr);
return 0;
}
static __inline void seteaq(uint64_t v)
{
if (seteaq_cwc())
return;
writememql(easeg + cpu_state.eaaddr, v);
}
#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); writemembl_2386(easeg+cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v
#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); writememwl_2386(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v
#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); writememll_2386(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v
#define seteab_mem(v) writemembl_2386(easeg+cpu_state.eaaddr,v);
#define seteaw_mem(v) writememwl_2386(easeg+cpu_state.eaaddr,v);
#define seteal_mem(v) writememll_2386(easeg+cpu_state.eaaddr,v);
#else
static __inline uint8_t
geteab(void)
{
@@ -489,6 +629,7 @@ seteaq(uint64_t v)
*eal_w = v; \
else \
writememll(easeg + cpu_state.eaaddr, v);
#endif
#define getbytef() \
((uint8_t) (fetchdat)); \

View File

@@ -183,78 +183,6 @@ fetch_ea_16_long(uint32_t rmdat)
#include "x86_flags.h"
/*Prefetch emulation is a fairly simplistic model:
- All instruction bytes must be fetched before it starts.
- Cycles used for non-instruction memory accesses are counted and subtracted
from the total cycles taken
- Any remaining cycles are used to refill the prefetch queue.
Note that this is only used for 286 / 386 systems. It is disabled when the
internal cache on 486+ CPUs is enabled.
*/
static int prefetch_bytes = 0;
static int prefetch_prefixes = 0;
static void
prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int reads_l, int writes, int writes_l, int ea32)
{
int mem_cycles = reads * cpu_cycles_read + reads_l * cpu_cycles_read_l + writes * cpu_cycles_write + writes_l * cpu_cycles_write_l;
if (instr_cycles < mem_cycles)
instr_cycles = mem_cycles;
prefetch_bytes -= prefetch_prefixes;
prefetch_bytes -= bytes;
if (modrm != -1) {
if (ea32) {
if ((modrm & 7) == 4) {
if ((modrm & 0x700) == 0x500)
prefetch_bytes -= 5;
else if ((modrm & 0xc0) == 0x40)
prefetch_bytes -= 2;
else if ((modrm & 0xc0) == 0x80)
prefetch_bytes -= 5;
} else {
if ((modrm & 0xc7) == 0x05)
prefetch_bytes -= 4;
else if ((modrm & 0xc0) == 0x40)
prefetch_bytes--;
else if ((modrm & 0xc0) == 0x80)
prefetch_bytes -= 4;
}
} else {
if ((modrm & 0xc7) == 0x06)
prefetch_bytes -= 2;
else if ((modrm & 0xc0) != 0xc0)
prefetch_bytes -= ((modrm & 0xc0) >> 6);
}
}
/* Fill up prefetch queue */
while (prefetch_bytes < 0) {
prefetch_bytes += cpu_prefetch_width;
cycles -= cpu_prefetch_cycles;
}
/* Subtract cycles used for memory access by instruction */
instr_cycles -= mem_cycles;
while (instr_cycles >= cpu_prefetch_cycles) {
prefetch_bytes += cpu_prefetch_width;
instr_cycles -= cpu_prefetch_cycles;
}
prefetch_prefixes = 0;
if (prefetch_bytes > 16)
prefetch_bytes = 16;
}
static void
prefetch_flush(void)
{
prefetch_bytes = 0;
}
#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32) \
do { \
if (cpu_prefetch_cycles) \
@@ -858,3 +786,156 @@ exec386_dynarec(int cycs)
}
}
#endif
void
exec386(int cycs)
{
int vector, tempi, cycdiff, oldcyc;
int cycle_period, ins_cycles;
uint32_t addr;
cycles += cycs;
while (cycles > 0) {
cycle_period = (timer_target - (uint32_t) tsc) + 1;
x86_was_reset = 0;
cycdiff = 0;
oldcyc = cycles;
while (cycdiff < cycle_period) {
ins_cycles = cycles;
#ifndef USE_NEW_DYNAREC
oldcs = CS;
oldcpl = CPL;
#endif
cpu_state.oldpc = cpu_state.pc;
cpu_state.op32 = use32;
#ifndef USE_NEW_DYNAREC
x86_was_reset = 0;
#endif
cpu_state.ea_seg = &cpu_state.seg_ds;
cpu_state.ssegs = 0;
fetchdat = fastreadl_fetch(cs + cpu_state.pc);
if (!cpu_state.abrt) {
#ifdef ENABLE_386_LOG
if (in_smm)
x386_dynarec_log("[%04X:%08X] %08X\n", CS, cpu_state.pc, fetchdat);
#endif
opcode = fetchdat & 0xFF;
fetchdat >>= 8;
trap = cpu_state.flags & T_FLAG;
cpu_state.pc++;
x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
if (x86_was_reset)
break;
}
#ifdef ENABLE_386_LOG
else if (in_smm)
x386_dynarec_log("[%04X:%08X] ABRT\n", CS, cpu_state.pc);
#endif
#ifndef USE_NEW_DYNAREC
if (!use32)
cpu_state.pc &= 0xffff;
#endif
if (cpu_end_block_after_ins)
cpu_end_block_after_ins--;
if (cpu_state.abrt) {
flags_rebuild();
tempi = cpu_state.abrt & ABRT_MASK;
cpu_state.abrt = 0;
x86_doabrt(tempi);
if (cpu_state.abrt) {
cpu_state.abrt = 0;
#ifndef USE_NEW_DYNAREC
CS = oldcs;
#endif
cpu_state.pc = cpu_state.oldpc;
x386_dynarec_log("Double fault\n");
pmodeint(8, 0);
if (cpu_state.abrt) {
cpu_state.abrt = 0;
softresetx86();
cpu_set_edx();
#ifdef ENABLE_386_LOG
x386_dynarec_log("Triple fault - reset\n");
#endif
}
}
} else if (trap) {
flags_rebuild();
trap = 0;
#ifndef USE_NEW_DYNAREC
oldcs = CS;
#endif
cpu_state.oldpc = cpu_state.pc;
dr[6] |= 0x4000;
x86_int(1);
}
if (smi_line)
enter_smm_check(0);
else if (nmi && nmi_enable && nmi_mask) {
#ifndef USE_NEW_DYNAREC
oldcs = CS;
#endif
cpu_state.oldpc = cpu_state.pc;
x86_int(2);
nmi_enable = 0;
#ifdef OLD_NMI_BEHAVIOR
if (nmi_auto_clear) {
nmi_auto_clear = 0;
nmi = 0;
}
#else
nmi = 0;
#endif
} else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins) {
vector = picinterrupt();
if (vector != -1) {
flags_rebuild();
if (msw & 1)
pmodeint(vector, 0);
else {
writememw(ss, (SP - 2) & 0xFFFF, cpu_state.flags);
writememw(ss, (SP - 4) & 0xFFFF, CS);
writememw(ss, (SP - 6) & 0xFFFF, cpu_state.pc);
SP -= 6;
addr = (vector << 2) + idt.base;
cpu_state.flags &= ~I_FLAG;
cpu_state.flags &= ~T_FLAG;
cpu_state.pc = readmemw(0, addr);
loadcs(readmemw(0, addr + 2));
}
}
}
ins_cycles -= cycles;
tsc += ins_cycles;
cycdiff = oldcyc - cycles;
if (timetolive) {
timetolive--;
if (!timetolive)
fatal("Life expired\n");
}
if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc))
timer_process_inline();
#ifdef USE_GDBSTUB
if (gdbstub_instruction())
return;
#endif
}
}
}

View File

@@ -179,7 +179,9 @@ extern void x386_dynarec_log(const char *fmt, ...);
#include "x86_ops_bcd.h"
#include "x86_ops_bit.h"
#include "x86_ops_bitscan.h"
#ifndef OPS_286_386
#include "x86_ops_cyrix.h"
#endif
#include "x86_ops_flag.h"
#include "x86_ops_fpu.h"
#include "x86_ops_inc_dec.h"
@@ -188,6 +190,7 @@ extern void x386_dynarec_log(const char *fmt, ...);
#include "x86_ops_jump.h"
#include "x86_ops_misc.h"
#include "x87_ops.h"
#ifndef OPS_286_386
#include "x86_ops_i686.h"
#include "x86_ops_mmx.h"
#include "x86_ops_mmx_arith.h"
@@ -196,30 +199,44 @@ extern void x386_dynarec_log(const char *fmt, ...);
#include "x86_ops_mmx_mov.h"
#include "x86_ops_mmx_pack.h"
#include "x86_ops_mmx_shift.h"
#endif
#include "x86_ops_mov.h"
#include "x86_ops_mov_ctrl.h"
#include "x86_ops_mov_seg.h"
#include "x86_ops_movx.h"
#ifndef OPS_286_386
#include "x86_ops_msr.h"
#endif
#include "x86_ops_mul.h"
#include "x86_ops_pmode.h"
#include "x86_ops_prefix.h"
#ifdef IS_DYNAREC
# include "x86_ops_rep_dyn.h"
#else
#ifdef OPS_286_386
# include "x86_ops_rep_2386.h"
#else
# include "x86_ops_rep.h"
#endif
#endif
#include "x86_ops_ret.h"
#include "x86_ops_set.h"
#include "x86_ops_stack.h"
#ifdef OPS_286_386
#include "x86_ops_string_2386.h"
#else
#include "x86_ops_string.h"
#endif
#include "x86_ops_xchg.h"
#include "x86_ops_call.h"
#include "x86_ops_shift.h"
#ifndef OPS_286_386
#include "x86_ops_amd.h"
#include "x86_ops_3dnow.h"
#endif
#include <time.h>
#ifndef OPS_286_386
static int
opVPCEXT(uint32_t fetchdat)
{
@@ -331,7 +348,50 @@ opVPCEXT(uint32_t fetchdat)
return 1;
}
#endif
#ifdef OPS_286_386
static int op0F_w_a16(uint32_t fetchdat)
{
int opcode = fetchdat & 0xff;
fopcode = opcode;
cpu_state.pc++;
PREFETCH_PREFIX();
return x86_2386_opcodes_0f[opcode](fetchdat >> 8);
}
static int op0F_l_a16(uint32_t fetchdat)
{
int opcode = fetchdat & 0xff;
fopcode = opcode;
cpu_state.pc++;
PREFETCH_PREFIX();
return x86_2386_opcodes_0f[opcode | 0x100](fetchdat >> 8);
}
static int op0F_w_a32(uint32_t fetchdat)
{
int opcode = fetchdat & 0xff;
fopcode = opcode;
cpu_state.pc++;
PREFETCH_PREFIX();
return x86_2386_opcodes_0f[opcode | 0x200](fetchdat >> 8);
}
static int op0F_l_a32(uint32_t fetchdat)
{
int opcode = fetchdat & 0xff;
fopcode = opcode;
cpu_state.pc++;
PREFETCH_PREFIX();
return x86_2386_opcodes_0f[opcode | 0x300](fetchdat >> 8);
}
#else
static int
op0F_w_a16(uint32_t fetchdat)
{
@@ -376,6 +436,7 @@ op0F_l_a32(uint32_t fetchdat)
return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8);
}
#endif
const OpFn OP_TABLE(186_0f)[1024] = {
// clang-format off
@@ -745,6 +806,7 @@ const OpFn OP_TABLE(486_0f)[1024] = {
// clang-format on
};
#ifndef OPS_286_386
const OpFn OP_TABLE(c486_0f)[1024] = {
// clang-format off
/*16-bit data, 16-bit addr*/
@@ -928,6 +990,7 @@ const OpFn OP_TABLE(stpc_0f)[1024] = {
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
// clang-format on
};
#endif
const OpFn OP_TABLE(ibm486_0f)[1024] = {
// clang-format off
@@ -1021,6 +1084,7 @@ const OpFn OP_TABLE(ibm486_0f)[1024] = {
// clang-format on
};
#ifndef OPS_286_386
const OpFn OP_TABLE(winchip_0f)[1024] = {
// clang-format off
/*16-bit data, 16-bit addr*/
@@ -2128,6 +2192,7 @@ const OpFn OP_TABLE(186)[1024] = {
/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16,
// clang-format on
};
#endif
const OpFn OP_TABLE(286)[1024] = {
// clang-format off

View File

@@ -126,6 +126,27 @@ const OpFn *x86_opcodes_REPE;
const OpFn *x86_opcodes_REPNE;
const OpFn *x86_opcodes_3DNOW;
const OpFn *x86_2386_opcodes;
const OpFn *x86_2386_opcodes_0f;
const OpFn *x86_2386_opcodes_d8_a16;
const OpFn *x86_2386_opcodes_d8_a32;
const OpFn *x86_2386_opcodes_d9_a16;
const OpFn *x86_2386_opcodes_d9_a32;
const OpFn *x86_2386_opcodes_da_a16;
const OpFn *x86_2386_opcodes_da_a32;
const OpFn *x86_2386_opcodes_db_a16;
const OpFn *x86_2386_opcodes_db_a32;
const OpFn *x86_2386_opcodes_dc_a16;
const OpFn *x86_2386_opcodes_dc_a32;
const OpFn *x86_2386_opcodes_dd_a16;
const OpFn *x86_2386_opcodes_dd_a32;
const OpFn *x86_2386_opcodes_de_a16;
const OpFn *x86_2386_opcodes_de_a32;
const OpFn *x86_2386_opcodes_df_a16;
const OpFn *x86_2386_opcodes_df_a32;
const OpFn *x86_2386_opcodes_REPE;
const OpFn *x86_2386_opcodes_REPNE;
uint16_t cpu_fast_off_count;
uint16_t cpu_fast_off_val;
uint16_t temp_seg_data[4] = { 0, 0, 0, 0 };
@@ -536,8 +557,11 @@ cpu_set(void)
#else
x86_setopcodes(ops_386, ops_386_0f);
#endif
x86_setopcodes_2386(ops_2386_386, ops_2386_386_0f);
x86_opcodes_REPE = ops_REPE;
x86_opcodes_REPNE = ops_REPNE;
x86_2386_opcodes_REPE = ops_2386_REPE;
x86_2386_opcodes_REPNE = ops_2386_REPNE;
x86_opcodes_3DNOW = ops_3DNOW;
#ifdef USE_DYNAREC
x86_dynarec_opcodes_REPE = dynarec_ops_REPE;
@@ -600,6 +624,23 @@ cpu_set(void)
x86_opcodes_de_a32 = ops_sf_fpu_de_a32;
x86_opcodes_df_a16 = ops_sf_fpu_df_a16;
x86_opcodes_df_a32 = ops_sf_fpu_df_a32;
x86_2386_opcodes_d8_a16 = ops_2386_sf_fpu_d8_a16;
x86_2386_opcodes_d8_a32 = ops_2386_sf_fpu_d8_a32;
x86_2386_opcodes_d9_a16 = ops_2386_sf_fpu_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_sf_fpu_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_sf_fpu_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_sf_fpu_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_sf_fpu_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_sf_fpu_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_sf_fpu_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_sf_fpu_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_sf_fpu_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_sf_fpu_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_sf_fpu_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_sf_fpu_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_sf_fpu_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_sf_fpu_df_a32;
} else {
x86_opcodes_d8_a16 = ops_fpu_d8_a16;
x86_opcodes_d8_a32 = ops_fpu_d8_a32;
@@ -617,6 +658,23 @@ cpu_set(void)
x86_opcodes_de_a32 = ops_fpu_de_a32;
x86_opcodes_df_a16 = ops_fpu_df_a16;
x86_opcodes_df_a32 = ops_fpu_df_a32;
x86_2386_opcodes_d8_a16 = ops_2386_fpu_d8_a16;
x86_2386_opcodes_d8_a32 = ops_2386_fpu_d8_a32;
x86_2386_opcodes_d9_a16 = ops_2386_fpu_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_fpu_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_fpu_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_fpu_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_fpu_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_fpu_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_fpu_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_fpu_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_fpu_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_fpu_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_fpu_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_fpu_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_fpu_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_fpu_df_a32;
}
} else {
#ifdef USE_DYNAREC
@@ -653,6 +711,23 @@ cpu_set(void)
x86_opcodes_de_a32 = ops_nofpu_a32;
x86_opcodes_df_a16 = ops_nofpu_a16;
x86_opcodes_df_a32 = ops_nofpu_a32;
x86_2386_opcodes_d8_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_d8_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_d9_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_d9_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_da_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_da_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_db_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_db_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_dc_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_dc_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_dd_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_dd_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_de_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_de_a32 = ops_2386_nofpu_a32;
x86_2386_opcodes_df_a16 = ops_2386_nofpu_a16;
x86_2386_opcodes_df_a32 = ops_2386_nofpu_a32;
}
#ifdef USE_DYNAREC
@@ -679,6 +754,7 @@ cpu_set(void)
#else
x86_setopcodes(ops_186, ops_186_0f);
#endif
x86_setopcodes_2386(ops_2386_286, ops_2386_286_0f);
break;
case CPU_286:
@@ -737,6 +813,21 @@ cpu_set(void)
x86_opcodes_de_a32 = ops_sf_fpu_287_de_a32;
x86_opcodes_df_a16 = ops_sf_fpu_287_df_a16;
x86_opcodes_df_a32 = ops_sf_fpu_287_df_a32;
x86_2386_opcodes_d9_a16 = ops_2386_sf_fpu_287_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_sf_fpu_287_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_sf_fpu_287_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_sf_fpu_287_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_sf_fpu_287_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_sf_fpu_287_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_sf_fpu_287_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_sf_fpu_287_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_sf_fpu_287_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_sf_fpu_287_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_sf_fpu_287_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_sf_fpu_287_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_sf_fpu_287_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_sf_fpu_287_df_a32;
} else {
x86_opcodes_d9_a16 = ops_fpu_287_d9_a16;
x86_opcodes_d9_a32 = ops_fpu_287_d9_a32;
@@ -752,6 +843,21 @@ cpu_set(void)
x86_opcodes_de_a32 = ops_fpu_287_de_a32;
x86_opcodes_df_a16 = ops_fpu_287_df_a16;
x86_opcodes_df_a32 = ops_fpu_287_df_a32;
x86_2386_opcodes_d9_a16 = ops_2386_fpu_287_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_fpu_287_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_fpu_287_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_fpu_287_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_fpu_287_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_fpu_287_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_fpu_287_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_fpu_287_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_fpu_287_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_fpu_287_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_fpu_287_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_fpu_287_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_fpu_287_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_fpu_287_df_a32;
}
}
@@ -794,11 +900,13 @@ cpu_set(void)
#else
x86_setopcodes(ops_386, ops_ibm486_0f);
#endif
x86_setopcodes_2386(ops_2386_386, ops_2386_ibm486_0f);
cpu_features = CPU_FEATURE_MSR;
/* FALLTHROUGH */
case CPU_386SX:
case CPU_386DX:
if (fpu_type == FPU_287) { /* In case we get Deskpro 386 emulation */
/* In case we get Deskpro 386 emulation */
if (fpu_type == FPU_287) {
#ifdef USE_DYNAREC
if (fpu_softfloat) {
x86_dynarec_opcodes_d9_a16 = dynarec_ops_sf_fpu_287_d9_a16;
@@ -847,6 +955,21 @@ cpu_set(void)
x86_opcodes_de_a32 = ops_sf_fpu_287_de_a32;
x86_opcodes_df_a16 = ops_sf_fpu_287_df_a16;
x86_opcodes_df_a32 = ops_sf_fpu_287_df_a32;
x86_2386_opcodes_d9_a16 = ops_2386_sf_fpu_287_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_sf_fpu_287_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_sf_fpu_287_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_sf_fpu_287_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_sf_fpu_287_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_sf_fpu_287_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_sf_fpu_287_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_sf_fpu_287_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_sf_fpu_287_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_sf_fpu_287_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_sf_fpu_287_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_sf_fpu_287_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_sf_fpu_287_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_sf_fpu_287_df_a32;
} else {
x86_opcodes_d9_a16 = ops_fpu_287_d9_a16;
x86_opcodes_d9_a32 = ops_fpu_287_d9_a32;
@@ -862,6 +985,21 @@ cpu_set(void)
x86_opcodes_de_a32 = ops_fpu_287_de_a32;
x86_opcodes_df_a16 = ops_fpu_287_df_a16;
x86_opcodes_df_a32 = ops_fpu_287_df_a32;
x86_2386_opcodes_d9_a16 = ops_2386_fpu_287_d9_a16;
x86_2386_opcodes_d9_a32 = ops_2386_fpu_287_d9_a32;
x86_2386_opcodes_da_a16 = ops_2386_fpu_287_da_a16;
x86_2386_opcodes_da_a32 = ops_2386_fpu_287_da_a32;
x86_2386_opcodes_db_a16 = ops_2386_fpu_287_db_a16;
x86_2386_opcodes_db_a32 = ops_2386_fpu_287_db_a32;
x86_2386_opcodes_dc_a16 = ops_2386_fpu_287_dc_a16;
x86_2386_opcodes_dc_a32 = ops_2386_fpu_287_dc_a32;
x86_2386_opcodes_dd_a16 = ops_2386_fpu_287_dd_a16;
x86_2386_opcodes_dd_a32 = ops_2386_fpu_287_dd_a32;
x86_2386_opcodes_de_a16 = ops_2386_fpu_287_de_a16;
x86_2386_opcodes_de_a32 = ops_2386_fpu_287_de_a32;
x86_2386_opcodes_df_a16 = ops_2386_fpu_287_df_a16;
x86_2386_opcodes_df_a32 = ops_2386_fpu_287_df_a32;
}
}
@@ -908,6 +1046,7 @@ cpu_set(void)
#else
x86_setopcodes(ops_386, ops_486_0f);
#endif
x86_setopcodes_2386(ops_2386_386, ops_2386_486_0f);
timing_rr = 1; /* register dest - register src */
timing_rm = 3; /* register dest - memory src */
@@ -947,6 +1086,7 @@ cpu_set(void)
#else
x86_setopcodes(ops_386, ops_486_0f);
#endif
x86_setopcodes_2386(ops_2386_386, ops_2386_486_0f);
timing_rr = 1; /* register dest - register src */
timing_rm = 3; /* register dest - memory src */
@@ -999,6 +1139,7 @@ cpu_set(void)
#else
x86_setopcodes(ops_386, ops_486_0f);
#endif
x86_setopcodes_2386(ops_2386_386, ops_2386_486_0f);
timing_rr = 1; /* register dest - register src */
timing_rm = 2; /* register dest - memory src */
@@ -1642,9 +1783,13 @@ cpu_set(void)
cpu_exec = exec386_dynarec;
else
#endif
/* Use exec386 for CPU_IBM486SLC because it can reach 100 MHz. */
if ((cpu_s->cpu_type == CPU_IBM486SLC) || (cpu_s->cpu_type > CPU_486DLC))
cpu_exec = exec386;
else
cpu_exec = exec386_2386;
} else if (cpu_s->cpu_type >= CPU_286)
cpu_exec = exec386;
cpu_exec = exec386_2386;
else
cpu_exec = execx86;
mmx_init();
@@ -3418,6 +3563,13 @@ x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f)
}
#endif
void
x86_setopcodes_2386(const OpFn *opcodes, const OpFn *opcodes_0f)
{
x86_2386_opcodes = opcodes;
x86_2386_opcodes_0f = opcodes_0f;
}
void
cpu_update_waitstates(void)
{

View File

@@ -748,6 +748,7 @@ extern void execx86(int cycs);
extern void enter_smm(int in_hlt);
extern void enter_smm_check(int in_hlt);
extern void leave_smm(void);
extern void exec386_2386(int cycs);
extern void exec386(int cycs);
extern void exec386_dynarec(int cycs);
extern int idivl(int32_t val);
@@ -831,6 +832,8 @@ extern int hlt_reset_pending;
extern cyrix_t cyrix;
extern int prefetch_prefixes;
extern uint8_t use_custom_nmi_vector;
extern uint32_t custom_nmi_vector;
@@ -855,5 +858,8 @@ extern MMX_REG *MMP[8];
extern uint16_t *MMEP[8];
extern void mmx_init(void);
extern void prefetch_flush(void);
extern void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int reads_l, int writes, int writes_l, int ea32);
#endif /*EMU_CPU_H*/

View File

@@ -330,6 +330,110 @@ extern const OpFn ops_REPNE[1024];
extern const OpFn ops_3DNOW[256];
extern const OpFn ops_3DNOWE[256];
void x86_setopcodes_2386(const OpFn *opcodes, const OpFn *opcodes_0f);
extern const OpFn *x86_2386_opcodes;
extern const OpFn *x86_2386_opcodes_0f;
extern const OpFn *x86_2386_opcodes_d8_a16;
extern const OpFn *x86_2386_opcodes_d8_a32;
extern const OpFn *x86_2386_opcodes_d9_a16;
extern const OpFn *x86_2386_opcodes_d9_a32;
extern const OpFn *x86_2386_opcodes_da_a16;
extern const OpFn *x86_2386_opcodes_da_a32;
extern const OpFn *x86_2386_opcodes_db_a16;
extern const OpFn *x86_2386_opcodes_db_a32;
extern const OpFn *x86_2386_opcodes_dc_a16;
extern const OpFn *x86_2386_opcodes_dc_a32;
extern const OpFn *x86_2386_opcodes_dd_a16;
extern const OpFn *x86_2386_opcodes_dd_a32;
extern const OpFn *x86_2386_opcodes_de_a16;
extern const OpFn *x86_2386_opcodes_de_a32;
extern const OpFn *x86_2386_opcodes_df_a16;
extern const OpFn *x86_2386_opcodes_df_a32;
extern const OpFn *x86_2386_opcodes_REPE;
extern const OpFn *x86_2386_opcodes_REPNE;
extern const OpFn ops_2386_286[1024];
extern const OpFn ops_2386_286_0f[1024];
extern const OpFn ops_2386_386[1024];
extern const OpFn ops_2386_386_0f[1024];
extern const OpFn ops_2386_486_0f[1024];
extern const OpFn ops_2386_ibm486_0f[1024];
extern const OpFn ops_2386_sf_fpu_287_d9_a16[256];
extern const OpFn ops_2386_sf_fpu_287_d9_a32[256];
extern const OpFn ops_2386_sf_fpu_287_da_a16[256];
extern const OpFn ops_2386_sf_fpu_287_da_a32[256];
extern const OpFn ops_2386_sf_fpu_287_db_a16[256];
extern const OpFn ops_2386_sf_fpu_287_db_a32[256];
extern const OpFn ops_2386_sf_fpu_287_dc_a16[32];
extern const OpFn ops_2386_sf_fpu_287_dc_a32[32];
extern const OpFn ops_2386_sf_fpu_287_dd_a16[256];
extern const OpFn ops_2386_sf_fpu_287_dd_a32[256];
extern const OpFn ops_2386_sf_fpu_287_de_a16[256];
extern const OpFn ops_2386_sf_fpu_287_de_a32[256];
extern const OpFn ops_2386_sf_fpu_287_df_a16[256];
extern const OpFn ops_2386_sf_fpu_287_df_a32[256];
extern const OpFn ops_2386_sf_fpu_d8_a16[32];
extern const OpFn ops_2386_sf_fpu_d8_a32[32];
extern const OpFn ops_2386_sf_fpu_d9_a16[256];
extern const OpFn ops_2386_sf_fpu_d9_a32[256];
extern const OpFn ops_2386_sf_fpu_da_a16[256];
extern const OpFn ops_2386_sf_fpu_da_a32[256];
extern const OpFn ops_2386_sf_fpu_db_a16[256];
extern const OpFn ops_2386_sf_fpu_db_a32[256];
extern const OpFn ops_2386_sf_fpu_dc_a16[32];
extern const OpFn ops_2386_sf_fpu_dc_a32[32];
extern const OpFn ops_2386_sf_fpu_dd_a16[256];
extern const OpFn ops_2386_sf_fpu_dd_a32[256];
extern const OpFn ops_2386_sf_fpu_de_a16[256];
extern const OpFn ops_2386_sf_fpu_de_a32[256];
extern const OpFn ops_2386_sf_fpu_df_a16[256];
extern const OpFn ops_2386_sf_fpu_df_a32[256];
extern const OpFn ops_2386_fpu_287_d9_a16[256];
extern const OpFn ops_2386_fpu_287_d9_a32[256];
extern const OpFn ops_2386_fpu_287_da_a16[256];
extern const OpFn ops_2386_fpu_287_da_a32[256];
extern const OpFn ops_2386_fpu_287_db_a16[256];
extern const OpFn ops_2386_fpu_287_db_a32[256];
extern const OpFn ops_2386_fpu_287_dc_a16[32];
extern const OpFn ops_2386_fpu_287_dc_a32[32];
extern const OpFn ops_2386_fpu_287_dd_a16[256];
extern const OpFn ops_2386_fpu_287_dd_a32[256];
extern const OpFn ops_2386_fpu_287_de_a16[256];
extern const OpFn ops_2386_fpu_287_de_a32[256];
extern const OpFn ops_2386_fpu_287_df_a16[256];
extern const OpFn ops_2386_fpu_287_df_a32[256];
extern const OpFn ops_2386_fpu_d8_a16[32];
extern const OpFn ops_2386_fpu_d8_a32[32];
extern const OpFn ops_2386_fpu_d9_a16[256];
extern const OpFn ops_2386_fpu_d9_a32[256];
extern const OpFn ops_2386_fpu_da_a16[256];
extern const OpFn ops_2386_fpu_da_a32[256];
extern const OpFn ops_2386_fpu_db_a16[256];
extern const OpFn ops_2386_fpu_db_a32[256];
extern const OpFn ops_2386_fpu_dc_a16[32];
extern const OpFn ops_2386_fpu_dc_a32[32];
extern const OpFn ops_2386_fpu_dd_a16[256];
extern const OpFn ops_2386_fpu_dd_a32[256];
extern const OpFn ops_2386_fpu_de_a16[256];
extern const OpFn ops_2386_fpu_de_a32[256];
extern const OpFn ops_2386_fpu_df_a16[256];
extern const OpFn ops_2386_fpu_df_a32[256];
extern const OpFn ops_2386_nofpu_a16[256];
extern const OpFn ops_2386_nofpu_a32[256];
extern const OpFn ops_2386_REPE[1024];
extern const OpFn ops_2386_REPNE[1024];
extern const OpFn ops_2386_3DNOW[256];
#define C0 (1 << 8)
#define C1 (1 << 9)
#define C2 (1 << 10)

View File

@@ -115,6 +115,7 @@ opCMPXCHG_l_a32(uint32_t fetchdat)
return 0;
}
#ifndef OPS_286_386
static int
opCMPXCHG8B_a16(uint32_t fetchdat)
{
@@ -169,6 +170,7 @@ opCMPXCHG8B_a32(uint32_t fetchdat)
cycles -= (cpu_mod == 3) ? 6 : 10;
return 0;
}
#endif
/* dest = eab, src = r8 */
static int

863
src/cpu/x86_ops_rep_2386.h Normal file
View File

@@ -0,0 +1,863 @@
#define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \
static int opREP_INSB_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
\
addr64 = 0x00000000; \
\
if (CNT_REG > 0) { \
uint8_t temp; \
\
SEG_CHECK_WRITE(&cpu_state.seg_es); \
check_io_perm(DX, 1); \
CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \
high_page = 0; \
do_mmut_wb(es, DEST_REG, &addr64); \
if (cpu_state.abrt) \
return 1; \
temp = inb(DX); \
writememb_n(es, DEST_REG, addr64, temp); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) \
DEST_REG--; \
else \
DEST_REG++; \
CNT_REG--; \
cycles -= 15; \
reads++; \
writes++; \
total_cycles += 15; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_INSW_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
\
addr64a[0] = addr64a[1] = 0x00000000; \
\
if (CNT_REG > 0) { \
uint16_t temp; \
\
SEG_CHECK_WRITE(&cpu_state.seg_es); \
check_io_perm(DX, 2); \
CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
high_page = 0; \
do_mmut_ww(es, DEST_REG, addr64a); \
if (cpu_state.abrt) \
return 1; \
temp = inw(DX); \
writememw_n(es, DEST_REG, addr64a, temp); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) \
DEST_REG -= 2; \
else \
DEST_REG += 2; \
CNT_REG--; \
cycles -= 15; \
reads++; \
writes++; \
total_cycles += 15; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_INSL_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
\
addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \
\
if (CNT_REG > 0) { \
uint32_t temp; \
\
SEG_CHECK_WRITE(&cpu_state.seg_es); \
check_io_perm(DX, 4); \
CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
high_page = 0; \
do_mmut_wl(es, DEST_REG, addr64a); \
if (cpu_state.abrt) \
return 1; \
temp = inl(DX); \
writememl_n(es, DEST_REG, addr64a, temp); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) \
DEST_REG -= 4; \
else \
DEST_REG += 4; \
CNT_REG--; \
cycles -= 15; \
reads++; \
writes++; \
total_cycles += 15; \
} \
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
\
static int opREP_OUTSB_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
\
if (CNT_REG > 0) { \
uint8_t temp; \
SEG_CHECK_READ(cpu_state.ea_seg); \
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \
temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \
if (cpu_state.abrt) \
return 1; \
check_io_perm(DX, 1); \
outb(DX, temp); \
if (cpu_state.flags & D_FLAG) \
SRC_REG--; \
else \
SRC_REG++; \
CNT_REG--; \
cycles -= 14; \
reads++; \
writes++; \
total_cycles += 14; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_OUTSW_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
\
if (CNT_REG > 0) { \
uint16_t temp; \
SEG_CHECK_READ(cpu_state.ea_seg); \
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \
temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \
if (cpu_state.abrt) \
return 1; \
check_io_perm(DX, 2); \
outw(DX, temp); \
if (cpu_state.flags & D_FLAG) \
SRC_REG -= 2; \
else \
SRC_REG += 2; \
CNT_REG--; \
cycles -= 14; \
reads++; \
writes++; \
total_cycles += 14; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_OUTSL_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
\
if (CNT_REG > 0) { \
uint32_t temp; \
SEG_CHECK_READ(cpu_state.ea_seg); \
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \
temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \
if (cpu_state.abrt) \
return 1; \
check_io_perm(DX, 4); \
outl(DX, temp); \
if (cpu_state.flags & D_FLAG) \
SRC_REG -= 4; \
else \
SRC_REG += 4; \
CNT_REG--; \
cycles -= 14; \
reads++; \
writes++; \
total_cycles += 14; \
} \
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
\
static int opREP_MOVSB_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
addr64 = addr64_2 = 0x00000000; \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) { \
SEG_CHECK_READ(cpu_state.ea_seg); \
SEG_CHECK_WRITE(&cpu_state.seg_es); \
} \
while (CNT_REG > 0) { \
uint8_t temp; \
\
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \
high_page = 0; \
do_mmut_rb(cpu_state.ea_seg->base, SRC_REG, &addr64); \
if (cpu_state.abrt) \
break; \
do_mmut_wb(es, DEST_REG, &addr64_2); \
if (cpu_state.abrt) \
break; \
temp = readmemb_n(cpu_state.ea_seg->base, SRC_REG, addr64); \
if (cpu_state.abrt) \
return 1; \
writememb_n(es, DEST_REG, addr64_2, temp); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) { \
DEST_REG--; \
SRC_REG--; \
} else { \
DEST_REG++; \
SRC_REG++; \
} \
CNT_REG--; \
cycles -= is486 ? 3 : 4; \
reads++; \
writes++; \
total_cycles += is486 ? 3 : 4; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_MOVSW_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
addr64a[0] = addr64a[1] = 0x00000000; \
addr64a_2[0] = addr64a_2[1] = 0x00000000; \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) { \
SEG_CHECK_READ(cpu_state.ea_seg); \
SEG_CHECK_WRITE(&cpu_state.seg_es); \
} \
while (CNT_REG > 0) { \
uint16_t temp; \
\
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
high_page = 0; \
do_mmut_rw(cpu_state.ea_seg->base, SRC_REG, addr64a); \
if (cpu_state.abrt) \
break; \
do_mmut_ww(es, DEST_REG, addr64a_2); \
if (cpu_state.abrt) \
break; \
temp = readmemw_n(cpu_state.ea_seg->base, SRC_REG, addr64a); \
if (cpu_state.abrt) \
return 1; \
writememw_n(es, DEST_REG, addr64a_2, temp); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) { \
DEST_REG -= 2; \
SRC_REG -= 2; \
} else { \
DEST_REG += 2; \
SRC_REG += 2; \
} \
CNT_REG--; \
cycles -= is486 ? 3 : 4; \
reads++; \
writes++; \
total_cycles += is486 ? 3 : 4; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_MOVSL_##size(uint32_t fetchdat) \
{ \
int reads = 0, writes = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \
addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) { \
SEG_CHECK_READ(cpu_state.ea_seg); \
SEG_CHECK_WRITE(&cpu_state.seg_es); \
} \
while (CNT_REG > 0) { \
uint32_t temp; \
\
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
high_page = 0; \
do_mmut_rl(cpu_state.ea_seg->base, SRC_REG, addr64a); \
if (cpu_state.abrt) \
break; \
do_mmut_wl(es, DEST_REG, addr64a_2); \
if (cpu_state.abrt) \
break; \
temp = readmeml_n(cpu_state.ea_seg->base, SRC_REG, addr64a); \
if (cpu_state.abrt) \
return 1; \
writememl_n(es, DEST_REG, addr64a_2, temp); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) { \
DEST_REG -= 4; \
SRC_REG -= 4; \
} else { \
DEST_REG += 4; \
SRC_REG += 4; \
} \
CNT_REG--; \
cycles -= is486 ? 3 : 4; \
reads++; \
writes++; \
total_cycles += is486 ? 3 : 4; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
\
static int opREP_STOSB_##size(uint32_t fetchdat) \
{ \
int writes = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) \
SEG_CHECK_WRITE(&cpu_state.seg_es); \
while (CNT_REG > 0) { \
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \
writememb(es, DEST_REG, AL); \
if (cpu_state.abrt) \
return 1; \
if (cpu_state.flags & D_FLAG) \
DEST_REG--; \
else \
DEST_REG++; \
CNT_REG--; \
cycles -= is486 ? 4 : 5; \
writes++; \
total_cycles += is486 ? 4 : 5; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_STOSW_##size(uint32_t fetchdat) \
{ \
int writes = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) \
SEG_CHECK_WRITE(&cpu_state.seg_es); \
while (CNT_REG > 0) { \
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
writememw(es, DEST_REG, AX); \
if (cpu_state.abrt) \
return 1; \
if (cpu_state.flags & D_FLAG) \
DEST_REG -= 2; \
else \
DEST_REG += 2; \
CNT_REG--; \
cycles -= is486 ? 4 : 5; \
writes++; \
total_cycles += is486 ? 4 : 5; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_STOSL_##size(uint32_t fetchdat) \
{ \
int writes = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) \
SEG_CHECK_WRITE(&cpu_state.seg_es); \
while (CNT_REG > 0) { \
CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
writememl(es, DEST_REG, EAX); \
if (cpu_state.abrt) \
return 1; \
if (cpu_state.flags & D_FLAG) \
DEST_REG -= 4; \
else \
DEST_REG += 4; \
CNT_REG--; \
cycles -= is486 ? 4 : 5; \
writes++; \
total_cycles += is486 ? 4 : 5; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, 0, 0, 0, writes, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
\
static int opREP_LODSB_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) \
SEG_CHECK_READ(cpu_state.ea_seg); \
while (CNT_REG > 0) { \
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \
AL = readmemb(cpu_state.ea_seg->base, SRC_REG); \
if (cpu_state.abrt) \
return 1; \
if (cpu_state.flags & D_FLAG) \
SRC_REG--; \
else \
SRC_REG++; \
CNT_REG--; \
cycles -= is486 ? 4 : 5; \
reads++; \
total_cycles += is486 ? 4 : 5; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_LODSW_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) \
SEG_CHECK_READ(cpu_state.ea_seg); \
while (CNT_REG > 0) { \
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \
AX = readmemw(cpu_state.ea_seg->base, SRC_REG); \
if (cpu_state.abrt) \
return 1; \
if (cpu_state.flags & D_FLAG) \
SRC_REG -= 2; \
else \
SRC_REG += 2; \
CNT_REG--; \
cycles -= is486 ? 4 : 5; \
reads++; \
total_cycles += is486 ? 4 : 5; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_LODSL_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
if (CNT_REG > 0) \
SEG_CHECK_READ(cpu_state.ea_seg); \
while (CNT_REG > 0) { \
CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \
EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); \
if (cpu_state.abrt) \
return 1; \
if (cpu_state.flags & D_FLAG) \
SRC_REG -= 4; \
else \
SRC_REG += 4; \
CNT_REG--; \
cycles -= is486 ? 4 : 5; \
reads++; \
total_cycles += is486 ? 4 : 5; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \
if (CNT_REG > 0) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
}
#define CHEK_READ(a, b, c)
#define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \
static int opREP_CMPSB_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0, tempz; \
\
addr64 = addr64_2 = 0x00000000; \
\
tempz = FV; \
if ((CNT_REG > 0) && (FV == tempz)) { \
uint8_t temp, temp2; \
SEG_CHECK_READ(cpu_state.ea_seg); \
SEG_CHECK_READ(&cpu_state.seg_es); \
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \
CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG); \
high_page = uncached = 0; \
do_mmut_rb(cpu_state.ea_seg->base, SRC_REG, &addr64); \
if (cpu_state.abrt) \
return 1; \
do_mmut_rb2(es, DEST_REG, &addr64_2); \
if (cpu_state.abrt) \
return 1; \
temp = readmemb_n(cpu_state.ea_seg->base, SRC_REG, addr64); \
if (cpu_state.abrt) \
return 1; \
temp2 = readmemb_n(es, DEST_REG, addr64_2); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) { \
DEST_REG--; \
SRC_REG--; \
} else { \
DEST_REG++; \
SRC_REG++; \
} \
CNT_REG--; \
cycles -= is486 ? 7 : 9; \
reads += 2; \
total_cycles += is486 ? 7 : 9; \
setsub8(temp, temp2); \
tempz = (ZF_SET()) ? 1 : 0; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
if ((CNT_REG > 0) && (FV == tempz)) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_CMPSW_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0, tempz; \
\
addr64a[0] = addr64a[1] = 0x00000000; \
addr64a_2[0] = addr64a_2[1] = 0x00000000; \
\
tempz = FV; \
if ((CNT_REG > 0) && (FV == tempz)) { \
uint16_t temp, temp2; \
SEG_CHECK_READ(cpu_state.ea_seg); \
SEG_CHECK_READ(&cpu_state.seg_es); \
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \
CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
high_page = uncached = 0; \
do_mmut_rw(cpu_state.ea_seg->base, SRC_REG, addr64a); \
if (cpu_state.abrt) \
return 1; \
do_mmut_rw2(es, DEST_REG, addr64a_2); \
if (cpu_state.abrt) \
return 1; \
temp = readmemw_n(cpu_state.ea_seg->base, SRC_REG, addr64a); \
if (cpu_state.abrt) \
return 1; \
temp2 = readmemw_n(es, DEST_REG, addr64a_2); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) { \
DEST_REG -= 2; \
SRC_REG -= 2; \
} else { \
DEST_REG += 2; \
SRC_REG += 2; \
} \
CNT_REG--; \
cycles -= is486 ? 7 : 9; \
reads += 2; \
total_cycles += is486 ? 7 : 9; \
setsub16(temp, temp2); \
tempz = (ZF_SET()) ? 1 : 0; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
if ((CNT_REG > 0) && (FV == tempz)) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_CMPSL_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0, tempz; \
\
addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \
addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; \
\
tempz = FV; \
if ((CNT_REG > 0) && (FV == tempz)) { \
uint32_t temp, temp2; \
SEG_CHECK_READ(cpu_state.ea_seg); \
SEG_CHECK_READ(&cpu_state.seg_es); \
CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \
CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
high_page = uncached = 0; \
do_mmut_rl(cpu_state.ea_seg->base, SRC_REG, addr64a); \
if (cpu_state.abrt) \
return 1; \
do_mmut_rl2(es, DEST_REG, addr64a_2); \
if (cpu_state.abrt) \
return 1; \
temp = readmeml_n(cpu_state.ea_seg->base, SRC_REG, addr64a); \
if (cpu_state.abrt) \
return 1; \
temp2 = readmeml_n(es, DEST_REG, addr64a_2); \
if (cpu_state.abrt) \
return 1; \
\
if (cpu_state.flags & D_FLAG) { \
DEST_REG -= 4; \
SRC_REG -= 4; \
} else { \
DEST_REG += 4; \
SRC_REG += 4; \
} \
CNT_REG--; \
cycles -= is486 ? 7 : 9; \
reads += 2; \
total_cycles += is486 ? 7 : 9; \
setsub32(temp, temp2); \
tempz = (ZF_SET()) ? 1 : 0; \
} \
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \
if ((CNT_REG > 0) && (FV == tempz)) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
\
static int opREP_SCASB_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0, tempz; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
tempz = FV; \
if ((CNT_REG > 0) && (FV == tempz)) \
SEG_CHECK_READ(&cpu_state.seg_es); \
while ((CNT_REG > 0) && (FV == tempz)) { \
CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \
uint8_t temp = readmemb(es, DEST_REG); \
if (cpu_state.abrt) \
break; \
setsub8(AL, temp); \
tempz = (ZF_SET()) ? 1 : 0; \
if (cpu_state.flags & D_FLAG) \
DEST_REG--; \
else \
DEST_REG++; \
CNT_REG--; \
cycles -= is486 ? 5 : 8; \
reads++; \
total_cycles += is486 ? 5 : 8; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
if ((CNT_REG > 0) && (FV == tempz)) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_SCASW_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0, tempz; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
tempz = FV; \
if ((CNT_REG > 0) && (FV == tempz)) \
SEG_CHECK_READ(&cpu_state.seg_es); \
while ((CNT_REG > 0) && (FV == tempz)) { \
CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \
uint16_t temp = readmemw(es, DEST_REG); \
if (cpu_state.abrt) \
break; \
setsub16(AX, temp); \
tempz = (ZF_SET()) ? 1 : 0; \
if (cpu_state.flags & D_FLAG) \
DEST_REG -= 2; \
else \
DEST_REG += 2; \
CNT_REG--; \
cycles -= is486 ? 5 : 8; \
reads++; \
total_cycles += is486 ? 5 : 8; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \
if ((CNT_REG > 0) && (FV == tempz)) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
} \
static int opREP_SCASL_##size(uint32_t fetchdat) \
{ \
int reads = 0, total_cycles = 0, tempz; \
int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \
if (trap) \
cycles_end = cycles + 1; /*Force the instruction to end after only one iteration when trap flag set*/ \
tempz = FV; \
if ((CNT_REG > 0) && (FV == tempz)) \
SEG_CHECK_READ(&cpu_state.seg_es); \
while ((CNT_REG > 0) && (FV == tempz)) { \
CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \
uint32_t temp = readmeml(es, DEST_REG); \
if (cpu_state.abrt) \
break; \
setsub32(EAX, temp); \
tempz = (ZF_SET()) ? 1 : 0; \
if (cpu_state.flags & D_FLAG) \
DEST_REG -= 4; \
else \
DEST_REG += 4; \
CNT_REG--; \
cycles -= is486 ? 5 : 8; \
reads++; \
total_cycles += is486 ? 5 : 8; \
if (cycles < cycles_end) \
break; \
} \
PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \
if ((CNT_REG > 0) && (FV == tempz)) { \
CPU_BLOCK_END(); \
cpu_state.pc = cpu_state.oldpc; \
return 1; \
} \
return cpu_state.abrt; \
}
REP_OPS(a16, CX, SI, DI)
REP_OPS(a32, ECX, ESI, EDI)
REP_OPS_CMPS_SCAS(a16_NE, CX, SI, DI, 0)
REP_OPS_CMPS_SCAS(a16_E, CX, SI, DI, 1)
REP_OPS_CMPS_SCAS(a32_NE, ECX, ESI, EDI, 0)
REP_OPS_CMPS_SCAS(a32_E, ECX, ESI, EDI, 1)
static int
opREPNE(uint32_t fetchdat)
{
fetchdat = fastreadl(cs + cpu_state.pc);
if (cpu_state.abrt)
return 1;
cpu_state.pc++;
CLOCK_CYCLES(2);
PREFETCH_PREFIX();
if (x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32])
return x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
}
static int
opREPE(uint32_t fetchdat)
{
fetchdat = fastreadl(cs + cpu_state.pc);
if (cpu_state.abrt)
return 1;
cpu_state.pc++;
CLOCK_CYCLES(2);
PREFETCH_PREFIX();
if (x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32])
return x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1408,6 +1408,7 @@ const OpFn OP_TABLE(sf_fpu_da_a32)[256] = {
// clang-format on
};
#ifndef OPS_286_386
const OpFn OP_TABLE(sf_fpu_686_da_a16)[256] = {
// clang-format off
sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16,
@@ -1487,6 +1488,7 @@ const OpFn OP_TABLE(sf_fpu_686_da_a32)[256] = {
ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32,
// clang-format on
};
#endif
const OpFn OP_TABLE(sf_fpu_287_db_a16)[256] = {
// clang-format off
@@ -1648,6 +1650,7 @@ const OpFn OP_TABLE(sf_fpu_db_a32)[256] = {
// clang-format on
};
#ifndef OPS_286_386
const OpFn OP_TABLE(sf_fpu_686_db_a16)[256] = {
// clang-format off
sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16,
@@ -1726,6 +1729,7 @@ const OpFn OP_TABLE(sf_fpu_686_db_a32)[256] = {
ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32,
// clang-format on
};
#endif
const OpFn OP_TABLE(sf_fpu_287_dc_a16)[32] = {
// clang-format off
@@ -2243,6 +2247,7 @@ const OpFn OP_TABLE(sf_fpu_df_a32)[256] = {
// clang-format on
};
#ifndef OPS_286_386
const OpFn OP_TABLE(sf_fpu_686_df_a16)[256] = {
// clang-format off
sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16,
@@ -2322,6 +2327,7 @@ const OpFn OP_TABLE(sf_fpu_686_df_a32)[256] = {
ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32,
// clang-format on
};
#endif
const OpFn OP_TABLE(fpu_d8_a16)[32] = {
// clang-format off
@@ -2661,6 +2667,7 @@ const OpFn OP_TABLE(fpu_da_a32)[256] = {
// clang-format on
};
#ifndef OPS_286_386
const OpFn OP_TABLE(fpu_686_da_a16)[256] = {
// clang-format off
opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16,
@@ -2740,6 +2747,7 @@ const OpFn OP_TABLE(fpu_686_da_a32)[256] = {
ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32,
// clang-format on
};
#endif
const OpFn OP_TABLE(fpu_287_db_a16)[256] = {
// clang-format off
@@ -2901,6 +2909,7 @@ const OpFn OP_TABLE(fpu_db_a32)[256] = {
// clang-format on
};
#ifndef OPS_286_386
const OpFn OP_TABLE(fpu_686_db_a16)[256] = {
// clang-format off
opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16,
@@ -2979,6 +2988,7 @@ const OpFn OP_TABLE(fpu_686_db_a32)[256] = {
ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32,
// clang-format on
};
#endif
const OpFn OP_TABLE(fpu_287_dc_a16)[32] = {
// clang-format off
@@ -3496,6 +3506,7 @@ const OpFn OP_TABLE(fpu_df_a32)[256] = {
// clang-format on
};
#ifndef OPS_286_386
const OpFn OP_TABLE(fpu_686_df_a16)[256] = {
// clang-format off
opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16,
@@ -3575,6 +3586,7 @@ const OpFn OP_TABLE(fpu_686_df_a32)[256] = {
ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32,
// clang-format on
};
#endif
const OpFn OP_TABLE(nofpu_a16)[256] = {
// clang-format off

View File

@@ -242,6 +242,7 @@ opFUCOMPP(uint32_t fetchdat)
return 0;
}
#ifndef OPS_286_386
static int
opFCOMI(uint32_t fetchdat)
{
@@ -274,6 +275,7 @@ opFCOMIP(uint32_t fetchdat)
return 0;
}
#endif
#endif
static int
opFDIV(uint32_t fetchdat)
@@ -476,6 +478,7 @@ opFUCOMP(uint32_t fetchdat)
return 0;
}
#ifndef OPS_286_386
static int
opFUCOMI(uint32_t fetchdat)
{
@@ -508,3 +511,4 @@ opFUCOMIP(uint32_t fetchdat)
return 0;
}
#endif
#endif

View File

@@ -1045,6 +1045,7 @@ opFSTCW_a32(uint32_t fetchdat)
#endif
#ifndef FPU_8087
#ifndef OPS_286_386
# define opFCMOV(condition) \
static int opFCMOV##condition(uint32_t fetchdat) \
{ \
@@ -1073,3 +1074,4 @@ opFCMOV(NBE)
opFCMOV(NU)
// clang-format on
#endif
#endif

View File

@@ -224,6 +224,7 @@ next_ins:
return 0;
}
#ifndef OPS_286_386
static int
sf_FCOMI_st0_stj(uint32_t fetchdat)
{
@@ -285,6 +286,7 @@ next_ins:
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi));
return 0;
}
#endif
static int
sf_FUCOM_sti(uint32_t fetchdat)
@@ -346,6 +348,7 @@ next_ins:
return 0;
}
#ifndef OPS_286_386
static int
sf_FUCOMI_st0_stj(uint32_t fetchdat)
{
@@ -407,6 +410,7 @@ next_ins:
return 0;
}
#endif
#endif
static int
sf_FTST(uint32_t fetchdat)

View File

@@ -1279,6 +1279,7 @@ sf_FSTP_sti(uint32_t fetchdat)
}
#ifndef FPU_8087
#ifndef OPS_286_386
# define sf_FCMOV(condition) \
static int sf_FCMOV##condition(uint32_t fetchdat) \
{ \
@@ -1310,3 +1311,4 @@ sf_FCMOV(NBE)
sf_FCMOV(NU)
// clang-format on
#endif
#endif

View File

@@ -83,6 +83,7 @@ extern lpt_port_t lpt_ports[PARALLEL_MAX];
extern void lpt_write(uint16_t port, uint8_t val, void *priv);
extern uint8_t lpt_read(uint16_t port, void *priv);
extern uint8_t lpt_read_status(int port);
extern void lpt_irq(void *priv, int raise);
extern char *lpt_device_get_name(int id);

View File

@@ -331,6 +331,24 @@ extern void writememll_no_mmut(uint32_t addr, uint32_t *a64, uint32_t val);
extern void do_mmutranslate(uint32_t addr, uint32_t *a64, int num, int write);
extern uint8_t readmembl_2386(uint32_t addr);
extern void writemembl_2386(uint32_t addr, uint8_t val);
extern uint16_t readmemwl_2386(uint32_t addr);
extern void writememwl_2386(uint32_t addr, uint16_t val);
extern uint32_t readmemll_2386(uint32_t addr);
extern void writememll_2386(uint32_t addr, uint32_t val);
extern uint64_t readmemql_2386(uint32_t addr);
extern void writememql_2386(uint32_t addr, uint64_t val);
extern uint8_t readmembl_no_mmut_2386(uint32_t addr, uint32_t a64);
extern void writemembl_no_mmut_2386(uint32_t addr, uint32_t a64, uint8_t val);
extern uint16_t readmemwl_no_mmut_2386(uint32_t addr, uint32_t *a64);
extern void writememwl_no_mmut_2386(uint32_t addr, uint32_t *a64, uint16_t val);
extern uint32_t readmemll_no_mmut_2386(uint32_t addr, uint32_t *a64);
extern void writememll_no_mmut_2386(uint32_t addr, uint32_t *a64, uint32_t val);
extern void do_mmutranslate_2386(uint32_t addr, uint32_t *a64, int num, int write);
extern uint8_t *getpccache(uint32_t a);
extern uint64_t mmutranslatereal(uint32_t addr, int rw);
extern uint32_t mmutranslatereal32(uint32_t addr, int rw);
@@ -429,6 +447,9 @@ extern void mem_close(void);
extern void mem_reset(void);
extern void mem_remap_top(int kb);
extern mem_mapping_t *read_mapping[MEM_MAPPINGS_NO];
extern mem_mapping_t *write_mapping[MEM_MAPPINGS_NO];
#ifdef EMU_CPU_H
static __inline uint32_t
get_phys(uint32_t addr)

View File

@@ -165,6 +165,20 @@ lpt_read(uint16_t port, void *priv)
return ret;
}
uint8_t
lpt_read_status(int port)
{
lpt_port_t *dev = &(lpt_ports[port]);
uint8_t ret = 0xff;
if (dev->dt && dev->dt->read_status && dev->priv)
ret = dev->dt->read_status(dev->priv) | 0x07;
else
ret = 0xdf;
return ret;
}
void
lpt_irq(void *priv, int raise)
{

View File

@@ -13,5 +13,5 @@
# Copyright 2020-2021 David Hrdlička.
#
add_library(mem OBJECT catalyst_flash.c i2c_eeprom.c intel_flash.c mem.c rom.c
row.c smram.c spd.c sst_flash.c)
add_library(mem OBJECT catalyst_flash.c i2c_eeprom.c intel_flash.c mem.c mmu_2386.c
rom.c row.c smram.c spd.c sst_flash.c)

View File

@@ -119,14 +119,15 @@ int purgeable_page_count = 0;
uint8_t high_page = 0; /* if a high (> 4 gb) page was detected */
mem_mapping_t *read_mapping[MEM_MAPPINGS_NO];
mem_mapping_t *write_mapping[MEM_MAPPINGS_NO];
/* FIXME: re-do this with a 'mem_ops' struct. */
static uint8_t *page_lookupp; /* pagetable mmu_perm lookup */
static uint8_t *readlookupp;
static uint8_t *writelookupp;
static mem_mapping_t *base_mapping;
static mem_mapping_t *last_mapping;
static mem_mapping_t *read_mapping[MEM_MAPPINGS_NO];
static mem_mapping_t *write_mapping[MEM_MAPPINGS_NO];
static mem_mapping_t *read_mapping_bus[MEM_MAPPINGS_NO];
static mem_mapping_t *write_mapping_bus[MEM_MAPPINGS_NO];
static uint8_t *_mem_exec[MEM_MAPPINGS_NO];

901
src/mem/mmu_2386.c Normal file
View File

@@ -0,0 +1,901 @@
/*
* 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.
*
* Memory handling and MMU.
*
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
* Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2020 Miran Grca.
* Copyright 2017-2020 Fred N. van Kempen.
*/
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/version.h>
#include "cpu.h"
#include "x86_ops.h"
#include "x86.h"
#include <86box/machine.h>
#include <86box/m_xt_xi8088.h>
#include <86box/config.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/plat.h>
#include <86box/rom.h>
#include <86box/gdbstub.h>
#ifdef USE_DYNAREC
# include "codegen_public.h"
#else
#ifdef USE_NEW_DYNAREC
# define PAGE_MASK_SHIFT 6
#else
# define PAGE_MASK_INDEX_MASK 3
# define PAGE_MASK_INDEX_SHIFT 10
# define PAGE_MASK_SHIFT 4
#endif
# define PAGE_MASK_MASK 63
#endif
#if (!defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC))
#define BLOCK_PC_INVALID 0xffffffff
#define BLOCK_INVALID 0
#endif
#define mmutranslate_read_2386(addr) mmutranslatereal_2386(addr,0)
#define mmutranslate_write_2386(addr) mmutranslatereal_2386(addr,1)
uint64_t
mmutranslatereal_2386(uint32_t addr, int rw)
{
uint32_t temp, temp2, temp3;
uint32_t addr2;
if (cpu_state.abrt)
return 0xffffffffffffffffULL;
addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc));
temp = temp2 = mem_readl_phys(addr2);
if (!(temp & 1)) {
cr2 = addr;
temp &= 1;
if (CPL == 3) temp |= 4;
if (rw) temp |= 2;
cpu_state.abrt = ABRT_PF;
abrt_error = temp;
return 0xffffffffffffffffULL;
}
temp = mem_readl_phys((temp & ~0xfff) + ((addr >> 10) & 0xffc));
temp3 = temp & temp2;
if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (is486 && (cr0 & WP_FLAG))))) {
cr2 = addr;
temp &= 1;
if (CPL == 3)
temp |= 4;
if (rw)
temp |= 2;
cpu_state.abrt = ABRT_PF;
abrt_error = temp;
return 0xffffffffffffffffULL;
}
mmu_perm = temp & 4;
mem_writel_phys(addr2, mem_readl_phys(addr) | 0x20);
mem_writel_phys((temp2 & ~0xfff) + ((addr >> 10) & 0xffc), mem_readl_phys((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) | (rw ? 0x60 : 0x20));
return (uint64_t) ((temp & ~0xfff) + (addr & 0xfff));
}
uint64_t
mmutranslate_noabrt_2386(uint32_t addr, int rw)
{
uint32_t temp,temp2,temp3;
uint32_t addr2;
if (cpu_state.abrt)
return 0xffffffffffffffffULL;
addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc));
temp = temp2 = mem_readl_phys(addr2);
if (! (temp & 1))
return 0xffffffffffffffffULL;
temp = mem_readl_phys((temp & ~0xfff) + ((addr >> 10) & 0xffc));
temp3 = temp & temp2;
if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && ((CPL == 3) || (cr0 & WP_FLAG))))
return 0xffffffffffffffffULL;
return (uint64_t) ((temp & ~0xfff) + (addr & 0xfff));
}
uint8_t
readmembl_2386(uint32_t addr)
{
mem_mapping_t *map;
uint64_t a;
GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1);
addr64 = (uint64_t) addr;
mem_logical_addr = addr;
high_page = 0;
if (cr0 >> 31) {
a = mmutranslate_read_2386(addr);
addr64 = (uint32_t) a;
if (a > 0xffffffffULL)
return 0xff;
}
addr = (uint32_t) (addr64 & rammask);
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->read_b)
return map->read_b(addr, map->priv);
return 0xff;
}
void
writemembl_2386(uint32_t addr, uint8_t val)
{
mem_mapping_t *map;
uint64_t a;
GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1);
addr64 = (uint64_t) addr;
mem_logical_addr = addr;
high_page = 0;
if (cr0 >> 31) {
a = mmutranslate_write_2386(addr);
addr64 = (uint32_t) a;
if (a > 0xffffffffULL)
return;
}
addr = (uint32_t) (addr64 & rammask);
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->write_b)
map->write_b(addr, val, map->priv);
}
/* Read a byte from memory without MMU translation - result of previous MMU translation passed as value. */
uint8_t
readmembl_no_mmut_2386(uint32_t addr, uint32_t a64)
{
mem_mapping_t *map;
GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1);
mem_logical_addr = addr;
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return 0xff;
addr = a64 & rammask;
} else
addr &= rammask;
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->read_b)
return map->read_b(addr, map->priv);
return 0xff;
}
/* Write a byte to memory without MMU translation - result of previous MMU translation passed as value. */
void
writemembl_no_mmut_2386(uint32_t addr, uint32_t a64, uint8_t val)
{
mem_mapping_t *map;
GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1);
mem_logical_addr = addr;
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return;
addr = a64 & rammask;
} else
addr &= rammask;
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->write_b)
map->write_b(addr, val, map->priv);
}
uint16_t
readmemwl_2386(uint32_t addr)
{
mem_mapping_t *map;
int i;
uint64_t a;
addr64a[0] = addr;
addr64a[1] = addr + 1;
GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 2);
mem_logical_addr = addr;
high_page = 0;
if (addr & 1) {
if (!cpu_cyrix_alignment || (addr & 7) == 7)
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xffe) {
if (cr0 >> 31) {
for (i = 0; i < 2; i++) {
a = mmutranslate_read_2386(addr + i);
addr64a[i] = (uint32_t) a;
if (a > 0xffffffffULL)
return 0xffff;
}
}
return readmembl_no_mmut(addr, addr64a[0]) |
(((uint16_t) readmembl_no_mmut(addr + 1, addr64a[1])) << 8);
}
}
if (cr0 >> 31) {
a = mmutranslate_read_2386(addr);
addr64a[0] = (uint32_t) a;
if (a > 0xffffffffULL)
return 0xffff;
} else
addr64a[0] = (uint64_t) addr;
addr = addr64a[0] & rammask;
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->read_w)
return map->read_w(addr, map->priv);
if (map && map->read_b) {
return map->read_b(addr, map->priv) |
((uint16_t) (map->read_b(addr + 1, map->priv)) << 8);
}
return 0xffff;
}
void
writememwl_2386(uint32_t addr, uint16_t val)
{
mem_mapping_t *map;
int i;
uint64_t a;
addr64a[0] = addr;
addr64a[1] = addr + 1;
GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 2);
mem_logical_addr = addr;
high_page = 0;
if (addr & 1) {
if (!cpu_cyrix_alignment || (addr & 7) == 7)
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xffe) {
if (cr0 >> 31) {
for (i = 0; i < 2; i++) {
a = mmutranslate_write_2386(addr + i);
addr64a[i] = (uint32_t) a;
if (a > 0xffffffffULL)
return;
}
}
/* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
their result as a parameter to be used if needed. */
writemembl_no_mmut(addr, addr64a[0], val);
writemembl_no_mmut(addr + 1, addr64a[1], val >> 8);
return;
}
}
if (cr0 >> 31) {
a = mmutranslate_write_2386(addr);
addr64a[0] = (uint32_t) a;
if (a > 0xffffffffULL)
return;
}
addr = addr64a[0] & rammask;
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->write_w) {
map->write_w(addr, val, map->priv);
return;
}
if (map && map->write_b) {
map->write_b(addr, val, map->priv);
map->write_b(addr + 1, val >> 8, map->priv);
return;
}
}
/* Read a word from memory without MMU translation - results of previous MMU translation passed as array. */
uint16_t
readmemwl_no_mmut_2386(uint32_t addr, uint32_t *a64)
{
mem_mapping_t *map;
GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 2);
mem_logical_addr = addr;
if (addr & 1) {
if (!cpu_cyrix_alignment || (addr & 7) == 7)
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xffe) {
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return 0xffff;
}
return readmembl_no_mmut(addr, a64[0]) |
(((uint16_t) readmembl_no_mmut(addr + 1, a64[1])) << 8);
}
}
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return 0xffff;
addr = (uint32_t) (a64[0] & rammask);
} else
addr &= rammask;
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->read_w)
return map->read_w(addr, map->priv);
if (map && map->read_b) {
return map->read_b(addr, map->priv) |
((uint16_t) (map->read_b(addr + 1, map->priv)) << 8);
}
return 0xffff;
}
/* Write a word to memory without MMU translation - results of previous MMU translation passed as array. */
void
writememwl_no_mmut_2386(uint32_t addr, uint32_t *a64, uint16_t val)
{
mem_mapping_t *map;
GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 2);
mem_logical_addr = addr;
if (addr & 1) {
if (!cpu_cyrix_alignment || (addr & 7) == 7)
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xffe) {
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return;
}
writemembl_no_mmut(addr, a64[0], val);
writemembl_no_mmut(addr + 1, a64[1], val >> 8);
return;
}
}
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return;
addr = (uint32_t) (a64[0] & rammask);
} else
addr &= rammask;
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->write_w) {
map->write_w(addr, val, map->priv);
return;
}
if (map && map->write_b) {
map->write_b(addr, val, map->priv);
map->write_b(addr + 1, val >> 8, map->priv);
return;
}
}
uint32_t
readmemll_2386(uint32_t addr)
{
mem_mapping_t *map;
int i;
uint64_t a = 0x0000000000000000ULL;
for (i = 0; i < 4; i++)
addr64a[i] = (uint64_t) (addr + i);
GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 4);
mem_logical_addr = addr;
high_page = 0;
if (addr & 3) {
if (!cpu_cyrix_alignment || (addr & 7) > 4)
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xffc) {
if (cr0 >> 31) {
for (i = 0; i < 4; i++) {
if (i == 0) {
a = mmutranslate_read_2386(addr + i);
addr64a[i] = (uint32_t) a;
} else if (!((addr + i) & 0xfff)) {
a = mmutranslate_read_2386(addr + 3);
addr64a[i] = (uint32_t) a;
if (!cpu_state.abrt) {
a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
addr64a[i] = (uint32_t) a;
}
} else {
a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
addr64a[i] = (uint32_t) a;
}
if (a > 0xffffffffULL)
return 0xffff;
}
}
/* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
their result as a parameter to be used if needed. */
return readmemwl_no_mmut(addr, addr64a) |
(((uint32_t) readmemwl_no_mmut(addr + 2, &(addr64a[2]))) << 16);
}
}
if (cr0 >> 31) {
a = mmutranslate_read_2386(addr);
addr64a[0] = (uint32_t) a;
if (a > 0xffffffffULL)
return 0xffffffff;
}
addr = addr64a[0] & rammask;
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->read_l)
return map->read_l(addr, map->priv);
if (map && map->read_w)
return map->read_w(addr, map->priv) |
((uint32_t) (map->read_w(addr + 2, map->priv)) << 16);
if (map && map->read_b)
return map->read_b(addr, map->priv) |
((uint32_t) (map->read_b(addr + 1, map->priv)) << 8) |
((uint32_t) (map->read_b(addr + 2, map->priv)) << 16) |
((uint32_t) (map->read_b(addr + 3, map->priv)) << 24);
return 0xffffffff;
}
void
writememll_2386(uint32_t addr, uint32_t val)
{
mem_mapping_t *map;
int i;
uint64_t a = 0x0000000000000000ULL;
for (i = 0; i < 4; i++)
addr64a[i] = (uint64_t) (addr + i);
GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 4);
mem_logical_addr = addr;
high_page = 0;
if (addr & 3) {
if (!cpu_cyrix_alignment || (addr & 7) > 4)
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xffc) {
if (cr0 >> 31) {
for (i = 0; i < 4; i++) {
if (i == 0) {
a = mmutranslate_write_2386(addr + i);
addr64a[i] = (uint32_t) a;
} else if (!((addr + i) & 0xfff)) {
a = mmutranslate_write_2386(addr + 3);
addr64a[i] = (uint32_t) a;
if (!cpu_state.abrt) {
a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
addr64a[i] = (uint32_t) a;
}
} else {
a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
addr64a[i] = (uint32_t) a;
}
if (a > 0xffffffffULL)
return;
}
}
/* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
their result as a parameter to be used if needed. */
writememwl_no_mmut(addr, &(addr64a[0]), val);
writememwl_no_mmut(addr + 2, &(addr64a[2]), val >> 16);
return;
}
}
if (cr0 >> 31) {
a = mmutranslate_write_2386(addr);
addr64a[0] = (uint32_t) a;
if (a > 0xffffffffULL)
return;
}
addr = addr64a[0] & rammask;
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->write_l) {
map->write_l(addr, val, map->priv);
return;
}
if (map && map->write_w) {
map->write_w(addr, val, map->priv);
map->write_w(addr + 2, val >> 16, map->priv);
return;
}
if (map && map->write_b) {
map->write_b(addr, val, map->priv);
map->write_b(addr + 1, val >> 8, map->priv);
map->write_b(addr + 2, val >> 16, map->priv);
map->write_b(addr + 3, val >> 24, map->priv);
return;
}
}
/* Read a long from memory without MMU translation - results of previous MMU translation passed as array. */
uint32_t
readmemll_no_mmut_2386(uint32_t addr, uint32_t *a64)
{
mem_mapping_t *map;
GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 4);
mem_logical_addr = addr;
if (addr & 3) {
if (!cpu_cyrix_alignment || (addr & 7) > 4)
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xffc) {
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return 0xffffffff;
}
return readmemwl_no_mmut(addr, a64) |
((uint32_t) (readmemwl_no_mmut(addr + 2, &(a64[2]))) << 16);
}
}
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return 0xffffffff;
addr = (uint32_t) (a64[0] & rammask);
} else
addr &= rammask;
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->read_l)
return map->read_l(addr, map->priv);
if (map && map->read_w)
return map->read_w(addr, map->priv) |
((uint32_t) (map->read_w(addr + 2, map->priv)) << 16);
if (map && map->read_b)
return map->read_b(addr, map->priv) |
((uint32_t) (map->read_b(addr + 1, map->priv)) << 8) |
((uint32_t) (map->read_b(addr + 2, map->priv)) << 16) |
((uint32_t) (map->read_b(addr + 3, map->priv)) << 24);
return 0xffffffff;
}
/* Write a long to memory without MMU translation - results of previous MMU translation passed as array. */
void
writememll_no_mmut_2386(uint32_t addr, uint32_t *a64, uint32_t val)
{
mem_mapping_t *map;
GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 4);
mem_logical_addr = addr;
if (addr & 3) {
if (!cpu_cyrix_alignment || (addr & 7) > 4)
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xffc) {
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return;
}
writememwl_no_mmut(addr, &(a64[0]), val);
writememwl_no_mmut(addr + 2, &(a64[2]), val >> 16);
return;
}
}
if (cr0 >> 31) {
if (cpu_state.abrt || high_page)
return;
addr = (uint32_t) (a64[0] & rammask);
} else
addr &= rammask;
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->write_l) {
map->write_l(addr, val, map->priv);
return;
}
if (map && map->write_w) {
map->write_w(addr, val, map->priv);
map->write_w(addr + 2, val >> 16, map->priv);
return;
}
if (map && map->write_b) {
map->write_b(addr, val, map->priv);
map->write_b(addr + 1, val >> 8, map->priv);
map->write_b(addr + 2, val >> 16, map->priv);
map->write_b(addr + 3, val >> 24, map->priv);
return;
}
}
uint64_t
readmemql_2386(uint32_t addr)
{
mem_mapping_t *map;
int i;
uint64_t a = 0x0000000000000000ULL;
for (i = 0; i < 8; i++)
addr64a[i] = (uint64_t) (addr + i);
GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 8);
mem_logical_addr = addr;
high_page = 0;
if (addr & 7) {
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xff8) {
if (cr0 >> 31) {
for (i = 0; i < 8; i++) {
if (i == 0) {
a = mmutranslate_read_2386(addr + i);
addr64a[i] = (uint32_t) a;
} else if (!((addr + i) & 0xfff)) {
a = mmutranslate_read_2386(addr + 7);
addr64a[i] = (uint32_t) a;
if (!cpu_state.abrt) {
a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
addr64a[i] = (uint32_t) a;
}
} else {
a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
addr64a[i] = (uint32_t) a;
}
if (a > 0xffffffffULL)
return 0xffff;
}
}
/* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
their result as a parameter to be used if needed. */
return readmemll_no_mmut(addr, addr64a) |
(((uint64_t) readmemll_no_mmut(addr + 4, &(addr64a[4]))) << 32);
}
}
if (cr0 >> 31) {
a = mmutranslate_read_2386(addr);
addr64a[0] = (uint32_t) a;
if (a > 0xffffffffULL)
return 0xffffffffffffffffULL;
}
addr = addr64a[0] & rammask;
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->read_l)
return map->read_l(addr, map->priv) | ((uint64_t)map->read_l(addr + 4, map->priv) << 32);
return readmemll(addr) | ((uint64_t) readmemll(addr + 4) << 32);
}
void
writememql_2386(uint32_t addr, uint64_t val)
{
mem_mapping_t *map;
int i;
uint64_t a = 0x0000000000000000ULL;
for (i = 0; i < 8; i++)
addr64a[i] = (uint64_t) (addr + i);
GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 8);
mem_logical_addr = addr;
high_page = 0;
if (addr & 7) {
cycles -= timing_misaligned;
if ((addr & 0xfff) > 0xff8) {
if (cr0 >> 31) {
for (i = 0; i < 8; i++) {
if (i == 0) {
a = mmutranslate_write_2386(addr + i);
addr64a[i] = (uint32_t) a;
} else if (!((addr + i) & 0xfff)) {
a = mmutranslate_write_2386(addr + 7);
addr64a[i] = (uint32_t) a;
if (!cpu_state.abrt) {
a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
addr64a[i] = (uint32_t) a;
}
} else {
a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
addr64a[i] = (uint32_t) a;
}
if (addr64a[i] > 0xffffffffULL)
return;
}
}
/* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
their result as a parameter to be used if needed. */
writememll_no_mmut(addr, addr64a, val);
writememll_no_mmut(addr + 4, &(addr64a[4]), val >> 32);
return;
}
}
if (cr0 >> 31) {
addr64a[0] = mmutranslate_write_2386(addr);
if (addr64a[0] > 0xffffffffULL)
return;
}
addr = addr64a[0] & rammask;
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
if (map && map->write_l) {
map->write_l(addr, val, map->priv);
map->write_l(addr + 4, val >> 32, map->priv);
return;
}
if (map && map->write_w) {
map->write_w(addr, val, map->priv);
map->write_w(addr + 2, val >> 16, map->priv);
map->write_w(addr + 4, val >> 32, map->priv);
map->write_w(addr + 6, val >> 48, map->priv);
return;
}
if (map && map->write_b) {
map->write_b(addr, val, map->priv);
map->write_b(addr + 1, val >> 8, map->priv);
map->write_b(addr + 2, val >> 16, map->priv);
map->write_b(addr + 3, val >> 24, map->priv);
map->write_b(addr + 4, val >> 32, map->priv);
map->write_b(addr + 5, val >> 40, map->priv);
map->write_b(addr + 6, val >> 48, map->priv);
map->write_b(addr + 7, val >> 56, map->priv);
return;
}
}
void
do_mmutranslate_2386(uint32_t addr, uint32_t *a64, int num, int write)
{
int i;
uint32_t last_addr = addr + (num - 1);
uint64_t a = 0x0000000000000000ULL;
for (i = 0; i < num; i++)
a64[i] = (uint64_t) addr;
for (i = 0; i < num; i++) {
if (cr0 >> 31) {
/* If we have encountered at least one page fault, mark all subsequent addresses as
having page faulted, prevents false negatives in readmem*l_no_mmut. */
if ((i > 0) && cpu_state.abrt && !high_page)
a64[i] = a64[i - 1];
/* If we are on the same page, there is no need to translate again, as we can just
reuse the previous result. */
else if (i == 0) {
a = mmutranslatereal_2386(addr, write);
a64[i] = (uint32_t) a;
} else if (!(addr & 0xfff)) {
a = mmutranslatereal_2386(last_addr, write);
a64[i] = (uint32_t) a;
if (!cpu_state.abrt) {
a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff));
a64[i] = (uint32_t) a;
}
} else {
a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff));
a64[i] = (uint32_t) a;
}
}
addr++;
}
}

View File

@@ -568,7 +568,8 @@ MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.
usb.o device.o nvr.o nvr_at.o nvr_ps2.o machine_status.o ini.o \
$(VNCOBJ)
MEMOBJ := catalyst_flash.o i2c_eeprom.o intel_flash.o mem.o rom.o row.o smram.o spd.o sst_flash.o
MEMOBJ := catalyst_flash.o i2c_eeprom.o intel_flash.o mem.o mmu_2386.o rom.o row.o \
smram.o spd.o sst_flash.o
CPU808XOBJ := queue.o