FabGL
ESP32 Display Controller and Graphics Library
i8086.cpp
1// =============================================================================
2//
3// Based on code from:
4// * 8086tiny: a tiny, highly functional, highly portable PC emulator/VM
5// Copyright 2013-14, Adrian Cable (adrian.cable@gmail.com) - http://www.megalith.co.uk/8086tiny
6// * 8086tiny plus Revision 1.34 - Copyright 2014 Julian Olds - https://jaybertsoftware.weebly.com/8086-tiny-plus.html
7//
8// This work is licensed under the MIT License. See included LICENSE.TXT.
9//
10// Changes by Fabrizio Di Vittorio
11// - some heavy optimizations
12// - bug fixes on several instructions (HLT, divide by zero interrupt, ROL, ROR, RCL, RCR, SHL, SHR, DAA, DAS)
13// - expanded macros
14// - removed redundant code resulted from macro expansions
15// - moved Flags out of registers file
16// - moved some static variables into auto function vars
17// - moved decodes tables from BIOS to C code
18// - emulator commands executed as INT instead of custom CPU opcodes
19// - reset to 0xffff:0000 as real 8086
20// - LEA, removed mod=11 option
21// - registers moved to different area
22// - memory read/write no more direct but by callbacks
23
24
25
26#include <stdio.h>
27#include <string.h>
28
29#include "i8086.h"
30
31
32namespace fabgl {
33
34
35
36#pragma GCC optimize ("O3")
37
38#if FABGL_ESP_IDF_VERSION > FABGL_ESP_IDF_VERSION_VAL(3, 3, 5)
39 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
40#endif
41
42
43#define VIDEOMEM_START 0xA0000
44#define VIDEOMEM_END 0xC0000
45
46
47// 16-bit register decodes
48
49#define REG_AX 0
50#define REG_CX 1
51#define REG_DX 2
52#define REG_BX 3
53#define REG_SP 4
54#define REG_BP 5
55#define REG_SI 6
56#define REG_DI 7
57
58#define REG_ES 8
59#define REG_CS 9
60#define REG_SS 10
61#define REG_DS 11
62
63#define REG_ZERO 12
64#define REG_SCRATCH 13
65
66#define REG_TMP 15
67
68
69// 8-bit register decodes
70#define REG_AL 0
71#define REG_AH 1
72#define REG_CL 2
73#define REG_CH 3
74#define REG_DL 4
75#define REG_DH 5
76#define REG_BL 6
77#define REG_BH 7
78
79
80// FLAGS
81
82#define CF_ADDR 0
83#define PF_ADDR 1
84#define AF_ADDR 2
85#define ZF_ADDR 3
86#define SF_ADDR 4
87#define TF_ADDR 5
88#define IF_ADDR 6
89#define DF_ADDR 7
90#define OF_ADDR 8
91#define XX_ADDR 9
92
93#define FLAG_CF (flags[CF_ADDR])
94#define FLAG_PF (flags[PF_ADDR])
95#define FLAG_AF (flags[AF_ADDR])
96#define FLAG_ZF (flags[ZF_ADDR])
97#define FLAG_SF (flags[SF_ADDR])
98#define FLAG_TF (flags[TF_ADDR])
99#define FLAG_IF (flags[IF_ADDR])
100#define FLAG_DF (flags[DF_ADDR])
101#define FLAG_OF (flags[OF_ADDR])
102
103
104
105// Global variable definitions
106static uint8_t regs[48];
107static uint8_t flags[10];
108static int32_t regs_offset;
109static uint8_t * regs8, i_mod_size, i_d, i_w, raw_opcode_id, xlat_opcode_id, extra, rep_mode, seg_override_en, rep_override_en;
110static uint16_t * regs16, reg_ip, seg_override;
111static uint32_t op_source, op_dest, set_flags_type;
112static int32_t op_to_addr, op_from_addr;
113
114
115void * i8086::s_context;
116i8086::ReadPort i8086::s_readPort;
117i8086::WritePort i8086::s_writePort;
118i8086::WriteVideoMemory8 i8086::s_writeVideoMemory8;
119i8086::WriteVideoMemory16 i8086::s_writeVideoMemory16;
120i8086::ReadVideoMemory8 i8086::s_readVideoMemory8;
121i8086::ReadVideoMemory16 i8086::s_readVideoMemory16;
122i8086::Interrupt i8086::s_interrupt;
123
124uint8_t * i8086::s_memory;
125bool i8086::s_pendingIRQ;
126uint8_t i8086::s_pendingIRQIndex;
127bool i8086::s_halted;
128
129
130
131
132// Table 0: R/M mode 1/2 "register 1" lookup
133static uint8_t rm_mode12_reg1[] = { 3, 3, 5, 5, 6, 7, 5, 3 };
134
135// Table 1: R/M mode 1/2 "register 2" lookup
136// Table 5: R/M mode 0 "register 2" lookup
137static uint8_t rm_mode012_reg2[] = { 6, 7, 6, 7, 12, 12, 12, 12 };
138
139// Table 2: R/M mode 1/2 "DISP multiplier" lookup
140static uint8_t rm_mode12_disp[] = { 1, 1, 1, 1, 1, 1, 1, 1 };
141
142// Table 3: R/M mode 1/2 "default segment" lookup
143static uint8_t rm_mode12_dfseg[] = { 11, 11, 10, 10, 11, 11, 10, 11 };
144
145// Table 4: R/M mode 0 "register 1" lookup
146static uint8_t rm_mode0_reg1[] = { 3, 3, 5, 5, 6, 7, 12, 3 };
147
148// Table 6: R/M mode 0 "DISP multiplier" lookup
149static uint8_t rm_mode0_disp[] = { 0, 0, 0, 0, 0, 0, 1, 0 };
150
151// Table 7: R/M mode 0 "default segment" lookup
152static uint8_t rm_mode0_dfseg[] = { 11, 11, 10, 10, 11, 11, 11, 11 };
153
154// Table 8: Translation of raw opcode index ("Raw ID") to function number ("Xlat'd ID")
155static uint8_t xlat_ids[] = { 9, 9, 9, 9, 7, 7, 25, 26, 9, 9, 9, 9, 7, 7, 25, 50,
156 9, 9, 9, 9, 7, 7, 25, 26, 9, 9, 9, 9, 7, 7, 25, 26,
157 9, 9, 9, 9, 7, 7, 27, 28, 9, 9, 9, 9, 7, 7, 27, 28,
158 9, 9, 9, 9, 7, 7, 27, 29, 9, 9, 9, 9, 7, 7, 27, 29,
159 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
160 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
161 53, 54, 55, 70, 71, 71, 72, 72, 56, 58, 57, 58, 59, 59, 60, 60,
162 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
163 8, 8, 8, 8, 15, 15, 24, 24, 9, 9, 9, 9, 10, 10, 10, 10,
164 16, 16, 16, 16, 16, 16, 16, 16, 30, 31, 32, 69, 33, 34, 35, 36,
165 11, 11, 11, 11, 17, 17, 18, 18, 47, 47, 17, 17, 17, 17, 18, 18,
166 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
167 12, 12, 19, 19, 37, 37, 20, 20, 51, 52, 19, 19, 38, 39, 40, 19,
168 12, 12, 12, 12, 41, 42, 43, 44, 69, 69, 69, 69, 69, 69, 69, 69,
169 13, 13, 13, 13, 21, 21, 22, 22, 14, 14, 14, 14, 21, 21, 22, 22,
170 48, 0, 23, 23, 49, 45, 6, 6, 46, 46, 46, 46, 46, 46, 5, 5 };
171
172// Table 9: Translation of Raw ID to Extra Data
173static uint8_t ex_data[] = { 0, 0, 0, 0, 0, 0, 8, 8, 1, 1, 1, 1, 1, 1, 9, 36,
174 2, 2, 2, 2, 2, 2, 10, 10, 3, 3, 3, 3, 3, 3, 11, 11,
175 4, 4, 4, 4, 4, 4, 8, 0, 5, 5, 5, 5, 5, 5, 9, 1,
176 6, 6, 6, 6, 6, 6, 10, 2, 7, 7, 7, 7, 7, 7, 11, 0,
177 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
179 0, 0, 21, 21, 21, 21, 21, 21, 0, 0, 0, 0, 21, 21, 21, 21,
180 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
181 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 12, 12, 12, 12,
182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0,
183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1,
184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185 1, 1, 0, 0, 16, 22, 0, 0, 0, 0, 1, 1, 0, 255, 48, 2,
186 0, 0, 0, 0, 255, 255, 40, 11, 3, 3, 3, 3, 3, 3, 3, 3,
187 43, 43, 43, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
188 1, 21, 0, 0, 2, 40, 21, 21, 80, 81, 92, 93, 94, 95, 0, 0 };
189
190// Table 10: How each Raw ID sets the flags (bit 1 = sets SZP, bit 2 = sets AF/OF for arithmetic, bit 3 = sets OF/CF for logic)
191static uint8_t std_flags[] = { 3, 3, 3, 3, 3, 3, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0,
192 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
193 5, 5, 5, 5, 5, 5, 0, 1, 3, 3, 3, 3, 3, 3, 0, 1,
194 5, 5, 5, 5, 5, 5, 0, 1, 3, 3, 3, 3, 3, 3, 0, 1,
195 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
196 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
197 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
198 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199 1, 1, 1, 1, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
201 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0,
202 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
203 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
204 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
205 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
206 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
207
208// Table 11: Parity flag loop-up table (256 entries)
209static uint8_t parity[] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
210 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
211 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
212 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
213 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
214 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
215 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
216 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
217 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
218 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
219 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
220 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
221 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
222 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
223 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
224 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 };
225
226// Table 12: Translation of Raw ID to base instruction size (bytes)
227static uint8_t base_size[] = { 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2,
228 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1,
229 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1,
230 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1,
231 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
232 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
233 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 1, 1, 1,
234 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
235 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
236 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
237 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
238 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
239 3, 3, 0, 0, 2, 2, 2, 2, 4, 1, 0, 0, 0, 0, 0, 0,
240 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
241 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1,
242 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2 };
243
244// Table 13: Translation of Raw ID to i_w size adder yes/no
245static uint8_t i_w_adder[] = { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
246 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
247 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
248 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
251 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
252 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
253 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
254 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
255 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
256 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
257 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
258 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
259 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
260 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
261
262// Table 14: Translation of Raw ID to i_mod size adder yes/no
263static uint8_t i_mod_adder[] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
264 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
265 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
266 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
271 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
275 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
276 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
279
280// Table 15: Jxx decode table A
281static uint8_t jxx_dec_a[] = { OF_ADDR, CF_ADDR, ZF_ADDR, CF_ADDR, SF_ADDR, PF_ADDR, XX_ADDR, XX_ADDR };
282
283// Table 16: Jxx decode table B
284static uint8_t jxx_dec_b[] = { XX_ADDR, XX_ADDR, XX_ADDR, ZF_ADDR, XX_ADDR, XX_ADDR, XX_ADDR, ZF_ADDR };
285
286// Table 17: Jxx decode table C
287static uint8_t jxx_dec_c[] = { XX_ADDR, XX_ADDR, XX_ADDR,XX_ADDR, XX_ADDR, XX_ADDR, SF_ADDR, SF_ADDR };
288
289// Table 18: Jxx decode table D
290static uint8_t jxx_dec_d[] = { XX_ADDR, XX_ADDR, XX_ADDR, XX_ADDR,XX_ADDR, XX_ADDR, OF_ADDR, OF_ADDR };
291
292
293static uint8_t * instr_table_lookup[] = { rm_mode12_reg1, // 0
294 rm_mode012_reg2, // 1
295 rm_mode12_disp, // 2
296 rm_mode12_dfseg, // 3
297 rm_mode0_reg1, // 4
298 rm_mode012_reg2, // 5
299 rm_mode0_disp, // 6
300 rm_mode0_dfseg, // 7
301 xlat_ids, // 8 TABLE_XLAT_OPCODE
302 ex_data, // 9 TABLE_XLAT_SUBFUNCTION
303 std_flags, // 10 TABLE_STD_FLAGS
304 parity, // 11 TABLE_PARITY_FLAG
305 base_size, // 12 TABLE_BASE_INST_SIZE
306 i_w_adder, // 13 TABLE_I_W_SIZE
307 i_mod_adder, // 14 TABLE_I_MOD_SIZE
308 };
309
310
311
312
313void i8086::setAL(uint8_t value)
314{
315 regs8[REG_AL] = value;
316}
317
318
319void i8086::setAH(uint8_t value)
320{
321 regs8[REG_AH] = value;
322}
323
324
325uint8_t i8086::AL()
326{
327 return regs8[REG_AL];
328}
329
330
331uint8_t i8086::AH()
332{
333 return regs8[REG_AH];
334}
335
336
337void i8086::setBL(uint8_t value)
338{
339 regs8[REG_BL] = value;
340}
341
342
343void i8086::setBH(uint8_t value)
344{
345 regs8[REG_BH] = value;
346}
347
348
349uint8_t i8086::BL()
350{
351 return regs8[REG_BL];
352}
353
354
355uint8_t i8086::BH()
356{
357 return regs8[REG_BH];
358}
359
360
361void i8086::setCL(uint8_t value)
362{
363 regs8[REG_CL] = value;
364}
365
366
367void i8086::setCH(uint8_t value)
368{
369 regs8[REG_CH] = value;
370}
371
372
373uint8_t i8086::CL()
374{
375 return regs8[REG_CL];
376}
377
378
379uint8_t i8086::CH()
380{
381 return regs8[REG_CH];
382}
383
384
385void i8086::setDL(uint8_t value)
386{
387 regs8[REG_DL] = value;
388}
389
390
391void i8086::setDH(uint8_t value)
392{
393 regs8[REG_DH] = value;
394}
395
396
397uint8_t i8086::DL()
398{
399 return regs8[REG_DL];
400}
401
402
403uint8_t i8086::DH()
404{
405 return regs8[REG_DH];
406}
407
408
409void i8086::setAX(uint16_t value)
410{
411 regs16[REG_AX] = value;
412}
413
414
415void i8086::setBX(uint16_t value)
416{
417 regs16[REG_BX] = value;
418}
419
420
421void i8086::setCX(uint16_t value)
422{
423 regs16[REG_CX] = value;
424}
425
426
427void i8086::setDX(uint16_t value)
428{
429 regs16[REG_DX] = value;
430}
431
432
433void i8086::setDI(uint16_t value)
434{
435 regs16[REG_DI] = value;
436}
437
438
439void i8086::setCS(uint16_t value)
440{
441 regs16[REG_CS] = value;
442}
443
444
445void i8086::setDS(uint16_t value)
446{
447 regs16[REG_DS] = value;
448}
449
450
451void i8086::setSS(uint16_t value)
452{
453 regs16[REG_SS] = value;
454}
455
456
457void i8086::setES(uint16_t value)
458{
459 regs16[REG_ES] = value;
460}
461
462
463void i8086::setIP(uint16_t value)
464{
465 reg_ip = value;
466}
467
468
469uint16_t i8086::IP()
470{
471 return reg_ip;
472}
473
474
475void i8086::setSP(uint16_t value)
476{
477 regs16[REG_SP] = value;
478}
479
480
481uint16_t i8086::AX()
482{
483 return regs16[REG_AX];
484}
485
486
487uint16_t i8086::BX()
488{
489 return regs16[REG_BX];
490}
491
492
493uint16_t i8086::CX()
494{
495 return regs16[REG_CX];
496}
497
498
499uint16_t i8086::DX()
500{
501 return regs16[REG_DX];
502}
503
504
505uint16_t i8086::BP()
506{
507 return regs16[REG_BP];
508}
509
510
511uint16_t i8086::SI()
512{
513 return regs16[REG_SI];
514}
515
516
517uint16_t i8086::DI()
518{
519 return regs16[REG_DI];
520}
521
522
523uint16_t i8086::SP()
524{
525 return regs16[REG_SP];
526}
527
528
529uint16_t i8086::CS()
530{
531 return regs16[REG_CS];
532}
533
534
535uint16_t i8086::ES()
536{
537 return regs16[REG_ES];
538}
539
540
541uint16_t i8086::DS()
542{
543 return regs16[REG_DS];
544}
545
546
547uint16_t i8086::SS()
548{
549 return regs16[REG_SS];
550}
551
552
553bool i8086::flagIF()
554{
555 return FLAG_IF;
556}
557
558
559bool i8086::flagTF()
560{
561 return FLAG_TF;
562}
563
564
565bool i8086::flagCF()
566{
567 return FLAG_CF;
568}
569
570
571bool i8086::flagZF()
572{
573 return FLAG_ZF;
574}
575
576bool i8086::flagOF()
577{
578 return FLAG_OF;
579}
580
581bool i8086::flagDF()
582{
583 return FLAG_DF;
584}
585
586bool i8086::flagSF()
587{
588 return FLAG_SF;
589}
590
591bool i8086::flagAF()
592{
593 return FLAG_AF;
594}
595
596bool i8086::flagPF()
597{
598 return FLAG_PF;
599}
600
601void i8086::setFlagZF(bool value)
602{
603 FLAG_ZF = value;
604}
605
606
607void i8086::setFlagCF(bool value)
608{
609 FLAG_CF = value;
610}
611
612
613
614
615// ret false if not acked
616bool i8086::IRQ(uint8_t interrupt_num)
617{
618 if (!s_pendingIRQ) {
619 s_pendingIRQ = true;
620 s_pendingIRQIndex = interrupt_num;
621 return true;
622 } else {
623 return false;
624 }
625}
626
627
628
630
631
632// direct RAM access (not video RAM)
633#define MEM8(addr) s_memory[addr]
634#define MEM16(addr) (*(uint16_t*)(s_memory + (addr)))
635
636
637uint8_t i8086::RMEM8(int addr)
638{
639 if (addr >= VIDEOMEM_START && addr < VIDEOMEM_END) {
640 return s_readVideoMemory8(s_context, addr);
641 } else {
642 return s_memory[addr];
643 }
644}
645
646
647uint16_t i8086::RMEM16(int addr)
648{
649 if (addr >= VIDEOMEM_START && addr < VIDEOMEM_END) {
650 return s_readVideoMemory16(s_context, addr);
651 } else {
652 return *(uint16_t*)(s_memory + addr);
653 }
654}
655
656
657inline __attribute__((always_inline)) uint8_t i8086::WMEM8(int addr, uint8_t value)
658{
659 if (addr >= VIDEOMEM_START && addr < VIDEOMEM_END) {
660 s_writeVideoMemory8(s_context, addr, value);
661 } else {
662 s_memory[addr] = value;
663 }
664 return value;
665}
666
667
668inline __attribute__((always_inline)) uint16_t i8086::WMEM16(int addr, uint16_t value)
669{
670 if (addr >= VIDEOMEM_START && addr < VIDEOMEM_END) {
671 s_writeVideoMemory16(s_context, addr, value);
672 } else {
673 *(uint16_t*)(s_memory + addr) = value;
674 }
675 return value;
676}
677
679
680
681
682// Set auxiliary and overflow flag after arithmetic operations
683void IRAM_ATTR set_AF_OF_arith(int32_t op_result)
684{
685 FLAG_AF = (bool)((op_source ^= op_dest ^ op_result) & 0x10);
686 if (op_result == op_dest)
687 FLAG_OF = 0;
688 else
689 FLAG_OF = 1 & (FLAG_CF ^ op_source >> (8 * (i_w + 1) - 1));
690}
691
692
693// Assemble and return emulated CPU FLAGS register
694uint16_t IRAM_ATTR i8086::make_flags()
695{
696 #if I80186MODE
697 uint16_t r = 0x0002; // to pass test186 tests, just unused bit nr. 1 is set to 1 (some programs checks this to know if this is a 80186 or 8086)
698 #else
699 uint16_t r = 0xf002; // for real 8086
700 #endif
701
702 return r | FLAG_CF << 0 | FLAG_PF << 2 | FLAG_AF << 4 | FLAG_ZF << 6 | FLAG_SF << 7 | FLAG_TF << 8 | FLAG_IF << 9 | FLAG_DF << 10 | FLAG_OF << 11;
703}
704
705
706void IRAM_ATTR i8086::set_flags(int new_flags)
707{
708 FLAG_CF = (bool)(new_flags & 0x001);
709 FLAG_PF = (bool)(new_flags & 0x004);
710 FLAG_AF = (bool)(new_flags & 0x010);
711 FLAG_ZF = (bool)(new_flags & 0x040);
712 FLAG_SF = (bool)(new_flags & 0x080);
713 FLAG_TF = (bool)(new_flags & 0x100);
714 FLAG_IF = (bool)(new_flags & 0x200);
715 FLAG_DF = (bool)(new_flags & 0x400);
716 FLAG_OF = (bool)(new_flags & 0x800);
717}
718
719
720// Convert raw opcode to translated opcode index. This condenses a large number of different encodings of similar
721// instructions into a much smaller number of distinct functions, which we then execute
722void IRAM_ATTR set_opcode(uint8_t opcode)
723{
724 raw_opcode_id = opcode;
725 xlat_opcode_id = xlat_ids[opcode];
726 extra = ex_data[opcode];
727 i_mod_size = i_mod_adder[opcode];
728 set_flags_type = std_flags[opcode];
729}
730
731
732// Execute INT #interrupt_num on the emulated machine
733void IRAM_ATTR i8086::pc_interrupt(uint8_t interrupt_num)
734{
735 // fab: interrupt can exit from halt state
736 if (s_halted) {
737 s_halted = false;
738 ++reg_ip; // go to next instruction after HLT
739 }
740
741 if (!s_interrupt(s_context, interrupt_num)) {
742 uint16_t newIP = MEM16(4 * interrupt_num);
743 uint16_t newCS = MEM16(4 * interrupt_num + 2);
744
745 regs16[REG_SP] -= 6;
746 uint16_t * stack = &MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
747 stack[2] = make_flags();
748 stack[1] = regs16[REG_CS];
749 stack[0] = reg_ip;
750
751 reg_ip = newIP;
752 regs16[REG_CS] = newCS;
753
754 FLAG_TF = FLAG_IF = 0;
755 }
756}
757
758
759// fab: necessary to go back to the first instruction prefix
760uint8_t i8086::raiseDivideByZeroInterrupt()
761{
762 if (seg_override_en || rep_override_en) {
763 // go back looking for segment prefixes or REP prefixes
764 while (true) {
765 uint8_t opcode = MEM8(16 * regs16[REG_CS] + reg_ip - 1);
766 // break if not REP and SEG
767 if ((opcode & 0xfe) != 0xf2 && (opcode & 0xe7) != 0x26)
768 break;
769 --reg_ip;
770 }
771 }
772 pc_interrupt(0);
773 return 0;
774}
775
776
777// AAA and AAS instructions - which_operation is +1 for AAA, and -1 for AAS
778static int32_t AAA_AAS()
779{
780 FLAG_AF = FLAG_CF = ((regs8[REG_AL] & 0x0F) > 9) || FLAG_AF;
781 regs16[REG_AX] += 262 * (extra - 1) * FLAG_AF;
782 return regs8[REG_AL] &= 0x0F;
783}
784
785
786static int32_t DAA_DAS()
787{
788 // fab: fixed to pass test186
789 i_w = 0;
790 FLAG_AF = (regs8[REG_AL] & 0x0f) > 9 || FLAG_AF;
791 FLAG_CF = regs8[REG_AL] > 0x99 || FLAG_CF;
792 if (extra) {
793 // DAS
794 if (FLAG_CF)
795 regs8[REG_AL] -= 0x60;
796 else if (FLAG_AF)
797 FLAG_CF = (regs8[REG_AL] < 6);
798 if (FLAG_AF)
799 regs8[REG_AL] -= 6;
800 } else {
801 // DAA
802 if (FLAG_CF)
803 regs8[REG_AL] += 0x60;
804 if (FLAG_AF)
805 regs8[REG_AL] += 6;
806 }
807 return regs8[REG_AL];
808}
809
810
811void i8086::reset()
812{
813 regs_offset = (int32_t)(regs - s_memory);
814
815 regs8 = (uint8_t *)(s_memory + regs_offset);
816 regs16 = (uint16_t *)(s_memory + regs_offset);
817
818 memset(regs8, 0, sizeof(regs));
819 set_flags(0);
820
821 // Initialise CPU state variables
822 seg_override_en = 0;
823 rep_override_en = 0;
824
825 s_halted = false;
826
827 regs16[REG_CS] = 0xffff;
828 reg_ip = 0;
829}
830
831
832// tries to make more compact opcode "switch"
833static uint8_t optcodes[] = {
834// 0 1 2 3 4 5 6 7 8 9 a b c d e f
835 0, 0, 0, 0, 0, 0, 13, 12, 0, 0, 0, 0, 0, 0, 13, 0, // 00 - 0f
836 0, 0, 0, 0, 0, 0, 13, 12, 0, 0, 0, 0, 0, 0, 13, 12, // 10 - 1f
837 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, // 20 - 2f
838 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, // 30 - 3f
839 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40 - 4f
840 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, // 50 - 5f
841 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60 - 6f
842 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 70 - 7f
843 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, // 80 - 8f
844 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90 - 9f
845 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a0 - af
846 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, // b0 - bf
847 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 17, 0, 15, 0, 16, // c0 - cf
848 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // d0 - df
849 0, 0, 0, 5, 0, 0, 0, 0, 6, 0, 0, 3, 0, 0, 0, 0, // e0 - ef
850 0, 0, 14, 14, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 0, 0, // f0 - ff
851};
852
853
854void IRAM_ATTR i8086::step()
855{
856
857 // Interrupts handling
858 // Following instructions inhibits interrupts for the next instruction:
859 // MOV SS, xxx [opcode 0x8e]
860 // POP SS [opcode 0x17]
861 // STI [opcode 0xfb]
862 // They are hard coded inside below loop, repeating it using "break" instead of "return"
863
864 // Application has set trap flag, so fire INT 1
865 if (FLAG_TF && !seg_override_en && !rep_override_en) {
866 pc_interrupt(1);
867 }
868 // Check for interrupts triggered by system interfaces
869 else if (FLAG_IF && s_pendingIRQ && !seg_override_en && !rep_override_en) {
870 pc_interrupt(s_pendingIRQIndex);
871 s_pendingIRQ = false;
872 }
873
874 // Instructions handling
875
876 PSRAM_WORKAROUND2
877
878 // external interrupts allowed only out of this loop
879 while (true) {
880
881 // seg_override_en and rep_override_en contain number of instructions to hold segment override and REP prefix respectively
882 if (seg_override_en)
883 --seg_override_en;
884 if (rep_override_en)
885 --rep_override_en;
886
887 uint8_t const * opcode_stream = s_memory + 16 * regs16[REG_CS] + reg_ip;
888
889 #if I8086_SHOW_OPCODE_STATS
890 static uint32_t opcodeStats[256] = {0};
891 static int opcodeStatsCount = 0;
892 static uint64_t opcodeStatsT0 = esp_timer_get_time();
893 opcodeStats[*opcode_stream] += 1;
894 ++opcodeStatsCount;
895 if ((opcodeStatsCount % 500000000) == 0) {
896 opcodeStatsCount = 0;
897 if (Serial.available()) {
898 Serial.read();
899 printf("\ntime delta = %llu uS\n\n", esp_timer_get_time() - opcodeStatsT0);
900 opcodeStatsT0 = esp_timer_get_time();
901 for (int i = 0; i < 256; ++i) {
902 if (opcodeStats[i] > 0)
903 printf("%d, %02X\n", opcodeStats[i], i);
904 opcodeStats[i] = 0;
905 }
906 printf("\n");
907 }
908 }
909 #endif
910
911 // quick and dirty processing of simple and common instructions
912 switch (optcodes[*opcode_stream]) {
913
914 // SEG ES
915 // SEG CS
916 // SEG SS
917 // SEG DS
918 // opcodes 0x26, 0x2e, 0x36, 0x3e
919 case 1:
920 seg_override_en = 2;
921 seg_override = ex_data[*opcode_stream];
922 if (rep_override_en)
923 ++rep_override_en;
924 ++reg_ip;
925 return;
926
927 // JO
928 // JNO
929 // JB/JNAE/JC
930 // JAE/JNB/JNC
931 // JE/JZ
932 // JNE/JNZ
933 // JBE/JNA
934 // JA/JNBE
935 // JS
936 // JNS
937 // JP/JPE
938 // JNP/JPO
939 // JL/JNGE
940 // JGE/JNL
941 // JLE/JNG
942 // JG/JNLE
943 // opcodes 0x70 ... 0x7f
944 case 2:
945 {
946 int32_t inv = *opcode_stream & 1; // inv is the invert flag, e.g. 1 means JNAE, whereas 0 means JAE
947 int32_t idx = (*opcode_stream >> 1) & 7;
948 reg_ip += 2 + (int8_t)opcode_stream[1] * (inv ^ (flags[jxx_dec_a[idx]] || flags[jxx_dec_b[idx]] || flags[jxx_dec_c[idx]] ^ flags[jxx_dec_d[idx]]));
949 return;
950 }
951
952 // JMP disp8
953 // opcode 0xeb
954 case 3:
955 reg_ip += 2 + (int8_t)opcode_stream[1];
956 return;
957
958 // CLC|STC|CLI|STI|CLD|STD
959 // opcodes 0xf8 ... 0xfd
960 case 4:
961 {
962 static int16_t FADDR[3] = { CF_ADDR, IF_ADDR, DF_ADDR };
963 flags[FADDR[(*opcode_stream >> 1) & 3]] = *opcode_stream & 1;
964 ++reg_ip;
965 break; // reloop, this is required to inhibit interrupt until next instruction (actually should be just for STI...)
966 }
967
968 // JCXZ
969 // opcode 0xe3
970 case 5:
971 reg_ip += 2 + !regs16[REG_CX] * (int8_t)opcode_stream[1];
972 return;
973
974 // CALL disp16
975 // opcode 0xe8
976 case 6:
977 {
978 uint16_t pIP = reg_ip + 3;
979 reg_ip = pIP + *(uint16_t*)(opcode_stream + 1);
980 regs16[REG_SP] -= 2;
981 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = pIP;
982 return;
983 }
984
985 // RET (intrasegment)
986 // opcode 0xc3
987 case 7:
988 reg_ip = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
989 regs16[REG_SP] += 2;
990 return;
991
992 // POP reg
993 // opcodes 0x58 ... 0x5f
994 case 8:
995 regs16[REG_SP] += 2; // SP may be read from stack, so we have to increment here
996 regs16[*opcode_stream & 7] = MEM16(16 * regs16[REG_SS] + (uint16_t)(regs16[REG_SP] - 2));
997 ++reg_ip;
998 return;
999
1000 // PUSH reg
1001 // opcodes 0x50 ... 0x57
1002 case 9:
1003 regs16[REG_SP] -= 2;
1004 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[*opcode_stream & 7];
1005 ++reg_ip;
1006 return;
1007
1008 // MOV reg8, data8
1009 // opcodes 0xb0 ... 0xb7
1010 case 10:
1011 regs8[((*opcode_stream >> 2) & 1) + (*opcode_stream & 3) * 2] = *(opcode_stream + 1);
1012 reg_ip += 2;
1013 return;
1014
1015 // MOV reg16, data16
1016 // opcodes 0xb8 ... 0xbf
1017 case 11:
1018 regs16[*opcode_stream & 0x7] = *(uint16_t*)(opcode_stream + 1);
1019 reg_ip += 3;
1020 return;
1021
1022 // POP ES
1023 // POP SS
1024 // POP DS
1025 // opcodes 0x07 0x17 0x1f
1026 case 12:
1027 regs16[REG_ES + (*opcode_stream >> 3)] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1028 regs16[REG_SP] += 2;
1029 ++reg_ip;
1030 break; // reloop, this is required to inhibit interrupt until next instruction (actually just for POP SS)
1031
1032 // PUSH ES
1033 // PUSH CS (80186)
1034 // PUSH SS
1035 // PUSH DS
1036 // opcodes 0x06 0x0e 0x16 0x1e
1037 case 13:
1038 regs16[REG_SP] -= 2;
1039 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_ES + (*opcode_stream >> 3)];
1040 ++reg_ip;
1041 return;
1042
1043 // REP / REPE / REPNE / REPNZ / REPZ
1044 // opcodes 0xf2 0xf3
1045 case 14:
1046 rep_override_en = 2;
1047 rep_mode = *opcode_stream & 1;
1048 if (seg_override_en)
1049 ++seg_override_en;
1050 ++reg_ip;
1051 return;
1052
1053 // INT imm8
1054 // opcode 0xcd
1055 case 15:
1056 reg_ip += 2;
1057 pc_interrupt(opcode_stream[1]);
1058 return;
1059
1060 // IRET
1061 // opcode 0xcf
1062 case 16:
1063 {
1064 uint16_t * stack = &MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1065 reg_ip = stack[0];
1066 regs16[REG_CS] = stack[1];
1067 set_flags(stack[2]);
1068 regs16[REG_SP] += 6;
1069 return;
1070 }
1071
1072 // RETF (intersegment RET)
1073 // opcode 0xcb
1074 case 17:
1075 {
1076 uint16_t * stack = &MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1077 reg_ip = stack[0];
1078 regs16[REG_CS] = stack[1];
1079 regs16[REG_SP] += 4;
1080 return;
1081 }
1082
1083 // MOV SS, r/m
1084 case 18:
1085 stepEx(opcode_stream);
1086 break; // reloop, this is required to inhibit interrupt until next instruction
1087
1088 default:
1089 stepEx(opcode_stream);
1090 return;
1091
1092 }
1093
1094 };
1095
1096}
1097
1098
1099void IRAM_ATTR i8086::stepEx(uint8_t const * opcode_stream)
1100{
1101 set_opcode(*opcode_stream);
1102
1103 // Extract fields from instruction
1104 uint8_t i_reg4bit = raw_opcode_id & 7;
1105 i_w = i_reg4bit & 1;
1106 i_d = i_reg4bit / 2 & 1;
1107
1108 // Extract instruction data fields
1109 uint16_t i_data0 = opcode_stream[1] | (opcode_stream[2] << 8);
1110 uint16_t i_data1 = (i_data0 >> 8) | (opcode_stream[3] << 8);
1111 uint16_t i_data2 = (i_data1 >> 8) | (opcode_stream[4] << 8);
1112
1113 uint8_t i_mod = 0, i_rm = 0, i_reg = 0;
1114 int32_t op_result = 0;
1115 int32_t rm_addr = 0;
1116
1117 bool calcIP = true;
1118
1119 // i_mod_size > 0 indicates that opcode uses i_mod/i_rm/i_reg, so decode them
1120 if (i_mod_size) {
1121 i_mod = (i_data0 & 0xFF) >> 6;
1122 i_rm = i_data0 & 7;
1123 i_reg = i_data0 / 8 & 7;
1124
1125 if ((!i_mod && i_rm == 6) || (i_mod == 2))
1126 i_data2 = (i_data2 >> 8) | (opcode_stream[5] << 8);
1127 else if (i_mod != 1)
1128 i_data2 = i_data1;
1129 else // If i_mod is 1, operand is (usually) 8 bits rather than 16 bits
1130 i_data1 = (int8_t) i_data1;
1131
1132 int idx = 4 * !i_mod;
1133 op_to_addr = rm_addr = i_mod < 3 ? 16 * regs16[seg_override_en ? seg_override : instr_table_lookup[idx + 3][i_rm]] + (uint16_t)(regs16[instr_table_lookup[idx + 1][i_rm]] + instr_table_lookup[idx + 2][i_rm] * i_data1 + regs16[instr_table_lookup[idx][i_rm]]) : (regs_offset + (i_w ? 2 * i_rm : (2 * i_rm + i_rm / 4) & 7));
1134 op_from_addr = regs_offset + (i_w ? 2 * i_reg : (2 * i_reg + i_reg / 4) & 7);
1135 if (i_d) {
1136 auto t = op_from_addr;
1137 op_from_addr = rm_addr;
1138 op_to_addr = t;
1139 }
1140 }
1141
1142 // Instruction execution unit
1143 switch (xlat_opcode_id) {
1144 case 2: // INC|DEC regs16
1145 {
1146 i_w = 1;
1147 i_d = 0;
1148 i_reg = i_reg4bit;
1149 int idx = 4 * !i_mod;
1150 op_to_addr = rm_addr = i_mod < 3 ? 16 * regs16[seg_override_en ? seg_override : instr_table_lookup[idx + 3][i_rm]] + (uint16_t)(regs16[instr_table_lookup[idx + 1][i_rm]] + instr_table_lookup[idx + 2][i_rm] * i_data1 + regs16[instr_table_lookup[idx][i_rm]]) : (regs_offset + 2 * i_rm);
1151 op_from_addr = regs_offset + 2 * i_reg;
1152 i_reg = extra;
1153 } // not break!
1154 case 5: // INC|DEC|JMP|CALL|PUSH
1155 if (i_reg < 2) {
1156 // INC|DEC
1157 if (i_w) {
1158 op_dest = RMEM16(op_from_addr);
1159 op_result = WMEM16(op_from_addr, (uint16_t)op_dest + 1 - 2 * i_reg);
1160 } else {
1161 op_dest = RMEM8(op_from_addr);
1162 op_result = WMEM8(op_from_addr, (uint16_t)op_dest + 1 - 2 * i_reg);
1163 }
1164 op_source = 1;
1165 set_AF_OF_arith(op_result);
1166 FLAG_OF = (bool)(op_dest + 1 - i_reg == 1 << (8 * (i_w + 1) - 1));
1167 if (xlat_opcode_id == 5) {
1168 // Decode like ADC (0x10)
1169 xlat_opcode_id = 0x10;
1170 set_flags_type = 1;
1171 }
1172 } else if (i_reg != 6) {
1173 // JMP|CALL
1174 uint16_t jumpTo = i_w ? MEM16(op_from_addr) : MEM8(op_from_addr);
1175 if (i_reg - 3 == 0) {
1176 // CALL (far)
1177 i_w = 1;
1178 regs16[REG_SP] -= 2;
1179 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_CS];
1180 }
1181 if (i_reg & 2) {
1182 // CALL (near or far)
1183 i_w = 1;
1184 regs16[REG_SP] -= 2;
1185 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = (reg_ip + 2 + i_mod * (i_mod != 3) + 2 * (!i_mod && i_rm == 6));
1186 }
1187 if (i_reg & 1) {
1188 // JMP|CALL (far)
1189 PSRAM_WORKAROUND2
1190 regs16[REG_CS] = MEM16(op_from_addr + 2);
1191 }
1192 reg_ip = jumpTo;
1193 return; // no calc IP, no flags
1194 } else {
1195 // PUSH
1196 i_w = 1;
1197 regs16[REG_SP] -= 2;
1198 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = RMEM16(rm_addr);
1199 }
1200 break;
1201 case 6: // TEST r/m, imm16 / NOT|NEG|MUL|IMUL|DIV|IDIV reg
1202 op_to_addr = op_from_addr;
1203
1204 switch (i_reg) {
1205 case 0: // TEST
1206 // Decode like AND (0x20)
1207 raw_opcode_id = 0x20;
1208 set_flags_type = 5;
1209
1210 reg_ip += i_w + 1;
1211 if (i_w) {
1212 op_dest = RMEM16(op_to_addr);
1213 op_source = (uint16_t)i_data2;
1214 op_result = (uint16_t)(op_dest & op_source);
1215 } else {
1216 op_dest = RMEM8(op_to_addr);
1217 op_source = (uint8_t)i_data2;
1218 op_result = (uint8_t)(op_dest & op_source);
1219 }
1220 break;
1221 case 2: // NOT
1222 if (i_w)
1223 WMEM16(op_to_addr, ~RMEM16(op_from_addr));
1224 else
1225 WMEM8(op_to_addr, ~RMEM8(op_from_addr));
1226 break;
1227 case 3: // NEG
1228 if (i_w)
1229 op_result = WMEM16(op_to_addr, -(op_source = RMEM16(op_from_addr)));
1230 else
1231 op_result = WMEM8(op_to_addr, -(op_source = RMEM8(op_from_addr)));
1232 op_dest = 0;
1233
1234 // Decode like SUB (0x28)
1235 raw_opcode_id = 0x28;
1236 set_flags_type = 3;
1237
1238 FLAG_CF = op_result > op_dest;
1239 break;
1240 case 4: // MUL
1241 raw_opcode_id = 0x10;
1242 set_flags_type = 1;
1243 if (i_w) {
1244 regs16[REG_DX] = (op_result = RMEM16(rm_addr) * regs16[REG_AX]) >> 16;
1245 regs16[REG_AX] = op_result;
1246 FLAG_OF = FLAG_CF = (bool)(op_result - (uint16_t)op_result);
1247 } else {
1248 regs16[REG_AX] = op_result = RMEM8(rm_addr) * regs8[REG_AL];
1249 FLAG_OF = FLAG_CF = (bool)(op_result - (uint8_t) op_result);
1250 }
1251 break;
1252 case 5: // IMUL
1253 raw_opcode_id = 0x10;
1254 set_flags_type = 1;
1255 if (i_w) {
1256 regs16[REG_DX] = (op_result = (int16_t)RMEM16(rm_addr) * (int16_t)regs16[REG_AX]) >> 16;
1257 regs16[REG_AX] = op_result;
1258 FLAG_OF = FLAG_CF = (bool)(op_result - (int16_t)op_result);
1259 } else {
1260 regs16[REG_AX] = op_result = (int8_t)RMEM8(rm_addr) * (int8_t)regs8[REG_AL];
1261 FLAG_OF = FLAG_CF = (bool)(op_result - (int8_t) op_result);
1262 }
1263 break;
1264 case 6: // DIV
1265 {
1266 int32_t scratch_int;
1267 int32_t scratch_uint, scratch2_uint;
1268 if (i_w) {
1269 (scratch_int = RMEM16(rm_addr))
1270 &&
1271 !(scratch2_uint = (uint32_t)(scratch_uint = (regs16[REG_DX] << 16) + regs16[REG_AX]) / scratch_int, scratch2_uint - (uint16_t) scratch2_uint)
1272 ?
1273 regs16[REG_DX] = scratch_uint - scratch_int * (regs16[REG_AX] = scratch2_uint)
1274 :
1275 (raiseDivideByZeroInterrupt(), calcIP = false);
1276 } else {
1277 (scratch_int = RMEM8(rm_addr))
1278 &&
1279 !(scratch2_uint = (uint16_t)(scratch_uint = regs16[REG_AX]) / scratch_int, scratch2_uint - (uint8_t) scratch2_uint)
1280 ?
1281 regs8[REG_AH] = scratch_uint - scratch_int * (regs8[REG_AL] = scratch2_uint)
1282 :
1283 (raiseDivideByZeroInterrupt(), calcIP = false);
1284 }
1285 break;
1286 }
1287 case 7: // IDIV
1288 {
1289 int32_t scratch_int;
1290 int32_t scratch2_uint, scratch_uint;
1291 if (i_w) {
1292 (scratch_int = (int16_t)RMEM16(rm_addr))
1293 &&
1294 !(scratch2_uint = (int)(scratch_uint = (regs16[REG_DX] << 16) + regs16[REG_AX]) / scratch_int, scratch2_uint - (int16_t) scratch2_uint)
1295 ?
1296 regs16[REG_DX] = scratch_uint - scratch_int * (regs16[REG_AX] = scratch2_uint)
1297 :
1298 (raiseDivideByZeroInterrupt(), calcIP = false);
1299 } else {
1300 (scratch_int = (int8_t)RMEM8(rm_addr))
1301 &&
1302 !(scratch2_uint = (int16_t)(scratch_uint = regs16[REG_AX]) / scratch_int, scratch2_uint - (int8_t) scratch2_uint)
1303 ?
1304 regs8[REG_AH] = scratch_uint - scratch_int * (regs8[REG_AL] = scratch2_uint)
1305 :
1306 (raiseDivideByZeroInterrupt(), calcIP = false);
1307 }
1308 break;
1309 }
1310 };
1311 break;
1312 case 7: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP AL/AX, immed
1313 rm_addr = regs_offset;
1314 i_data2 = i_data0;
1315 i_mod = 3;
1316 i_reg = extra;
1317 reg_ip--;
1318 // not break!
1319 case 8: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP reg, immed
1320 op_to_addr = rm_addr;
1321 regs16[REG_SCRATCH] = (i_d |= !i_w) ? (int8_t) i_data2 : i_data2;
1322 op_from_addr = regs_offset + 2 * REG_SCRATCH;
1323 reg_ip += !i_d + 1;
1324 set_opcode(0x08 * (extra = i_reg));
1325 // not break!
1326 case 9: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP|MOV reg, r/m
1327 switch (extra) {
1328 case 0: // ADD
1329 if (i_w) {
1330 op_dest = RMEM16(op_to_addr);
1331 op_source = RMEM16(op_from_addr);
1332 op_result = (uint16_t)(op_dest + op_source);
1333 WMEM16(op_to_addr, op_result);
1334 } else {
1335 op_dest = RMEM8(op_to_addr);
1336 op_source = RMEM8(op_from_addr);
1337 op_result = (uint8_t)(op_dest + op_source);
1338 WMEM8(op_to_addr, op_result);
1339 }
1340 FLAG_CF = op_result < op_dest;
1341 break;
1342 case 1: // OR
1343 if (i_w) {
1344 op_dest = RMEM16(op_to_addr);
1345 op_source = RMEM16(op_from_addr);
1346 op_result = op_dest | op_source;
1347 WMEM16(op_to_addr, op_result);
1348 } else {
1349 op_dest = RMEM8(op_to_addr);
1350 op_source = RMEM8(op_from_addr);
1351 op_result = op_dest | op_source;
1352 WMEM8(op_to_addr, op_result);
1353 }
1354 break;
1355 case 2: // ADC
1356 if (i_w) {
1357 op_dest = RMEM16(op_to_addr);
1358 op_source = RMEM16(op_from_addr);
1359 op_result = WMEM16(op_to_addr, op_dest + FLAG_CF + op_source);
1360 } else {
1361 op_dest = RMEM8(op_to_addr);
1362 op_source = RMEM8(op_from_addr);
1363 op_result = WMEM8(op_to_addr, op_dest + FLAG_CF + op_source);
1364 }
1365 FLAG_CF = (FLAG_CF && (op_result == op_dest)) || (op_result < (int) op_dest);
1366 set_AF_OF_arith(op_result);
1367 break;
1368 case 3: // SBB
1369 if (i_w) {
1370 op_dest = RMEM16(op_to_addr);
1371 op_source = RMEM16(op_from_addr);
1372 op_result = WMEM16(op_to_addr, op_dest - (FLAG_CF + op_source));
1373 } else {
1374 op_dest = RMEM8(op_to_addr);
1375 op_source = RMEM8(op_from_addr);
1376 op_result = WMEM8(op_to_addr, op_dest - (FLAG_CF + op_source));
1377 }
1378 FLAG_CF = (FLAG_CF && (op_result == op_dest)) || (-op_result < -(int) op_dest);
1379 set_AF_OF_arith(op_result);
1380 break;
1381 case 4: // AND
1382 if (i_w) {
1383 op_dest = RMEM16(op_to_addr);
1384 op_source = RMEM16(op_from_addr);
1385 op_result = op_dest & op_source;
1386 WMEM16(op_to_addr, op_result);
1387 } else {
1388 op_dest = RMEM8(op_to_addr);
1389 op_source = RMEM8(op_from_addr);
1390 op_result = op_dest & op_source;
1391 WMEM8(op_to_addr, op_result);
1392 }
1393 break;
1394 case 5: // SUB
1395 if (i_w) {
1396 op_dest = RMEM16(op_to_addr);
1397 op_source = RMEM16(op_from_addr);
1398 op_result = WMEM16(op_to_addr, op_dest - op_source);
1399 } else {
1400 op_dest = RMEM8(op_to_addr);
1401 op_source = RMEM8(op_from_addr);
1402 op_result = WMEM8(op_to_addr, op_dest - op_source);
1403 }
1404 FLAG_CF = op_result > op_dest;
1405 break;
1406 case 6: // XOR
1407 if (i_w) {
1408 op_dest = RMEM16(op_to_addr);
1409 op_source = RMEM16(op_from_addr);
1410 op_result = op_dest ^ op_source;
1411 WMEM16(op_to_addr, op_result);
1412 } else {
1413 op_dest = RMEM8(op_to_addr);
1414 op_source = RMEM8(op_from_addr);
1415 op_result = op_dest ^ op_source;
1416 WMEM8(op_to_addr, op_result);
1417 }
1418 break;
1419 case 7: // CMP
1420 if (i_w) {
1421 op_dest = RMEM16(op_to_addr);
1422 op_source = RMEM16(op_from_addr);
1423 } else {
1424 op_dest = RMEM8(op_to_addr);
1425 op_source = RMEM8(op_from_addr);
1426 }
1427 op_result = op_dest - op_source;
1428 FLAG_CF = op_result > op_dest;
1429 break;
1430 case 8: // MOV
1431 if (i_w) {
1432 WMEM16(op_to_addr, RMEM16(op_from_addr));
1433 } else {
1434 WMEM8(op_to_addr, RMEM8(op_from_addr));
1435 }
1436 break;
1437 };
1438 break;
1439 case 10: // MOV sreg, r/m | POP r/m | LEA reg, r/m
1440 if (!i_w) { // i_w == 0
1441 // MOV
1442 i_w = 1;
1443 i_reg += 8;
1444 int32_t scratch2_uint = 4 * !i_mod;
1445 rm_addr = i_mod < 3 ?
1446 16 * regs16[seg_override_en ?
1447 seg_override
1448 : instr_table_lookup[scratch2_uint + 3][i_rm]] + (uint16_t)(regs16[instr_table_lookup[scratch2_uint + 1][i_rm]] + instr_table_lookup[scratch2_uint + 2][i_rm] * i_data1 + regs16[instr_table_lookup[scratch2_uint][i_rm]])
1449 : (regs_offset + (2 * i_rm));
1450 if (i_d) {
1451 regs16[i_reg] = RMEM16(rm_addr);
1452 } else {
1453 WMEM16(rm_addr, regs16[i_reg]);
1454 }
1455 } else if (!i_d) { // i_w == 1 && i_d == 0
1456 // LEA
1457 int idx = 4 * !i_mod;
1458 regs16[i_reg] = regs16[instr_table_lookup[idx + 1][i_rm]] + instr_table_lookup[idx + 2][i_rm] * i_data1 + regs16[instr_table_lookup[idx][i_rm]];
1459 } else { // i_w == 1 && i_d == 1
1460 // POP
1461 regs16[REG_SP] += 2;
1462 WMEM16(rm_addr, MEM16(16 * regs16[REG_SS] + (uint16_t)(-2 + regs16[REG_SP])));
1463 }
1464 break;
1465 case 11: // MOV AL/AX, [loc]
1466 rm_addr = 16 * regs16[seg_override_en ? seg_override : REG_DS] + i_data0;
1467 if (i_d) {
1468 if (i_w) {
1469 WMEM16(rm_addr, regs16[REG_AX]);
1470 } else {
1471 WMEM8(rm_addr, regs8[REG_AL]);
1472 }
1473 } else {
1474 if (i_w) {
1475 regs16[REG_AX] = RMEM16(rm_addr);
1476 } else {
1477 regs8[REG_AL] = RMEM8(rm_addr);
1478 }
1479 }
1480 reg_ip += 3;
1481 return; // no calc IP, no flags
1482 case 12: // ROL|ROR|RCL|RCR|SHL|SHR|???|SAR reg/MEM, 1/CL/imm (80186)
1483 {
1484 uint16_t scratch2_uint = (1 & (i_w ? (int16_t)RMEM16(rm_addr) : RMEM8(rm_addr)) >> (8 * (i_w + 1) - 1));
1485 uint16_t scratch_uint = extra ? // xxx reg/MEM, imm
1486 (int8_t) i_data1 : // xxx reg/MEM, CL
1487 i_d ?
1488 31 & regs8[REG_CL] : // xxx reg/MEM, 1
1489 1;
1490 if (scratch_uint) {
1491 if (i_reg < 4) {
1492 // Rotate operations
1493 scratch_uint %= i_reg / 2 + 8 * (i_w + 1);
1494 scratch2_uint = i_w ? RMEM16(rm_addr) : RMEM8(rm_addr);
1495 }
1496 if (i_reg & 1) {
1497 // Rotate/shift right operations
1498 if (i_w) {
1499 op_dest = RMEM16(rm_addr);
1500 op_result = WMEM16(rm_addr, (uint16_t)op_dest >> scratch_uint);
1501 } else {
1502 op_dest = RMEM8(rm_addr);
1503 op_result = WMEM8(rm_addr, (uint8_t)op_dest >> (uint8_t)scratch_uint);
1504 }
1505 } else {
1506 // Rotate/shift left operations
1507 if (i_w) {
1508 op_dest = RMEM16(rm_addr);
1509 op_result = WMEM16(rm_addr, (uint16_t)op_dest << scratch_uint);
1510 } else {
1511 op_dest = RMEM8(rm_addr);
1512 op_result = WMEM8(rm_addr, (uint8_t)op_dest << (uint8_t)scratch_uint);
1513 }
1514 }
1515 if (i_reg > 3) // Shift operations
1516 set_flags_type = 1; // Shift instructions affect SZP
1517 if (i_reg > 4) // SHR or SAR
1518 FLAG_CF = op_dest >> (scratch_uint - 1) & 1;
1519 }
1520
1521 switch (i_reg) {
1522 case 0: // ROL
1523 if (i_w) {
1524 op_dest = RMEM16(rm_addr);
1525 op_result = WMEM16(rm_addr, (uint16_t)op_dest + (op_source = scratch2_uint >> (16 - scratch_uint)));
1526 } else {
1527 op_dest = RMEM8(rm_addr);
1528 op_result = WMEM8(rm_addr, (uint8_t)op_dest + (op_source = (uint8_t)scratch2_uint >> (8 - scratch_uint)));
1529 }
1530 if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1531 FLAG_OF = (1 & op_result >> (8 * (i_w + 1) - 1)) ^ (FLAG_CF = op_result & 1);
1532 break;
1533 case 1: // ROR
1534 scratch2_uint &= (1 << scratch_uint) - 1;
1535 if (i_w) {
1536 op_dest = RMEM16(rm_addr);
1537 op_result = WMEM16(rm_addr, (uint16_t)op_dest + (op_source = scratch2_uint << (16 - scratch_uint)));
1538 } else {
1539 op_dest = RMEM8(rm_addr);
1540 op_result = WMEM8(rm_addr, (uint8_t)op_dest + (op_source = (uint8_t)scratch2_uint << (8 - scratch_uint)));
1541 }
1542 if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1543 FLAG_OF = (1 & (i_w ? (int16_t)op_result * 2 : op_result * 2) >> (8 * (i_w + 1) - 1)) ^ (FLAG_CF = 1 & (i_w ? (int16_t)op_result : op_result) >> (8 * (i_w + 1) - 1));
1544 ;
1545 break;
1546 case 2: // RCL
1547 if (i_w) {
1548 op_dest = RMEM16(rm_addr);
1549 op_result = WMEM16(rm_addr, (uint16_t)op_dest + (FLAG_CF << (scratch_uint - 1)) + (op_source = scratch2_uint >> (17 - scratch_uint)));
1550 } else {
1551 op_dest = RMEM8(rm_addr);
1552 op_result = WMEM8(rm_addr, (uint8_t)op_dest + (FLAG_CF << (scratch_uint - 1)) + (op_source = (uint8_t)scratch2_uint >> (9 - scratch_uint)));
1553 }
1554 if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1555 FLAG_OF = (1 & op_result >> (8 * (i_w + 1) - 1)) ^ (FLAG_CF = (bool)(scratch2_uint & 1 << (8 * (i_w + 1) - scratch_uint)));
1556 break;
1557 case 3: // RCR
1558 if (i_w) {
1559 op_dest = RMEM16(rm_addr);
1560 op_result = WMEM16(rm_addr, (uint16_t)op_dest + (FLAG_CF << (16 - scratch_uint)) + (op_source = scratch2_uint << (17 - scratch_uint)));
1561 } else {
1562 op_dest = RMEM8(rm_addr);
1563 op_result = WMEM8(rm_addr, (uint8_t)op_dest + (FLAG_CF << (8 - scratch_uint)) + (op_source = (uint8_t)scratch2_uint << (9 - scratch_uint)));
1564 }
1565 if (scratch_uint) { // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1566 FLAG_CF = (bool)(scratch2_uint & 1 << (scratch_uint - 1));
1567 FLAG_OF = (1 & op_result >> (8 * (i_w + 1) - 1)) ^ (1 & (i_w ? (int16_t)op_result * 2 : op_result * 2) >> (8 * (i_w + 1) - 1));
1568 }
1569 break;
1570 case 4: // SHL
1571 if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1572 FLAG_OF = (1 & op_result >> (8 * (i_w + 1) - 1)) ^ (FLAG_CF = (1 & (op_dest << (scratch_uint - 1)) >> (8 * (i_w + 1) - 1)));
1573 break;
1574 case 5: // SHR
1575 if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1576 FLAG_OF = 1 & op_dest >> (8 * (i_w + 1) - 1);
1577 break;
1578 case 7: // SAR
1579 scratch_uint < 8 * (i_w + 1) || (FLAG_CF = (bool)scratch2_uint);
1580 FLAG_OF = 0;
1581 if (i_w) {
1582 op_dest = RMEM16(rm_addr);
1583 uint16_t u16 = (uint16_t)scratch2_uint * ~(((1 << 16) - 1) >> scratch_uint);
1584 op_result = WMEM16(rm_addr, op_dest + (op_source = u16));
1585 } else {
1586 op_dest = RMEM8(rm_addr);
1587 uint8_t u8 = (uint8_t)scratch2_uint * ~(((1 << 8) - 1) >> scratch_uint);
1588 op_result = WMEM8(rm_addr, op_dest + (op_source = u8));
1589 }
1590 break;
1591 };
1592 break;
1593 }
1594 case 13: // LOOPxx
1595 // i_reg4bit: 0=LOOPNZ, 1=LOOPZ, 2=LOOP
1596 if (--regs16[REG_CX])
1597 reg_ip += ((FLAG_ZF ^ !i_reg4bit) | (bool)(i_reg4bit & 2)) * (int8_t) i_data0;
1598 break;
1599 case 14: // JMP | CALL int16_t/near
1600 reg_ip += 3 - i_d;
1601 if (!i_w) {
1602 if (i_d) {
1603 // JMP far
1604 reg_ip = 0;
1605 regs16[REG_CS] = i_data2;
1606 } else {
1607 // CALL
1608 i_w = 1;
1609 regs16[REG_SP] -= 2;
1610 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = reg_ip;
1611 }
1612 }
1613 reg_ip += i_d && i_w ? (int8_t) i_data0 : i_data0;
1614 return; // no calc IP, no flags
1615 case 15: // TEST reg, r/m
1616 if (i_w) {
1617 op_result = RMEM16(op_from_addr) & RMEM16(op_to_addr);
1618 } else {
1619 op_result = RMEM8(op_from_addr) & RMEM8(op_to_addr);
1620 }
1621 break;
1622 case 16: // XCHG AX, regs16
1623 if (i_reg4bit != REG_AX) {
1624 uint16_t t = regs16[REG_AX];
1625 regs16[REG_AX] = regs16[i_reg4bit];
1626 regs16[i_reg4bit] = t;
1627 }
1628 ++reg_ip;
1629 return; // no calc ip, no flags
1630 case 24: // NOP|XCHG reg, r/m
1631 if (op_to_addr != op_from_addr) {
1632 if (i_w) {
1633 uint16_t t = RMEM16(op_to_addr);
1634 WMEM16(op_to_addr, RMEM16(op_from_addr));
1635 WMEM16(op_from_addr, t);
1636 } else {
1637 uint16_t t = RMEM8(op_to_addr);
1638 WMEM8(op_to_addr, RMEM8(op_from_addr));
1639 WMEM8(op_from_addr, t);
1640 }
1641 }
1642 break;
1643 case 17: // MOVSx (extra=0)|STOSx (extra=1)|LODSx (extra=2)
1644 {
1645 int32_t seg = seg_override_en ? seg_override : REG_DS;
1646 if (i_w) {
1647 const int dec = (2 * FLAG_DF - 1) * 2;
1648 for (int32_t i = rep_override_en ? regs16[REG_CX] : 1; i; --i) {
1649 uint16_t src = extra & 1 ? regs16[REG_AX] : RMEM16(16 * regs16[seg] + regs16[REG_SI]);
1650 if (extra < 2) {
1651 WMEM16(16 * regs16[REG_ES] + regs16[REG_DI], src);
1652 PSRAM_WORKAROUND2;
1653 } else
1654 regs16[REG_AX] = src;
1655 extra & 1 || (regs16[REG_SI] -= dec);
1656 extra & 2 || (regs16[REG_DI] -= dec);
1657
1658 }
1659 } else {
1660 const int dec = (2 * FLAG_DF - 1);
1661 for (int32_t i = rep_override_en ? regs16[REG_CX] : 1; i; --i) {
1662 uint8_t src = extra & 1 ? regs8[REG_AL] : RMEM8(16 * regs16[seg] + regs16[REG_SI]);
1663 if (extra < 2) {
1664 WMEM8(16 * regs16[REG_ES] + regs16[REG_DI], src);
1665 PSRAM_WORKAROUND2;
1666 } else
1667 regs8[REG_AL] = src;
1668 extra & 1 || (regs16[REG_SI] -= dec);
1669 extra & 2 || (regs16[REG_DI] -= dec);
1670 }
1671 }
1672 if (rep_override_en)
1673 regs16[REG_CX] = 0;
1674 ++reg_ip;
1675 return; // no calc ip, no flags
1676 }
1677 case 18: // CMPSx (extra=0)|SCASx (extra=1)
1678 {
1679 int count = rep_override_en ? regs16[REG_CX] : 1;
1680 if (count) {
1681 int incval = (2 * FLAG_DF - 1) * (i_w + 1);
1682 if (extra) {
1683 // SCASx
1684 op_dest = i_w ? regs16[REG_AX] : regs8[REG_AL];
1685 for (; count; rep_override_en || count--) {
1686 if (i_w) {
1687 op_result = op_dest - (op_source = RMEM16(16 * regs16[REG_ES] + regs16[REG_DI]));
1688 } else {
1689 op_result = op_dest - (op_source = RMEM8(16 * regs16[REG_ES] + regs16[REG_DI]));
1690 }
1691 regs16[REG_DI] -= incval;
1692 rep_override_en && !(--regs16[REG_CX] && ((!op_result) == rep_mode)) && (count = 0);
1693 }
1694 } else {
1695 // CMPSx
1696 int scratch2_uint = seg_override_en ? seg_override : REG_DS;
1697 for (; count; rep_override_en || count--) {
1698 if (i_w) {
1699 op_dest = RMEM16(16 * regs16[scratch2_uint] + regs16[REG_SI]);
1700 op_result = op_dest - (op_source = RMEM16(16 * regs16[REG_ES] + regs16[REG_DI]));
1701 } else {
1702 op_dest = RMEM8(16 * regs16[scratch2_uint] + regs16[REG_SI]);
1703 op_result = op_dest - (op_source = RMEM8(16 * regs16[REG_ES] + regs16[REG_DI]));
1704 }
1705 regs16[REG_SI] -= incval;
1706 regs16[REG_DI] -= incval;
1707 rep_override_en && !(--regs16[REG_CX] && ((!op_result) == rep_mode)) && (count = 0);
1708 }
1709 }
1710 set_flags_type = 3; // set SZP/AO flags
1711 FLAG_CF = op_result > op_dest;
1712 };
1713 ++reg_ip;
1714 calcIP = false;
1715 break;
1716 }
1717 case 19: // RET / RETF imm16
1718 reg_ip = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1719 regs16[REG_SP] += 2;
1720 if (extra) {
1721 // RETF
1722 regs16[REG_CS] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1723 regs16[REG_SP] += 2;
1724 }
1725 regs16[REG_SP] += i_data0;
1726 return; // no calc ip, no flags
1727 case 20: // MOV r/m, immed
1728 if (i_w) {
1729 WMEM16(op_from_addr, i_data2);
1730 } else {
1731 WMEM8(op_from_addr, i_data2);
1732 }
1733 break;
1734 case 21: // IN AL/AX, DX/imm8
1735 {
1736 int32_t port = extra ? regs16[REG_DX] : (uint8_t) i_data0;
1737 regs8[REG_AL] = s_readPort(s_context, port);
1738 if (i_w)
1739 regs8[REG_AH] = s_readPort(s_context, port + 1);
1740 break;
1741 }
1742 case 22: // OUT DX/imm8, AL/AX
1743 {
1744 int32_t port = extra ? regs16[REG_DX] : (uint8_t) i_data0;
1745 s_writePort(s_context, port, regs8[REG_AL]);
1746 if (i_w)
1747 s_writePort(s_context, port + 1, regs8[REG_AH]);
1748 break;
1749 }
1750 case 28: // DAA/DAS
1751 op_result = DAA_DAS();
1752 break;
1753 case 29: // AAA/AAS
1754 op_result = AAA_AAS();
1755 break;
1756 case 30: // CBW
1757 regs8[REG_AH] = -(1 & (i_w ? * (int16_t *) & regs8[REG_AL] : regs8[REG_AL]) >> (8 * (i_w + 1) - 1));
1758 break;
1759 case 31: // CWD
1760 regs16[REG_DX] = -(1 & (i_w ? * (int16_t *) & regs16[REG_AX] : regs16[REG_AX]) >> (8 * (i_w + 1) - 1));
1761 break;
1762 case 32: // CALL FAR imm16:imm16
1763 {
1764 regs16[REG_SP] -= 4;
1765 uint16_t * stack = &MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1766 stack[1] = regs16[REG_CS];
1767 stack[0] = reg_ip + 5;
1768 regs16[REG_CS] = i_data2;
1769 reg_ip = i_data0;
1770 return; // no calc ip, no flags
1771 }
1772 case 33: // PUSHF
1773 regs16[REG_SP] -= 2;
1774 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = make_flags();
1775 ++reg_ip;
1776 return; // no calc ip, no flags
1777 case 34: // POPF
1778 regs16[REG_SP] += 2;
1779 set_flags(MEM16(16 * regs16[REG_SS] + (uint16_t)(-2 + regs16[REG_SP])));
1780 ++reg_ip;
1781 return; // no calc ip, no flags
1782 case 35: // SAHF
1783 set_flags((make_flags() & 0xFF00) + regs8[REG_AH]);
1784 break;
1785 case 36: // LAHF
1786 regs8[REG_AH] = make_flags();
1787 break;
1788 case 37: // LES|LDS reg, r/m
1789 i_w = i_d = 1;
1790 regs16[i_reg] = RMEM16(rm_addr);
1791 regs16[extra / 2] = RMEM16(rm_addr + 2);
1792 break;
1793 case 38: // INT 3
1794 ++reg_ip;
1795 pc_interrupt(3);
1796 return; // no calc ip, no flags
1797 case 40: // INTO
1798 ++reg_ip;
1799 if (FLAG_OF)
1800 pc_interrupt(4);
1801 return; // no calc ip, no flags
1802 case 41: // AAM;
1803 if (i_data0 &= 0xFF) {
1804 regs8[REG_AH] = regs8[REG_AL] / i_data0;
1805 op_result = regs8[REG_AL] %= i_data0;
1806 } else {
1807 // Divide by zero
1808 raiseDivideByZeroInterrupt();
1809 return; // no calc ip, no flags
1810 }
1811 break;
1812 case 42: // AAD
1813 i_w = 0;
1814 regs16[REG_AX] = op_result = 0xFF & (regs8[REG_AL] + i_data0 * regs8[REG_AH]);
1815 break;
1816 case 43: // SALC
1817 regs8[REG_AL] = -FLAG_CF;
1818 break;
1819 case 44: // XLAT
1820 regs8[REG_AL] = RMEM8(16 * regs16[seg_override_en ? seg_override : REG_DS] + (uint16_t)(regs8[REG_AL] + regs16[REG_BX]));
1821 ++reg_ip;
1822 return; // no calc ip, no flags
1823 case 45: // CMC
1824 FLAG_CF ^= 1;
1825 ++reg_ip;
1826 return; // no calc ip, no flags
1827 case 47: // TEST AL/AX, immed
1828 if (i_w) {
1829 op_result = regs16[REG_AX] & i_data0;
1830 } else {
1831 op_result = regs8[REG_AL] & (uint8_t)i_data0;
1832 }
1833 break;
1834 case 48: // LOCK:
1835 break;
1836 case 49: // HLT
1837 //printf("CPU HALT, IP = %04X:%04X, AX = %04X, BX = %04X, CX = %04X, DX = %04X\n", regs16[REG_CS], reg_ip, regs16[REG_AX], regs16[REG_BX], regs16[REG_CX], regs16[REG_DX]);
1838 s_halted = true;
1839 return; // no calc ip, no flags
1840 case 51: // 80186, NEC V20: ENTER
1841 {
1842 //printf("80186, NEC V20: ENTER\n");
1843 regs16[REG_SP] -= 2;
1844 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_BP];
1845 uint16_t framePtr = regs16[REG_SP];
1846 int16_t level = i_data2 & 31;
1847 if (level > 0) {
1848 while (--level) {
1849 regs16[REG_BP] -= 2;
1850 regs16[REG_SP] -= 2;
1851 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = MEM16(16 * regs16[REG_SS] + regs16[REG_BP]);
1852 }
1853 regs16[REG_SP] -= 2;
1854 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = framePtr;
1855 }
1856 regs16[REG_BP] = framePtr;
1857 regs16[REG_SP] -= i_data0;
1858 break;
1859 }
1860 case 52: // 80186, NEC V20: LEAVE
1861 //printf("80186, NEC V20: LEAVE\n");
1862 regs16[REG_SP] = regs16[REG_BP];
1863 regs16[REG_BP] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1864 regs16[REG_SP] += 2;
1865 break;
1866 case 53: // 80186, NEC V20: PUSHA
1867 {
1868 //printf("80186, NEC V20: PUSHA\n");
1869 uint16_t temp = regs16[REG_SP];
1870 regs16[REG_SP] -= 2;
1871 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_AX];
1872 regs16[REG_SP] -= 2;
1873 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_CX];
1874 regs16[REG_SP] -= 2;
1875 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_DX];
1876 regs16[REG_SP] -= 2;
1877 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_BX];
1878 regs16[REG_SP] -= 2;
1879 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = temp;
1880 regs16[REG_SP] -= 2;
1881 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_BP];
1882 regs16[REG_SP] -= 2;
1883 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_SI];
1884 regs16[REG_SP] -= 2;
1885 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_DI];
1886 break;
1887 }
1888 case 54: // 80186, NEC V20: POPA
1889 {
1890 //printf("80186, NEC V20: POPA\n");
1891 regs16[REG_DI] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1892 regs16[REG_SP] += 2;
1893 regs16[REG_SI] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1894 regs16[REG_SP] += 2;
1895 regs16[REG_BP] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1896 regs16[REG_SP] += 2;
1897 regs16[REG_SP] += 2; // SP ignored
1898 regs16[REG_BX] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1899 regs16[REG_SP] += 2;
1900 regs16[REG_DX] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1901 regs16[REG_SP] += 2;
1902 regs16[REG_CX] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1903 regs16[REG_SP] += 2;
1904 regs16[REG_AX] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1905 regs16[REG_SP] += 2;
1906 break;
1907 }
1908 case 55: // 80186: BOUND
1909 printf("80186: BOUND - not implemented!\n");
1910 break;
1911 case 56: // 80186, NEC V20: PUSH imm16
1912 //printf("80186, NEC V20: PUSH imm16\n");
1913 regs16[REG_SP] -= 2;
1914 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = i_data0;
1915 break;
1916 case 57: // 80186, NEC V20: PUSH imm8
1917 //printf("80186, NEC V20: PUSH imm8\n");
1918 regs16[REG_SP] -= 2;
1919 MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = (i_data0 & 0xff) | (i_data0 & 0x80 ? 0xff00 : 0); // 8->16 bit with sign extension
1920 break;
1921 case 58: // 80186 IMUL
1922 printf("80186 IMUL - not implemented!\n");
1923 break;
1924 case 59: // 80186: INSB INSW
1925 printf("80186: INSB INSW - not implemented!\n");
1926 break;
1927 case 60: // 80186: OUTSB OUTSW
1928 printf("80186: OUTSB OUTSW - not implemented!\n");
1929 break;
1930 case 69: // 8087 MATH Coprocessor
1931 printf("8087 MATH Coprocessor %02X %02X %02X %02X - not implemented!\n", opcode_stream[0], opcode_stream[1], opcode_stream[2], opcode_stream[3]);
1932 break;
1933 /*
1934 case 70: // 80286+
1935 printf("80286+\n");
1936 break;
1937 case 71: // 80386+
1938 printf("80386+\n");
1939 break;
1940 case 72: // BAD OP CODE
1941 printf("Bad 8086 opcode %02X %02X\n", opcode_stream[0], opcode_stream[1]);
1942 break;
1943 */
1944 default:
1945 printf("Unsupported 8086 opcode %02X %02X\n", opcode_stream[0], opcode_stream[1]);
1946 break;
1947 }
1948
1949 // Increment instruction pointer by computed instruction length.
1950 if (calcIP)
1951 reg_ip += (i_mod * (i_mod != 3) + 2 * (!i_mod && i_rm == 6)) * i_mod_size + base_size[raw_opcode_id] + i_w_adder[raw_opcode_id] * (i_w + 1);
1952
1953 // If instruction needs to update SF, ZF and PF, set them as appropriate
1954 if (set_flags_type & 1) {
1955 FLAG_SF = (1 & op_result >> (8 * (i_w + 1) - 1));
1956 FLAG_ZF = !op_result;
1957 FLAG_PF = parity[(uint8_t) op_result];
1958
1959 // If instruction is an arithmetic or logic operation, also set AF/OF/CF as appropriate.
1960 if (set_flags_type & 2)
1961 set_AF_OF_arith(op_result);
1962 else if (set_flags_type & 4)
1963 FLAG_CF = FLAG_OF = 0;
1964 }
1965
1966}
1967
1968
1969} // namespace fabgl