blob: 06e4c8e3bb53cb6fe70136be5e927eb33302eb00 [file] [log] [blame] [raw]
/*
* Dos/PC Emulator
* Copyright (C) 1991 Jim Hudgens
*
*
* The file is part of GDE.
*
* GDE is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* GDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDE; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* 8086 support structs and definitions */
/* definition of the registers */
/* general EAX,EBX,ECX, EDX type registers.
Note that for portability, and speed, the issue of byte
swapping is not addressed in the registers. All registers
are stored in the default format available on the
host machine. The only critical issue is that the
registers should line up EXACTLY in the same manner as
they do in the 386. That is:
EAX & 0xff === AL
EAX & 0xffff == AX
etc. The result is that alot of the calculations can then be
done using the native instruction set fully.
*/
/* Endian Logic
Priority 1: If LOWFIRST is defined, use it. LOWFIRST must be 1 if the
lower part of a 16 bit quantity comes first in memory, otherwise
LOWFIRST must be 0
Priority 2: If __BIG_ENDIAN__ is defined, use it to define LOWFIRST accordingly
Priority 3: OS 9 on Macintosh needs LOWFIRST 0
Priority 4: Use LOWFIRST 1 as default
*/
#ifndef LOWFIRST
#ifdef __BIG_ENDIAN__
#if __BIG_ENDIAN__
#define LOWFIRST 0
#else
#define LOWFIRST 1
#endif
#elif defined (__MWERKS__) && defined (macintosh)
#define LOWFIRST 0
#else
#define LOWFIRST 1
#endif
#endif
#if LOWFIRST
typedef struct { uint16 x_reg; } I16_reg_t;
typedef struct { uint8 l_reg, h_reg; } I8_reg_t;
#else
typedef struct { uint16 x_reg; } I16_reg_t;
typedef struct { uint8 h_reg, l_reg; } I8_reg_t;
#endif
typedef union
{
I16_reg_t I16_reg;
I8_reg_t I8_reg;
} i386_general_register;
struct i386_general_regs
{
i386_general_register A, B, C, D;
};
typedef struct i386_general_regs Gen_reg_t;
struct i386_special_regs
{
i386_general_register SP, BP, SI, DI, IP;
uint32 FLAGS;
};
/*
* segment registers here represent the 16 bit quantities
* CS, DS, ES, SS
*
* segment pointers --- used to speed up the expressions:
* q = m->R_CSP + m->R_IP;
* fetched = *q;
* m->R_IP += 1;
* compared to:
* fetched = GetBYTEExtended(((uint32)m->R_CS << 4) + (m->R_IP++));
* Save at least one shift, more if doing two byte moves.
*/
struct i386_segment_regs
{
uint16 CS, DS, SS, ES, FS, GS;
};
/* 8 bit registers */
#define R_AH Gn_regs.A.I8_reg.h_reg
#define R_AL Gn_regs.A.I8_reg.l_reg
#define R_BH Gn_regs.B.I8_reg.h_reg
#define R_BL Gn_regs.B.I8_reg.l_reg
#define R_CH Gn_regs.C.I8_reg.h_reg
#define R_CL Gn_regs.C.I8_reg.l_reg
#define R_DH Gn_regs.D.I8_reg.h_reg
#define R_DL Gn_regs.D.I8_reg.l_reg
/* 16 bit registers */
#define R_AX Gn_regs.A.I16_reg.x_reg
#define R_BX Gn_regs.B.I16_reg.x_reg
#define R_CX Gn_regs.C.I16_reg.x_reg
#define R_DX Gn_regs.D.I16_reg.x_reg
/* special registers */
#define R_SP Sp_regs.SP.I16_reg.x_reg
#define R_BP Sp_regs.BP.I16_reg.x_reg
#define R_SI Sp_regs.SI.I16_reg.x_reg
#define R_DI Sp_regs.DI.I16_reg.x_reg
#define R_IP Sp_regs.IP.I16_reg.x_reg
#define R_FLG Sp_regs.FLAGS
/* segment registers */
#define R_CS Sg_regs.CS
#define R_DS Sg_regs.DS
#define R_SS Sg_regs.SS
#define R_ES Sg_regs.ES
/* 8088 has top 4 bits of the flags set to 1 */
/* Also, bit#1 is set. This is (not well) documented behavior. */
/* see note in userman.tex about the subtleties of dealing with */
/* code which attempts to detect the host processor. */
/* This is def'd as F_ALWAYS_ON */
#define F_ALWAYS_ON (0xf002) /* flag bits always on */
/* following bits masked in to a 16bit quantity */
#define F_CF 0x1 /* CARRY flag */
#define F_PF 0x4 /* PARITY flag */
#define F_AF 0x10 /* AUX flag */
#define F_ZF 0x40 /* ZERO flag */
#define F_SF 0x80 /* SIGN flag */
#define F_TF 0x100 /* TRAP flag */
#define F_IF 0x200 /* INTERRUPT ENABLE flag */
#define F_DF 0x400 /* DIR flag */
#define F_OF 0x800 /* OVERFLOW flag */
/*
* DEFINE A MASK FOR ONLY THOSE FLAG BITS WE WILL EVER PASS BACK
* (via PUSHF)
*/
#define F_MSK (F_CF|F_PF|F_AF|F_ZF|F_SF|F_TF|F_IF|F_DF|F_OF)
#define TOGGLE_FLAG(M,FLAG) (M)->R_FLG ^= FLAG
#define SET_FLAG(M,FLAG) (M)->R_FLG |= FLAG
#define CLEAR_FLAG(M, FLAG) (M)->R_FLG &= ~FLAG
#define ACCESS_FLAG(M,FLAG) ((M)->R_FLG & (FLAG))
#define CONDITIONAL_SET_FLAG(COND,M,FLAG) \
if (COND) SET_FLAG(M,FLAG); else CLEAR_FLAG(M,FLAG)
/* emulator machine state. */
/* segment usage control */
#define SYSMODE_SEG_DS_SS 0x01
#define SYSMODE_SEGOVR_CS 0x02
#define SYSMODE_SEGOVR_DS 0x04
#define SYSMODE_SEGOVR_ES 0x08
#define SYSMODE_SEGOVR_SS 0x10
#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | SYSMODE_SEGOVR_CS | \
SYSMODE_SEGOVR_DS | SYSMODE_SEGOVR_ES | SYSMODE_SEGOVR_SS)
#define SYSMODE_PREFIX_REPE 0x20
#define SYSMODE_PREFIX_REPNE 0x40
#define INTR_SYNCH 0x1
#define INTR_HALTED 0x4
#define INTR_ILLEGAL_OPCODE 0x8
/* INSTRUCTION DECODING STUFF */
#define FETCH_DECODE_MODRM(m,mod,rh,rl) fetch_decode_modrm(m,&mod,&rh,&rl)
#define DECODE_RM_BYTE_REGISTER(m,r) decode_rm_byte_register(m,r)
#define DECODE_RM_WORD_REGISTER(m,r) decode_rm_word_register(m,r)
#define DECODE_CLEAR_SEGOVR(m) m->sysmode &= ~(SYSMODE_SEGMASK)
typedef struct pc_env PC_ENV;
struct pc_env
{
/* The registers!! */
struct i386_general_regs Gn_regs;
struct i386_special_regs Sp_regs;
struct i386_segment_regs Sg_regs;
/* our flags structrure. This contains information on
REPE prefix 2 bits repe,repne
SEGMENT overrides 5 bits normal,DS,SS,CS,ES
Delayed flag set 3 bits (zero, signed, parity)
reserved 6 bits
interrupt # 8 bits instruction raised interrupt
BIOS video segregs 4 bits
Interrupt Pending 1 bits
Extern interrupt 1 bits
Halted 1 bits
*/
long sysmode;
uint8 intno;
};
/* GLOBAL */
volatile int intr;
void halt_sys (PC_ENV *sys);
void fetch_decode_modrm (PC_ENV *m, uint16 *mod, uint16 *regh, uint16 *regl);
uint8 *decode_rm_byte_register (PC_ENV *m, int reg);
uint16 *decode_rm_word_register (PC_ENV *m, int reg);
uint16 *decode_rm_seg_register (PC_ENV *m, int reg);
uint8 fetch_byte_imm (PC_ENV *m);
uint16 fetch_word_imm (PC_ENV *m);
uint16 decode_rm00_address (PC_ENV *m, int rm);
uint16 decode_rm01_address (PC_ENV *m, int rm);
uint16 decode_rm10_address (PC_ENV *m, int rm);
uint8 fetch_data_byte (PC_ENV *m, uint16 offset);
uint8 fetch_data_byte_abs (PC_ENV *m, uint16 segment, uint16 offset);
uint16 fetch_data_word (PC_ENV *m, uint16 offset);
uint16 fetch_data_word_abs (PC_ENV *m, uint16 segment, uint16 offset);
void store_data_byte (PC_ENV *m, uint16 offset, uint8 val);
void store_data_byte_abs (PC_ENV *m, uint16 segment, uint16 offset, uint8 val);
void store_data_word (PC_ENV *m, uint16 offset, uint16 val);
void store_data_word_abs (PC_ENV *m, uint16 segment, uint16 offset, uint16 val);
typedef void (*OP)(PC_ENV *m);
extern OP i86_optab[256];
/* PRIMITIVE OPERATIONS */
uint8 aad_word (PC_ENV *m, uint16 d);
uint16 aam_word (PC_ENV *m, uint8 d);
uint8 adc_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 adc_word (PC_ENV *m, uint16 d, uint16 s);
uint8 add_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 add_word (PC_ENV *m, uint16 d, uint16 s);
uint8 and_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 and_word (PC_ENV *m, uint16 d, uint16 s);
uint8 cmp_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 cmp_word (PC_ENV *m, uint16 d, uint16 s);
uint8 dec_byte (PC_ENV *m, uint8 d);
uint16 dec_word (PC_ENV *m, uint16 d);
uint8 inc_byte (PC_ENV *m, uint8 d);
uint16 inc_word (PC_ENV *m, uint16 d);
uint8 or_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 or_word (PC_ENV *m, uint16 d, uint16 s);
uint8 neg_byte (PC_ENV *m, uint8 s);
uint16 neg_word (PC_ENV *m, uint16 s);
uint8 not_byte (PC_ENV *m, uint8 s);
uint16 not_word (PC_ENV *m, uint16 s);
uint16 mem_access_word (PC_ENV *m, int addr);
void push_word (PC_ENV *m, uint16 w);
uint16 pop_word (PC_ENV *m);
uint8 rcl_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 rcl_word (PC_ENV *m, uint16 d, uint16 s);
uint8 rcr_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 rcr_word (PC_ENV *m, uint16 d, uint16 s);
uint8 rol_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 rol_word (PC_ENV *m, uint16 d, uint16 s);
uint8 ror_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 ror_word (PC_ENV *m, uint16 d, uint16 s);
uint8 shl_byte (PC_ENV *m, uint8 d, uint8 s) ;
uint16 shl_word (PC_ENV *m, uint16 d, uint16 s);
uint8 shr_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 shr_word (PC_ENV *m, uint16 d, uint16 s);
uint8 sar_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 sar_word (PC_ENV *m, uint16 d, uint16 s);
uint8 sbb_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 sbb_word (PC_ENV *m, uint16 d, uint16 s);
uint8 sub_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 sub_word (PC_ENV *m, uint16 d, uint16 s);
void test_byte (PC_ENV *m, uint8 d, uint8 s);
void test_word (PC_ENV *m, uint16 d, uint16 s);
uint8 xor_byte (PC_ENV *m, uint8 d, uint8 s);
uint16 xor_word (PC_ENV *m, uint16 d, uint16 s);
void imul_byte (PC_ENV *m, uint8 s);
void imul_word (PC_ENV *m, uint16 s);
void mul_byte (PC_ENV *m, uint8 s);
void mul_word (PC_ENV *m, uint16 s);
void idiv_byte (PC_ENV *m, uint8 s);
void idiv_word (PC_ENV *m, uint16 s);
void div_byte (PC_ENV *m, uint8 s);
void div_word (PC_ENV *m, uint16 s);