i386: x87 bug fixes and FERR support [Andrey Merkulov]

i8087: separate 8087 device [Carl]
This commit is contained in:
cracyc 2017-12-16 14:24:24 -06:00
parent 145bbb789c
commit a3e4c79be6
9 changed files with 5071 additions and 38 deletions

View File

@ -1088,6 +1088,18 @@ if (MACHINES["I7220"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/i8087.h,MACHINES["I8087"] = true
---------------------------------------------------
if (MACHINES["I8087"]~=null) then
files {
MAME_DIR .. "src/devices/machine/i8087.cpp",
MAME_DIR .. "src/devices/machine/i8087.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/i8155.h,MACHINES["I8155"] = true

View File

@ -424,7 +424,7 @@ MACHINES["1MB5"] = true
MACHINES["I2CMEM"] = true
MACHINES["I7220"] = true
MACHINES["I80130"] = true
MACHINES["I8089"] = true
MACHINES["I8087"] = true
MACHINES["I8155"] = true
MACHINES["I8212"] = true
MACHINES["I8214"] = true

View File

@ -53,6 +53,7 @@ i386_device::i386_device(const machine_config &mconfig, device_type type, const
, m_program_config("program", ENDIANNESS_LITTLE, program_data_width, program_addr_width, 0)
, m_io_config("io", ENDIANNESS_LITTLE, io_data_width, 16, 0)
, m_smiact(*this)
, m_ferr_handler(*this)
{
m_program_config.m_logaddr_width = 32;
m_program_config.m_page_shift = 12;
@ -3320,6 +3321,8 @@ void i386_device::i386_common_init()
machine().save().register_postload(save_prepost_delegate(FUNC(i386_device::i386_postload), this));
m_smiact.resolve_safe();
m_ferr_handler.resolve_safe();
m_ferr_handler(0);
m_icountptr = &m_cycles;
}

View File

@ -27,6 +27,9 @@
#define MCFG_I386_SMIACT(_devcb) \
devcb = &i386_device::set_smiact(*device, DEVCB_##_devcb);
#define MCFG_I486_FERR_HANDLER(_devcb) \
devcb = &i386_device::set_ferr(*device, DEVCB_##_devcb);
#define X86_NUM_CPUS 4
@ -38,6 +41,7 @@ public:
// static configuration helpers
template <class Object> static devcb_base &set_smiact(device_t &device, Object &&cb) { return downcast<i386_device &>(device).m_smiact.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_ferr(device_t &device, Object &&cb) { return downcast<i386_device &>(device).m_ferr_handler.set_callback(std::forward<Object>(cb)); }
uint64_t debug_segbase(symbol_table &table, int params, const uint64_t *param);
uint64_t debug_seglimit(symbol_table &table, int params, const uint64_t *param);
@ -283,6 +287,7 @@ protected:
bool m_nmi_latched;
uint32_t m_smbase;
devcb_write_line m_smiact;
devcb_write_line m_ferr_handler;
bool m_lock;
// bytes in current opcode, debug only
@ -1386,6 +1391,8 @@ protected:
void x87_fincstp(uint8_t modrm);
void x87_fclex(uint8_t modrm);
void x87_ffree(uint8_t modrm);
void x87_fdisi(uint8_t modrm);
void x87_feni(uint8_t modrm);
void x87_finit(uint8_t modrm);
void x87_fldcw(uint8_t modrm);
void x87_fstcw(uint8_t modrm);

View File

@ -16,6 +16,12 @@
- Remove redundant operand checks
- Exceptions
Corrections and Additions [8-December-2017 Andrey Merkulov)
FXAM, FPREM - fixed
FINCSTP, FDECSTP - tags and exceptions corrected
Interrupt handling for 8087 added
FENI, FDISI opcodes added
***************************************************************************/
#include <math.h>
@ -49,6 +55,7 @@
#define X87_CW_OM 0x0008
#define X87_CW_UM 0x0010
#define X87_CW_PM 0x0020
#define X87_CW_IEM 0x0080
#define X87_CW_PC_SHIFT 8
#define X87_CW_PC_MASK 3
#define X87_CW_PC_SINGLE 0
@ -309,6 +316,9 @@ int i386_device::x87_check_exceptions()
{
// m_device->execute().set_input_line(INPUT_LINE_FERR, RAISE_LINE);
logerror("Unmasked x87 exception (CW:%.4x, SW:%.4x)\n", m_x87_cw, m_x87_sw);
// interrupt handler
if (!(m_x87_cw & X87_CW_IEM)) { m_x87_sw |= X87_SW_ES; m_ferr_handler(1); }
if (m_cr[0] & 0x20) // FIXME: 486 and up only
{
m_ext = 1;
@ -339,6 +349,8 @@ void i386_device::x87_reset()
m_x87_data_ptr = 0;
m_x87_inst_ptr = 0;
m_x87_opcode = 0;
m_ferr_handler(0);
}
@ -2173,7 +2185,7 @@ void i386_device::x87_fcmovnu_sti(uint8_t modrm)
* Miscellaneous arithmetic
*
*************************************/
/* D9 F8 */
void i386_device::x87_fprem(uint8_t modrm)
{
floatx80 result;
@ -2185,19 +2197,22 @@ void i386_device::x87_fprem(uint8_t modrm)
}
else
{
floatx80 a0 = ST(0);
floatx80 b1 = ST(1);
floatx80 a0 = ST(0); // dividend
floatx80 b1 = ST(1); // divider
floatx80 a0_abs = packFloatx80(0, (a0.high & 0x7FFF), a0.low);
floatx80 b1_abs = packFloatx80(0, (b1.high & 0x7FFF), b1.low);
m_x87_sw &= ~X87_SW_C2;
//int d=extractFloatx80Exp(a0)-extractFloatx80Exp(b1);
int d = (a0.high & 0x7FFF) - (b1.high & 0x7FFF);
if (d < 64) {
floatx80 t=floatx80_div(a0, b1);
floatx80 t=floatx80_div(a0_abs, b1_abs);
int64 q = floatx80_to_int64_round_to_zero(t);
floatx80 qf = int64_to_floatx80(q);
floatx80 tt = floatx80_mul(b1, qf);
result = floatx80_sub(a0, tt);
floatx80 tt = floatx80_mul(b1_abs, qf);
result = floatx80_sub(a0_abs, tt);
result.high |= a0.high & 0x8000;
// C2 already 0
m_x87_sw &= ~(X87_SW_C0|X87_SW_C3|X87_SW_C1);
if (q & 1)
@ -2381,7 +2396,7 @@ void i386_device::x87_fyl2xp1(uint8_t modrm)
CYCLES(313);
}
/* D9 F2 if 8087 0 < angle < pi/4 */
void i386_device::x87_fptan(uint8_t modrm)
{
floatx80 result1, result2;
@ -2403,7 +2418,7 @@ void i386_device::x87_fptan(uint8_t modrm)
result1 = ST(0);
result2 = fx80_one;
#if 0 // TODO: Function produces bad values
#if 1 // TODO: Function produces bad values
if (floatx80_ftan(result1) != -1)
m_x87_sw &= ~X87_SW_C2;
else
@ -2426,7 +2441,7 @@ void i386_device::x87_fptan(uint8_t modrm)
CYCLES(244);
}
/* D9 F3 */
void i386_device::x87_fpatan(uint8_t modrm)
{
floatx80 result;
@ -2451,7 +2466,7 @@ void i386_device::x87_fpatan(uint8_t modrm)
CYCLES(289);
}
/* D9 FE 387 only */
void i386_device::x87_fsin(uint8_t modrm)
{
floatx80 result;
@ -2465,7 +2480,8 @@ void i386_device::x87_fsin(uint8_t modrm)
{
result = ST(0);
#if 0 // TODO: Function produces bad values
#if 1 // TODO: Function produces bad values Result checked
if (floatx80_fsin(result) != -1)
m_x87_sw &= ~X87_SW_C2;
else
@ -2484,7 +2500,7 @@ void i386_device::x87_fsin(uint8_t modrm)
CYCLES(241);
}
/* D9 FF 387 only */
void i386_device::x87_fcos(uint8_t modrm)
{
floatx80 result;
@ -2498,7 +2514,7 @@ void i386_device::x87_fcos(uint8_t modrm)
{
result = ST(0);
#if 0 // TODO: Function produces bad values
#if 1 // TODO: Function produces bad values to check!
if (floatx80_fcos(result) != -1)
m_x87_sw &= ~X87_SW_C2;
else
@ -2517,7 +2533,7 @@ void i386_device::x87_fcos(uint8_t modrm)
CYCLES(241);
}
/* D9 FB 387 only */
void i386_device::x87_fsincos(uint8_t modrm)
{
floatx80 s_result, c_result;
@ -3609,7 +3625,7 @@ void i386_device::x87_fxam(uint8_t modrm)
{
m_x87_sw |= X87_SW_C3;
}
if (floatx80_is_nan(value))
else if (floatx80_is_nan(value))
{
m_x87_sw |= X87_SW_C0;
}
@ -4365,8 +4381,7 @@ void i386_device::x87_fdecstp(uint8_t modrm)
{
m_x87_sw &= ~X87_SW_C1;
x87_dec_stack();
x87_check_exceptions();
x87_set_stack_top(ST_TO_PHYS(7));
CYCLES(3);
}
@ -4375,8 +4390,7 @@ void i386_device::x87_fincstp(uint8_t modrm)
{
m_x87_sw &= ~X87_SW_C1;
x87_inc_stack();
x87_check_exceptions();
x87_set_stack_top(ST_TO_PHYS(1));
CYCLES(3);
}
@ -4384,7 +4398,7 @@ void i386_device::x87_fincstp(uint8_t modrm)
void i386_device::x87_fclex(uint8_t modrm)
{
m_x87_sw &= ~0x80ff;
m_ferr_handler(0);
CYCLES(7);
}
@ -4395,6 +4409,21 @@ void i386_device::x87_ffree(uint8_t modrm)
CYCLES(3);
}
void i386_device::x87_feni(uint8_t modrm)
{
m_x87_cw &= ~X87_CW_IEM;
x87_check_exceptions();
CYCLES(5);
}
void i386_device::x87_fdisi(uint8_t modrm)
{
m_x87_cw |= X87_CW_IEM;
CYCLES(5);
}
void i386_device::x87_finit(uint8_t modrm)
{
x87_reset();
@ -4492,6 +4521,7 @@ void i386_device::x87_fstenv(uint8_t modrm)
// WRITE32(ea + 24, m_fpu_inst_ptr);
break;
}
m_x87_cw |= 0x3f; // set all masks
CYCLES((m_cr[0] & 1) ? 56 : 67);
}
@ -4931,8 +4961,8 @@ void i386_device::build_x87_opcode_table_db()
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: ptr = &i386_device::x87_fcmovne_sti; break;
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: ptr = &i386_device::x87_fcmovnbe_sti; break;
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: ptr = &i386_device::x87_fcmovnu_sti; break;
case 0xe0: ptr = &i386_device::x87_fnop; break; /* FENI */
case 0xe1: ptr = &i386_device::x87_fnop; break; /* FDISI */
case 0xe0: ptr = &i386_device::x87_feni; break; /* FENI */
case 0xe1: ptr = &i386_device::x87_fdisi; break; /* FDISI */
case 0xe2: ptr = &i386_device::x87_fclex; break;
case 0xe3: ptr = &i386_device::x87_finit; break;
case 0xe4: ptr = &i386_device::x87_fnop; break; /* FSETPM */
@ -5111,3 +5141,5 @@ void i386_device::build_x87_opcode_table()
build_x87_opcode_table_de();
build_x87_opcode_table_df();
}

View File

@ -114,6 +114,8 @@ i8086_cpu_device::i8086_cpu_device(const machine_config &mconfig, device_type ty
, m_extra_config("extra", ENDIANNESS_LITTLE, data_bus_size, 20, 0)
, m_io_config("io", ENDIANNESS_LITTLE, data_bus_size, 16, 0)
, m_out_if_func(*this)
, m_esc_opcode_handler(*this)
, m_esc_data_handler(*this)
{
}
@ -274,6 +276,23 @@ void i8086_cpu_device::execute_run()
}
break;
case 0xd8: // i_esc
case 0xd9:
case 0xda:
case 0xdb:
case 0xdc:
case 0xdd:
case 0xde:
case 0xdf:
m_esc_opcode_handler(pc() - 1);
m_modrm = fetch();
if(m_modrm < 0xc0)
m_esc_data_handler(get_ea(1, I8086_READ));
else
m_esc_data_handler(0);
CLK(NOP);
break;
default:
if(!common_op(op))
{
@ -295,6 +314,8 @@ void i8086_cpu_device::device_start()
{
i8086_common_cpu_device::device_start();
m_out_if_func.resolve_safe();
m_esc_opcode_handler.resolve_safe();
m_esc_data_handler.resolve_safe();
m_stack = has_space(AS_STACK) ? &space(AS_STACK) : m_program;
m_code = has_space(AS_CODE) ? &space(AS_CODE) : m_program;
m_extra = has_space(AS_EXTRA) ? &space(AS_EXTRA) : m_program;
@ -1916,21 +1937,6 @@ bool i8086_common_cpu_device::common_op(uint8_t op)
CLK(XLAT);
break;
case 0xd8: // i_esc
case 0xd9:
case 0xda:
case 0xdb:
case 0xdc:
case 0xdd:
case 0xde:
case 0xdf:
m_modrm = fetch();
GetRMByte();
CLK(NOP);
logerror("%06x: Unimplemented floating point escape %02x%02x\n", pc(), op, m_modrm);
break;
case 0xe0: // i_loopne
{
int8_t disp = (int8_t)fetch();

View File

@ -31,6 +31,12 @@ DECLARE_DEVICE_TYPE(I8088, i8088_cpu_device)
#define MCFG_I8086_EXTRA_MAP(map) \
MCFG_DEVICE_ADDRESS_MAP(i8086_cpu_device::AS_EXTRA, map)
#define MCFG_I8086_ESC_OPCODE_HANDLER(_write) \
devcb = &i8086_cpu_device::set_esc_opcode_handler(*device, DEVCB_##_write);
#define MCFG_I8086_ESC_DATA_HANDLER(_write) \
devcb = &i8086_cpu_device::set_esc_data_handler(*device, DEVCB_##_write);
enum
{
I8086_PC = STATE_GENPC,
@ -370,6 +376,12 @@ public:
template <class Object> static devcb_base &set_if_handler(device_t &device, Object &&cb)
{ return downcast<i8086_cpu_device &>(device).m_out_if_func.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_esc_opcode_handler(device_t &device, Object &&cb)
{ return downcast<i8086_cpu_device &>(device).m_esc_opcode_handler.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_esc_data_handler(device_t &device, Object &&cb)
{ return downcast<i8086_cpu_device &>(device).m_esc_data_handler.set_callback(std::forward<Object>(cb)); }
protected:
i8086_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int data_bus_size);
@ -388,6 +400,8 @@ protected:
address_space_config m_io_config;
static const uint8_t m_i8086_timing[200];
devcb_write_line m_out_if_func;
devcb_write32 m_esc_opcode_handler;
devcb_write32 m_esc_data_handler;
};
class i8088_cpu_device : public i8086_cpu_device

File diff suppressed because it is too large Load Diff

234
src/devices/machine/i8087.h Normal file
View File

@ -0,0 +1,234 @@
// license:BSD-3-Clause
// copyright-holders:Philip Bennett, Carl
// SoftFloat 2 lacks an include guard
#ifndef softfloat_h
#define softfloat_h 1
#include "softfloat/milieu.h"
#include "softfloat/softfloat.h"
#endif
#define MCFG_I8087_DATA_WIDTH(_data_width) \
i8087_device::set_data_width(*device, _data_width);
#define MCFG_I8087_INT_HANDLER(_devcb) \
devcb = &i8087_device::set_int(*device, DEVCB_##_devcb);
#define MCFG_I8087_BUSY_HANDLER(_devcb) \
devcb = &i8087_device::set_busy(*device, DEVCB_##_devcb);
DECLARE_DEVICE_TYPE(I8087, i8087_device)
class i8087_device : public device_t,
public device_memory_interface
{
public:
i8087_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
static void set_data_width(device_t &device, u8 data_width) { downcast<i8087_device &>(device).m_data_width = data_width; }
template <class Object> static devcb_base &set_int(device_t &device, Object &&cb) { return downcast<i8087_device &>(device).m_int_handler.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_busy(device_t &device, Object &&cb) { return downcast<i8087_device &>(device).m_busy_handler.set_callback(std::forward<Object>(cb)); }
DECLARE_WRITE32_MEMBER(insn_w); // the real 8087 sniffs the bus watching for esc, can't do that here so provide a poke spot
DECLARE_WRITE32_MEMBER(addr_w);
protected:
i8087_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_config_complete() override;
virtual space_config_vector memory_space_config() const override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
typedef void (i8087_device::*x87_func)(u8 modrm);
address_space_config m_space_config;
devcb_write_line m_int_handler;
devcb_write_line m_busy_handler;
emu_timer *m_timer;
floatx80 m_reg[8];
u32 m_ea;
u32 m_pc;
u32 m_ppc;
u16 m_opcode;
u16 m_cw;
u16 m_sw;
u16 m_tw;
int m_data_width;
int m_icount;
x87_func m_opcode_table_d8[256];
x87_func m_opcode_table_d9[256];
x87_func m_opcode_table_da[256];
x87_func m_opcode_table_db[256];
x87_func m_opcode_table_dc[256];
x87_func m_opcode_table_dd[256];
x87_func m_opcode_table_de[256];
x87_func m_opcode_table_df[256];
void execute();
void CYCLES(int cycles) {m_icount = cycles;}
u8 FETCH();
u8 READ8(offs_t ea);
void WRITE8(offs_t ea, u8 data);
u16 READ16(offs_t ea);
void WRITE16(offs_t ea, u16 data);
u32 READ32(offs_t ea);
void WRITE32(offs_t ea, u32 data);
u64 READ64(offs_t ea);
void WRITE64(offs_t ea, u64 data);
floatx80 READ80(offs_t);
void WRITE80(offs_t ea, floatx80 t);
void set_stack_top(int top);
void set_tag(int reg, int tag);
void write_stack(int i, floatx80 value, bool update_tag);
void set_stack_underflow();
void set_stack_overflow();
int inc_stack();
int dec_stack();
int check_exceptions();
void write_cw(u16 cw);
floatx80 add(floatx80 a, floatx80 b);
floatx80 sub(floatx80 a, floatx80 b);
floatx80 mul(floatx80 a, floatx80 b);
floatx80 div(floatx80 a, floatx80 b);
void fadd_m32real(u8 modrm);
void fadd_m64real(u8 modrm);
void fadd_st_sti(u8 modrm);
void fadd_sti_st(u8 modrm);
void faddp(u8 modrm);
void fiadd_m32int(u8 modrm);
void fiadd_m16int(u8 modrm);
void fsub_m32real(u8 modrm);
void fsub_m64real(u8 modrm);
void fsub_st_sti(u8 modrm);
void fsub_sti_st(u8 modrm);
void fsubp(u8 modrm);
void fisub_m32int(u8 modrm);
void fisub_m16int(u8 modrm);
void fsubr_m32real(u8 modrm);
void fsubr_m64real(u8 modrm);
void fsubr_st_sti(u8 modrm);
void fsubr_sti_st(u8 modrm);
void fsubrp(u8 modrm);
void fisubr_m32int(u8 modrm);
void fisubr_m16int(u8 modrm);
void fdiv_m32real(u8 modrm);
void fdiv_m64real(u8 modrm);
void fdiv_st_sti(u8 modrm);
void fdiv_sti_st(u8 modrm);
void fdivp(u8 modrm);
void fidiv_m32int(u8 modrm);
void fidiv_m16int(u8 modrm);
void fdivr_m32real(u8 modrm);
void fdivr_m64real(u8 modrm);
void fdivr_st_sti(u8 modrm);
void fdivr_sti_st(u8 modrm);
void fdivrp(u8 modrm);
void fidivr_m32int(u8 modrm);
void fidivr_m16int(u8 modrm);
void fmul_m32real(u8 modrm);
void fmul_m64real(u8 modrm);
void fmul_st_sti(u8 modrm);
void fmul_sti_st(u8 modrm);
void fmulp(u8 modrm);
void fimul_m32int(u8 modrm);
void fimul_m16int(u8 modrm);
void fprem(u8 modrm);
void fprem1(u8 modrm);
void fsqrt(u8 modrm);
void f2xm1(u8 modrm);
void fyl2x(u8 modrm);
void fyl2xp1(u8 modrm);
void fptan(u8 modrm);
void fpatan(u8 modrm);
void fsin(u8 modrm);
void fcos(u8 modrm);
void fsincos(u8 modrm);
void fld_m32real(u8 modrm);
void fld_m64real(u8 modrm);
void fld_m80real(u8 modrm);
void fld_sti(u8 modrm);
void fild_m16int(u8 modrm);
void fild_m32int(u8 modrm);
void fild_m64int(u8 modrm);
void fbld(u8 modrm);
void fst_m32real(u8 modrm);
void fst_m64real(u8 modrm);
void fst_sti(u8 modrm);
void fstp_m32real(u8 modrm);
void fstp_m64real(u8 modrm);
void fstp_m80real(u8 modrm);
void fstp_sti(u8 modrm);
void fist_m16int(u8 modrm);
void fist_m32int(u8 modrm);
void fistp_m16int(u8 modrm);
void fistp_m32int(u8 modrm);
void fistp_m64int(u8 modrm);
void fbstp(u8 modrm);
void fld1(u8 modrm);
void fldl2t(u8 modrm);
void fldl2e(u8 modrm);
void fldpi(u8 modrm);
void fldlg2(u8 modrm);
void fldln2(u8 modrm);
void fldz(u8 modrm);
void fnop(u8 modrm);
void fchs(u8 modrm);
void fabs(u8 modrm);
void fscale(u8 modrm);
void frndint(u8 modrm);
void fxtract(u8 modrm);
void ftst(u8 modrm);
void fxam(u8 modrm);
void ficom_m16int(u8 modrm);
void ficom_m32int(u8 modrm);
void ficomp_m16int(u8 modrm);
void ficomp_m32int(u8 modrm);
void fcom_m32real(u8 modrm);
void fcom_m64real(u8 modrm);
void fcom_sti(u8 modrm);
void fcomp_m32real(u8 modrm);
void fcomp_m64real(u8 modrm);
void fcomp_sti(u8 modrm);
void fcompp(u8 modrm);
void fucom_sti(u8 modrm);
void fucomp_sti(u8 modrm);
void fucompp(u8 modrm);
void fdecstp(u8 modrm);
void fincstp(u8 modrm);
void fclex(u8 modrm);
void ffree(u8 modrm);
void fdisi(u8 modrm);
void feni(u8 modrm);
void finit(u8 modrm);
void fldcw(u8 modrm);
void fstcw(u8 modrm);
void fldenv(u8 modrm);
void fstenv(u8 modrm);
void fsave(u8 modrm);
void frstor(u8 modrm);
void fxch(u8 modrm);
void fxch_sti(u8 modrm);
void fstsw_ax(u8 modrm);
void fstsw_m2byte(u8 modrm);
void invalid(u8 modrm);
void group_d8(u8 modrm);
void group_d9(u8 modrm);
void group_da(u8 modrm);
void group_db(u8 modrm);
void group_dc(u8 modrm);
void group_dd(u8 modrm);
void group_de(u8 modrm);
void group_df(u8 modrm);
void build_opcode_table_d8();
void build_opcode_table_d9();
void build_opcode_table_da();
void build_opcode_table_db();
void build_opcode_table_dc();
void build_opcode_table_dd();
void build_opcode_table_de();
void build_opcode_table_df();
void build_opcode_table();
};