Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /*\r |
2 | * Dos/PC Emulator\r | |
3 | * Copyright (C) 1991 Jim Hudgens\r | |
4 | *\r | |
5 | *\r | |
6 | * The file is part of GDE.\r | |
7 | *\r | |
8 | * GDE is free software; you can redistribute it and/or modify\r | |
9 | * it under the terms of the GNU General Public License as published by\r | |
10 | * the Free Software Foundation; either version 1, or (at your option)\r | |
11 | * any later version.\r | |
12 | *\r | |
13 | * GDE is distributed in the hope that it will be useful,\r | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of\r | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r | |
16 | * GNU General Public License for more details.\r | |
17 | *\r | |
18 | * You should have received a copy of the GNU General Public License\r | |
19 | * along with GDE; see the file COPYING. If not, write to\r | |
20 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\r | |
21 | *\r | |
22 | */\r | |
23 | \r | |
24 | /* 8086 support structs and definitions */\r | |
25 | /* definition of the registers */\r | |
26 | \r | |
27 | /* general EAX,EBX,ECX, EDX type registers.\r | |
28 | Note that for portability, and speed, the issue of byte\r | |
29 | swapping is not addressed in the registers. All registers\r | |
30 | are stored in the default format available on the\r | |
31 | host machine. The only critical issue is that the\r | |
32 | registers should line up EXACTLY in the same manner as\r | |
33 | they do in the 386. That is:\r | |
34 | \r | |
35 | EAX & 0xff === AL\r | |
36 | EAX & 0xffff == AX\r | |
37 | \r | |
38 | etc. The result is that alot of the calculations can then be\r | |
39 | done using the native instruction set fully.\r | |
40 | */\r | |
41 | \r | |
42 | /* Endian Logic\r | |
43 | Priority 1: If LOWFIRST is defined, use it. LOWFIRST must be 1 if the\r | |
44 | lower part of a 16 bit quantity comes first in memory, otherwise\r | |
45 | LOWFIRST must be 0\r | |
46 | Priority 2: If __BIG_ENDIAN__ is defined, use it to define LOWFIRST accordingly\r | |
47 | Priority 3: OS 9 on Macintosh needs LOWFIRST 0\r | |
48 | Priority 4: Use LOWFIRST 1 as default\r | |
49 | */\r | |
50 | \r | |
51 | #ifndef LOWFIRST\r | |
52 | #ifdef __BIG_ENDIAN__\r | |
53 | #if __BIG_ENDIAN__\r | |
54 | #define LOWFIRST 0\r | |
55 | #else\r | |
56 | #define LOWFIRST 1\r | |
57 | #endif\r | |
58 | #elif defined (__MWERKS__) && defined (macintosh)\r | |
59 | #define LOWFIRST 0\r | |
60 | #else\r | |
61 | #define LOWFIRST 1\r | |
62 | #endif\r | |
63 | #endif\r | |
64 | \r | |
65 | #if LOWFIRST\r | |
66 | typedef struct { uint16 x_reg; } I16_reg_t;\r | |
67 | typedef struct { uint8 l_reg, h_reg; } I8_reg_t;\r | |
68 | #else\r | |
69 | typedef struct { uint16 x_reg; } I16_reg_t;\r | |
70 | typedef struct { uint8 h_reg, l_reg; } I8_reg_t;\r | |
71 | #endif\r | |
72 | \r | |
73 | typedef union\r | |
74 | {\r | |
75 | I16_reg_t I16_reg;\r | |
76 | I8_reg_t I8_reg;\r | |
77 | } i386_general_register;\r | |
78 | \r | |
79 | struct i386_general_regs\r | |
80 | {\r | |
81 | i386_general_register A, B, C, D;\r | |
82 | };\r | |
83 | \r | |
84 | typedef struct i386_general_regs Gen_reg_t;\r | |
85 | \r | |
86 | struct i386_special_regs\r | |
87 | {\r | |
88 | i386_general_register SP, BP, SI, DI, IP;\r | |
89 | uint32 FLAGS;\r | |
90 | };\r | |
91 | \r | |
92 | /*\r | |
93 | * segment registers here represent the 16 bit quantities\r | |
94 | * CS, DS, ES, SS\r | |
95 | *\r | |
96 | * segment pointers --- used to speed up the expressions:\r | |
97 | * q = m->R_CSP + m->R_IP;\r | |
98 | * fetched = *q;\r | |
99 | * m->R_IP += 1;\r | |
100 | * compared to:\r | |
101 | * fetched = GetBYTEExtended(((uint32)m->R_CS << 4) + (m->R_IP++));\r | |
102 | * Save at least one shift, more if doing two byte moves.\r | |
103 | */\r | |
104 | struct i386_segment_regs\r | |
105 | {\r | |
106 | uint16 CS, DS, SS, ES, FS, GS;\r | |
107 | };\r | |
108 | \r | |
109 | /* 8 bit registers */\r | |
110 | #define R_AH Gn_regs.A.I8_reg.h_reg\r | |
111 | #define R_AL Gn_regs.A.I8_reg.l_reg\r | |
112 | #define R_BH Gn_regs.B.I8_reg.h_reg\r | |
113 | #define R_BL Gn_regs.B.I8_reg.l_reg\r | |
114 | #define R_CH Gn_regs.C.I8_reg.h_reg\r | |
115 | #define R_CL Gn_regs.C.I8_reg.l_reg\r | |
116 | #define R_DH Gn_regs.D.I8_reg.h_reg\r | |
117 | #define R_DL Gn_regs.D.I8_reg.l_reg\r | |
118 | \r | |
119 | /* 16 bit registers */\r | |
120 | #define R_AX Gn_regs.A.I16_reg.x_reg\r | |
121 | #define R_BX Gn_regs.B.I16_reg.x_reg\r | |
122 | #define R_CX Gn_regs.C.I16_reg.x_reg\r | |
123 | #define R_DX Gn_regs.D.I16_reg.x_reg\r | |
124 | \r | |
125 | /* special registers */\r | |
126 | #define R_SP Sp_regs.SP.I16_reg.x_reg\r | |
127 | #define R_BP Sp_regs.BP.I16_reg.x_reg\r | |
128 | #define R_SI Sp_regs.SI.I16_reg.x_reg\r | |
129 | #define R_DI Sp_regs.DI.I16_reg.x_reg\r | |
130 | #define R_IP Sp_regs.IP.I16_reg.x_reg\r | |
131 | #define R_FLG Sp_regs.FLAGS\r | |
132 | \r | |
133 | /* segment registers */\r | |
134 | #define R_CS Sg_regs.CS\r | |
135 | #define R_DS Sg_regs.DS\r | |
136 | #define R_SS Sg_regs.SS\r | |
137 | #define R_ES Sg_regs.ES\r | |
138 | \r | |
139 | /* 8088 has top 4 bits of the flags set to 1 */\r | |
140 | /* Also, bit#1 is set. This is (not well) documented behavior. */\r | |
141 | /* see note in userman.tex about the subtleties of dealing with */\r | |
142 | /* code which attempts to detect the host processor. */\r | |
143 | /* This is def'd as F_ALWAYS_ON */\r | |
144 | #define F_ALWAYS_ON (0xf002) /* flag bits always on */\r | |
145 | \r | |
146 | /* following bits masked in to a 16bit quantity */\r | |
147 | #define F_CF 0x1 /* CARRY flag */\r | |
148 | #define F_PF 0x4 /* PARITY flag */\r | |
149 | #define F_AF 0x10 /* AUX flag */\r | |
150 | #define F_ZF 0x40 /* ZERO flag */\r | |
151 | #define F_SF 0x80 /* SIGN flag */\r | |
152 | #define F_TF 0x100 /* TRAP flag */\r | |
153 | #define F_IF 0x200 /* INTERRUPT ENABLE flag */\r | |
154 | #define F_DF 0x400 /* DIR flag */\r | |
155 | #define F_OF 0x800 /* OVERFLOW flag */\r | |
156 | \r | |
157 | /*\r | |
158 | * DEFINE A MASK FOR ONLY THOSE FLAG BITS WE WILL EVER PASS BACK\r | |
159 | * (via PUSHF)\r | |
160 | */\r | |
161 | #define F_MSK (F_CF|F_PF|F_AF|F_ZF|F_SF|F_TF|F_IF|F_DF|F_OF)\r | |
162 | \r | |
163 | #define TOGGLE_FLAG(M,FLAG) (M)->R_FLG ^= FLAG\r | |
164 | #define SET_FLAG(M,FLAG) (M)->R_FLG |= FLAG\r | |
165 | #define CLEAR_FLAG(M, FLAG) (M)->R_FLG &= ~FLAG\r | |
166 | #define ACCESS_FLAG(M,FLAG) ((M)->R_FLG & (FLAG))\r | |
167 | \r | |
168 | #define CONDITIONAL_SET_FLAG(COND,M,FLAG) \\r | |
169 | if (COND) SET_FLAG(M,FLAG); else CLEAR_FLAG(M,FLAG)\r | |
170 | \r | |
171 | /* emulator machine state. */\r | |
172 | /* segment usage control */\r | |
173 | #define SYSMODE_SEG_DS_SS 0x01\r | |
174 | #define SYSMODE_SEGOVR_CS 0x02\r | |
175 | #define SYSMODE_SEGOVR_DS 0x04\r | |
176 | #define SYSMODE_SEGOVR_ES 0x08\r | |
177 | #define SYSMODE_SEGOVR_SS 0x10\r | |
178 | \r | |
179 | #define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | SYSMODE_SEGOVR_CS | \\r | |
180 | SYSMODE_SEGOVR_DS | SYSMODE_SEGOVR_ES | SYSMODE_SEGOVR_SS)\r | |
181 | \r | |
182 | #define SYSMODE_PREFIX_REPE 0x20\r | |
183 | #define SYSMODE_PREFIX_REPNE 0x40\r | |
184 | \r | |
185 | #define INTR_SYNCH 0x1\r | |
186 | #define INTR_HALTED 0x4\r | |
187 | #define INTR_ILLEGAL_OPCODE 0x8\r | |
188 | \f\r | |
189 | /* INSTRUCTION DECODING STUFF */\r | |
190 | #define FETCH_DECODE_MODRM(m,mod,rh,rl) fetch_decode_modrm(m,&mod,&rh,&rl)\r | |
191 | #define DECODE_RM_BYTE_REGISTER(m,r) decode_rm_byte_register(m,r)\r | |
192 | #define DECODE_RM_WORD_REGISTER(m,r) decode_rm_word_register(m,r)\r | |
193 | #define DECODE_CLEAR_SEGOVR(m) m->sysmode &= ~(SYSMODE_SEGMASK)\r | |
194 | \r | |
195 | typedef struct pc_env PC_ENV;\r | |
196 | struct pc_env\r | |
197 | {\r | |
198 | /* The registers!! */\r | |
199 | struct i386_general_regs Gn_regs;\r | |
200 | struct i386_special_regs Sp_regs;\r | |
201 | struct i386_segment_regs Sg_regs;\r | |
202 | /* our flags structrure. This contains information on\r | |
203 | REPE prefix 2 bits repe,repne\r | |
204 | SEGMENT overrides 5 bits normal,DS,SS,CS,ES\r | |
205 | Delayed flag set 3 bits (zero, signed, parity)\r | |
206 | reserved 6 bits\r | |
207 | interrupt # 8 bits instruction raised interrupt\r | |
208 | BIOS video segregs 4 bits\r | |
209 | Interrupt Pending 1 bits\r | |
210 | Extern interrupt 1 bits\r | |
211 | Halted 1 bits\r | |
212 | */\r | |
213 | long sysmode;\r | |
214 | uint8 intno;\r | |
215 | };\r | |
216 | \r | |
217 | /* GLOBAL */\r | |
218 | volatile int intr;\r | |
219 | \r | |
220 | void halt_sys (PC_ENV *sys);\r | |
221 | void fetch_decode_modrm (PC_ENV *m, uint16 *mod, uint16 *regh, uint16 *regl);\r | |
222 | uint8 *decode_rm_byte_register (PC_ENV *m, int reg);\r | |
223 | uint16 *decode_rm_word_register (PC_ENV *m, int reg);\r | |
224 | uint16 *decode_rm_seg_register (PC_ENV *m, int reg);\r | |
225 | uint8 fetch_byte_imm (PC_ENV *m);\r | |
226 | uint16 fetch_word_imm (PC_ENV *m);\r | |
227 | uint16 decode_rm00_address (PC_ENV *m, int rm);\r | |
228 | uint16 decode_rm01_address (PC_ENV *m, int rm);\r | |
229 | uint16 decode_rm10_address (PC_ENV *m, int rm);\r | |
230 | uint8 fetch_data_byte (PC_ENV *m, uint16 offset);\r | |
231 | uint8 fetch_data_byte_abs (PC_ENV *m, uint16 segment, uint16 offset);\r | |
232 | uint16 fetch_data_word (PC_ENV *m, uint16 offset);\r | |
233 | uint16 fetch_data_word_abs (PC_ENV *m, uint16 segment, uint16 offset);\r | |
234 | void store_data_byte (PC_ENV *m, uint16 offset, uint8 val);\r | |
235 | void store_data_byte_abs (PC_ENV *m, uint16 segment, uint16 offset, uint8 val);\r | |
236 | void store_data_word (PC_ENV *m, uint16 offset, uint16 val);\r | |
237 | void store_data_word_abs (PC_ENV *m, uint16 segment, uint16 offset, uint16 val);\r | |
238 | \r | |
239 | typedef void (*OP)(PC_ENV *m);\r | |
240 | extern OP i86_optab[256];\r | |
241 | \r | |
242 | /* PRIMITIVE OPERATIONS */\r | |
243 | \r | |
244 | uint8 aad_word (PC_ENV *m, uint16 d);\r | |
245 | uint16 aam_word (PC_ENV *m, uint8 d);\r | |
246 | uint8 adc_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
247 | uint16 adc_word (PC_ENV *m, uint16 d, uint16 s);\r | |
248 | uint8 add_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
249 | uint16 add_word (PC_ENV *m, uint16 d, uint16 s);\r | |
250 | uint8 and_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
251 | uint16 and_word (PC_ENV *m, uint16 d, uint16 s);\r | |
252 | uint8 cmp_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
253 | uint16 cmp_word (PC_ENV *m, uint16 d, uint16 s);\r | |
254 | uint8 dec_byte (PC_ENV *m, uint8 d);\r | |
255 | uint16 dec_word (PC_ENV *m, uint16 d);\r | |
256 | uint8 inc_byte (PC_ENV *m, uint8 d);\r | |
257 | uint16 inc_word (PC_ENV *m, uint16 d);\r | |
258 | uint8 or_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
259 | uint16 or_word (PC_ENV *m, uint16 d, uint16 s);\r | |
260 | uint8 neg_byte (PC_ENV *m, uint8 s);\r | |
261 | uint16 neg_word (PC_ENV *m, uint16 s);\r | |
262 | uint8 not_byte (PC_ENV *m, uint8 s);\r | |
263 | uint16 not_word (PC_ENV *m, uint16 s);\r | |
264 | uint16 mem_access_word (PC_ENV *m, int addr);\r | |
265 | void push_word (PC_ENV *m, uint16 w);\r | |
266 | uint16 pop_word (PC_ENV *m);\r | |
267 | uint8 rcl_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
268 | uint16 rcl_word (PC_ENV *m, uint16 d, uint16 s);\r | |
269 | uint8 rcr_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
270 | uint16 rcr_word (PC_ENV *m, uint16 d, uint16 s);\r | |
271 | uint8 rol_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
272 | uint16 rol_word (PC_ENV *m, uint16 d, uint16 s);\r | |
273 | uint8 ror_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
274 | uint16 ror_word (PC_ENV *m, uint16 d, uint16 s);\r | |
275 | uint8 shl_byte (PC_ENV *m, uint8 d, uint8 s) ;\r | |
276 | uint16 shl_word (PC_ENV *m, uint16 d, uint16 s);\r | |
277 | uint8 shr_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
278 | uint16 shr_word (PC_ENV *m, uint16 d, uint16 s);\r | |
279 | uint8 sar_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
280 | uint16 sar_word (PC_ENV *m, uint16 d, uint16 s);\r | |
281 | uint8 sbb_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
282 | uint16 sbb_word (PC_ENV *m, uint16 d, uint16 s);\r | |
283 | uint8 sub_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
284 | uint16 sub_word (PC_ENV *m, uint16 d, uint16 s);\r | |
285 | void test_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
286 | void test_word (PC_ENV *m, uint16 d, uint16 s);\r | |
287 | uint8 xor_byte (PC_ENV *m, uint8 d, uint8 s);\r | |
288 | uint16 xor_word (PC_ENV *m, uint16 d, uint16 s);\r | |
289 | void imul_byte (PC_ENV *m, uint8 s);\r | |
290 | void imul_word (PC_ENV *m, uint16 s);\r | |
291 | void mul_byte (PC_ENV *m, uint8 s);\r | |
292 | void mul_word (PC_ENV *m, uint16 s);\r | |
293 | void idiv_byte (PC_ENV *m, uint8 s);\r | |
294 | void idiv_word (PC_ENV *m, uint16 s);\r | |
295 | void div_byte (PC_ENV *m, uint8 s);\r | |
296 | void div_word (PC_ENV *m, uint16 s);\r |