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 
32 namespace 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
106 static uint8_t regs[48];
107 static uint8_t flags[10];
108 static int32_t regs_offset;
109 static 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, trap_flag;
110 static uint16_t * regs16, reg_ip, seg_override;
111 static uint32_t op_source, op_dest, set_flags_type;
112 static int32_t op_to_addr, op_from_addr;
113 
114 
115 void * i8086::s_context;
116 i8086::ReadPort i8086::s_readPort;
117 i8086::WritePort i8086::s_writePort;
118 i8086::WriteVideoMemory8 i8086::s_writeVideoMemory8;
119 i8086::WriteVideoMemory16 i8086::s_writeVideoMemory16;
120 i8086::ReadVideoMemory8 i8086::s_readVideoMemory8;
121 i8086::ReadVideoMemory16 i8086::s_readVideoMemory16;
122 i8086::Interrupt i8086::s_interrupt;
123 
124 uint8_t * i8086::s_memory;
125 bool i8086::s_pendingIRQ;
126 uint8_t i8086::s_pendingIRQIndex;
127 bool i8086::s_halted;
128 
129 
130 
131 
132 // Table 0: R/M mode 1/2 "register 1" lookup
133 static 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
137 static 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
140 static 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
143 static uint8_t rm_mode12_dfseg[] = { 11, 11, 10, 10, 11, 11, 10, 11 };
144 
145 // Table 4: R/M mode 0 "register 1" lookup
146 static uint8_t rm_mode0_reg1[] = { 3, 3, 5, 5, 6, 7, 12, 3 };
147 
148 // Table 6: R/M mode 0 "DISP multiplier" lookup
149 static uint8_t rm_mode0_disp[] = { 0, 0, 0, 0, 0, 0, 1, 0 };
150 
151 // Table 7: R/M mode 0 "default segment" lookup
152 static 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")
155 static 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
173 static 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)
191 static 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)
209 static 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)
227 static 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
245 static 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
263 static 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
281 static 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
284 static 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
287 static 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
290 static uint8_t jxx_dec_d[] = { XX_ADDR, XX_ADDR, XX_ADDR, XX_ADDR,XX_ADDR, XX_ADDR, OF_ADDR, OF_ADDR };
291 
292 
293 static 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 
313 void i8086::setAL(uint8_t value)
314 {
315  regs8[REG_AL] = value;
316 }
317 
318 
319 void i8086::setAH(uint8_t value)
320 {
321  regs8[REG_AH] = value;
322 }
323 
324 
325 uint8_t i8086::AL()
326 {
327  return regs8[REG_AL];
328 }
329 
330 
331 uint8_t i8086::AH()
332 {
333  return regs8[REG_AH];
334 }
335 
336 
337 void i8086::setBL(uint8_t value)
338 {
339  regs8[REG_BL] = value;
340 }
341 
342 
343 void i8086::setBH(uint8_t value)
344 {
345  regs8[REG_BH] = value;
346 }
347 
348 
349 uint8_t i8086::BL()
350 {
351  return regs8[REG_BL];
352 }
353 
354 
355 uint8_t i8086::BH()
356 {
357  return regs8[REG_BH];
358 }
359 
360 
361 void i8086::setCL(uint8_t value)
362 {
363  regs8[REG_CL] = value;
364 }
365 
366 
367 void i8086::setCH(uint8_t value)
368 {
369  regs8[REG_CH] = value;
370 }
371 
372 
373 uint8_t i8086::CL()
374 {
375  return regs8[REG_CL];
376 }
377 
378 
379 uint8_t i8086::CH()
380 {
381  return regs8[REG_CH];
382 }
383 
384 
385 void i8086::setDL(uint8_t value)
386 {
387  regs8[REG_DL] = value;
388 }
389 
390 
391 void i8086::setDH(uint8_t value)
392 {
393  regs8[REG_DH] = value;
394 }
395 
396 
397 uint8_t i8086::DL()
398 {
399  return regs8[REG_DL];
400 }
401 
402 
403 uint8_t i8086::DH()
404 {
405  return regs8[REG_DH];
406 }
407 
408 
409 void i8086::setAX(uint16_t value)
410 {
411  regs16[REG_AX] = value;
412 }
413 
414 
415 void i8086::setBX(uint16_t value)
416 {
417  regs16[REG_BX] = value;
418 }
419 
420 
421 void i8086::setCX(uint16_t value)
422 {
423  regs16[REG_CX] = value;
424 }
425 
426 
427 void i8086::setDX(uint16_t value)
428 {
429  regs16[REG_DX] = value;
430 }
431 
432 
433 void i8086::setDI(uint16_t value)
434 {
435  regs16[REG_DI] = value;
436 }
437 
438 
439 void i8086::setCS(uint16_t value)
440 {
441  regs16[REG_CS] = value;
442 }
443 
444 
445 void i8086::setDS(uint16_t value)
446 {
447  regs16[REG_DS] = value;
448 }
449 
450 
451 void i8086::setSS(uint16_t value)
452 {
453  regs16[REG_SS] = value;
454 }
455 
456 
457 void i8086::setES(uint16_t value)
458 {
459  regs16[REG_ES] = value;
460 }
461 
462 
463 void i8086::setIP(uint16_t value)
464 {
465  reg_ip = value;
466 }
467 
468 
469 uint16_t i8086::IP()
470 {
471  return reg_ip;
472 }
473 
474 
475 void i8086::setSP(uint16_t value)
476 {
477  regs16[REG_SP] = value;
478 }
479 
480 
481 uint16_t i8086::AX()
482 {
483  return regs16[REG_AX];
484 }
485 
486 
487 uint16_t i8086::BX()
488 {
489  return regs16[REG_BX];
490 }
491 
492 
493 uint16_t i8086::CX()
494 {
495  return regs16[REG_CX];
496 }
497 
498 
499 uint16_t i8086::DX()
500 {
501  return regs16[REG_DX];
502 }
503 
504 
505 uint16_t i8086::BP()
506 {
507  return regs16[REG_BP];
508 }
509 
510 
511 uint16_t i8086::SI()
512 {
513  return regs16[REG_SI];
514 }
515 
516 
517 uint16_t i8086::DI()
518 {
519  return regs16[REG_DI];
520 }
521 
522 
523 uint16_t i8086::SP()
524 {
525  return regs16[REG_SP];
526 }
527 
528 
529 uint16_t i8086::CS()
530 {
531  return regs16[REG_CS];
532 }
533 
534 
535 uint16_t i8086::ES()
536 {
537  return regs16[REG_ES];
538 }
539 
540 
541 uint16_t i8086::DS()
542 {
543  return regs16[REG_DS];
544 }
545 
546 
547 uint16_t i8086::SS()
548 {
549  return regs16[REG_SS];
550 }
551 
552 
553 bool i8086::flagIF()
554 {
555  return FLAG_IF;
556 }
557 
558 
559 bool i8086::flagTF()
560 {
561  return FLAG_TF;
562 }
563 
564 
565 bool i8086::flagCF()
566 {
567  return FLAG_CF;
568 }
569 
570 
571 bool i8086::flagZF()
572 {
573  return FLAG_ZF;
574 }
575 
576 bool i8086::flagOF()
577 {
578  return FLAG_OF;
579 }
580 
581 bool i8086::flagDF()
582 {
583  return FLAG_DF;
584 }
585 
586 bool i8086::flagSF()
587 {
588  return FLAG_SF;
589 }
590 
591 bool i8086::flagAF()
592 {
593  return FLAG_AF;
594 }
595 
596 bool i8086::flagPF()
597 {
598  return FLAG_PF;
599 }
600 
601 void i8086::setFlagZF(bool value)
602 {
603  FLAG_ZF = value;
604 }
605 
606 
607 void i8086::setFlagCF(bool value)
608 {
609  FLAG_CF = value;
610 }
611 
612 
613 
614 
615 // ret false if not acked
616 bool 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 
637 inline __attribute__((always_inline)) uint8_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 
647 inline __attribute__((always_inline)) uint16_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 
657 inline __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 
668 inline __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 
683 // Helper functions
684 
685 // Set carry flag
686 static int8_t set_CF(int new_CF)
687 {
688  return FLAG_CF = !!new_CF;
689 }
690 
691 
692 // Set auxiliary flag
693 static int8_t set_AF(int new_AF)
694 {
695  return FLAG_AF = !!new_AF;
696 }
697 
698 
699 // Set overflow flag
700 static int8_t set_OF(int new_OF)
701 {
702  return FLAG_OF = !!new_OF;
703 }
704 
705 
706 // Set auxiliary and overflow flag after arithmetic operations
707 int8_t set_AF_OF_arith(int32_t op_result, uint8_t i_w)
708 {
709  set_AF((op_source ^= op_dest ^ op_result) & 0x10);
710  if (op_result == op_dest)
711  return FLAG_OF = 0;
712  else
713  return set_OF(1 & (FLAG_CF ^ op_source >> (8 * (i_w + 1) - 1)));
714 }
715 
716 
717 // Assemble and return emulated CPU FLAGS register
718 uint16_t i8086::make_flags()
719 {
720  #if I80186MODE
721  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)
722  #else
723  uint16_t r = 0xf002; // for real 8086
724  #endif
725 
726  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;
727 }
728 
729 
730 void i8086::set_flags(int new_flags)
731 {
732  FLAG_CF = (new_flags >> 0) & 1;
733  FLAG_PF = (new_flags >> 2) & 1;
734  FLAG_AF = (new_flags >> 4) & 1;
735  FLAG_ZF = (new_flags >> 6) & 1;
736  FLAG_SF = (new_flags >> 7) & 1;
737  FLAG_TF = (new_flags >> 8) & 1;
738  FLAG_IF = (new_flags >> 9) & 1;
739  FLAG_DF = (new_flags >> 10) & 1;
740  FLAG_OF = (new_flags >> 11) & 1;
741 }
742 
743 
744 // Convert raw opcode to translated opcode index. This condenses a large number of different encodings of similar
745 // instructions into a much smaller number of distinct functions, which we then execute
746 void i8086::set_opcode(uint8_t opcode)
747 {
748  raw_opcode_id = opcode;
749  xlat_opcode_id = xlat_ids[opcode];
750  extra = ex_data[opcode];
751  i_mod_size = i_mod_adder[opcode];
752  set_flags_type = std_flags[opcode];
753 }
754 
755 
756 // Execute INT #interrupt_num on the emulated machine
757 uint8_t i8086::pc_interrupt(uint8_t interrupt_num)
758 {
759  // fab: interrupt can exit from halt state
760  if (s_halted) {
761  s_halted = false;
762  ++reg_ip; // go to next instruction after HLT
763  }
764 
765  if (!s_interrupt(s_context, interrupt_num)) {
766  regs16[REG_SP] -= 2;
767  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = make_flags();
768 
769  regs16[REG_SP] -= 2;
770  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_CS];
771 
772  regs16[REG_SP] -= 2;
773  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = reg_ip;
774 
775  regs16[REG_CS] = MEM16(4 * interrupt_num + 2);
776 
777  reg_ip = MEM16(4 * interrupt_num);
778 
779  FLAG_TF = FLAG_IF = 0;
780  }
781  return 0;
782 }
783 
784 
785 // fab: necessary to go back to the first instruction prefix
786 uint8_t i8086::raiseDivideByZeroInterrupt()
787 {
788  if (seg_override_en || rep_override_en) {
789  // go back looking for segment prefixes or REP prefixes
790  while (true) {
791  uint8_t opcode = MEM8(16 * regs16[REG_CS] + reg_ip - 1);
792  // break if not REP and SEG
793  if ((opcode & 0xfe) != 0xf2 && (opcode & 0xe7) != 0x26)
794  break;
795  --reg_ip;
796  }
797  }
798  return pc_interrupt(0);
799 }
800 
801 
802 // AAA and AAS instructions - which_operation is +1 for AAA, and -1 for AAS
803 int i8086::AAA_AAS(int8_t which_operation)
804 {
805  regs16[REG_AX] += 262 * which_operation * set_AF(set_CF(((regs8[REG_AL] & 0x0F) > 9) || FLAG_AF));
806  return regs8[REG_AL] &= 0x0F;
807 }
808 
809 
810 void i8086::reset()
811 {
812  regs_offset = (int32_t)(regs - s_memory);
813 
814  regs8 = (uint8_t *)(s_memory + regs_offset);
815  regs16 = (uint16_t *)(s_memory + regs_offset);
816 
817  memset(regs8, 0, sizeof(regs));
818  set_flags(0);
819 
820  // Initialise CPU state variables
821  seg_override_en = 0;
822  rep_override_en = 0;
823 
824  s_halted = false;
825 
826  regs16[REG_CS] = 0xffff;
827  reg_ip = 0;
828 }
829 
830 
831 void IRAM_ATTR i8086::step()
832 {
833  do {
834  uint8_t const * opcode_stream = s_memory + 16 * regs16[REG_CS] + reg_ip;
835 
836  #if I8086_SHOW_OPCODE_STATS
837  static uint32_t opcodeStats[256] = {0};
838  static int opcodeStatsCount = 0;
839  static uint64_t opcodeStatsT0 = esp_timer_get_time();
840  opcodeStats[*opcode_stream] += 1;
841  ++opcodeStatsCount;
842  if ((opcodeStatsCount % 1000000) == 0) {
843  opcodeStatsCount = 0;
844  if (Serial.available()) {
845  Serial.read();
846  printf("\ntime delta = %llu uS\n\n", esp_timer_get_time() - opcodeStatsT0);
847  opcodeStatsT0 = esp_timer_get_time();
848  for (int i = 0; i < 256; ++i) {
849  if (opcodeStats[i] > 0)
850  printf("%d, %02X\n", opcodeStats[i], i);
851  opcodeStats[i] = 0;
852  }
853  printf("\n");
854  }
855  }
856  #endif
857 
858  // seg_override_en and rep_override_en contain number of instructions to hold segment override and REP prefix respectively
859  if (seg_override_en)
860  seg_override_en--;
861  if (rep_override_en)
862  rep_override_en--;
863 
864  // quick and dirty processing of the most common instructions (statistically measured)
865  switch (*opcode_stream) {
866 
867  // SEG ES
868  // SEG CS
869  // SEG SS
870  // SEG DS
871  case 0x26:
872  case 0x2e:
873  case 0x36:
874  case 0x3e:
875  seg_override_en = 2;
876  seg_override = ex_data[*opcode_stream];
877  rep_override_en && rep_override_en++;
878  ++reg_ip;
879  break;
880 
881  // JO
882  // JNO
883  // JB/JNAE/JC
884  // JAE/JNB/JNC
885  // JE/JZ
886  // JNE/JNZ
887  // JBE/JNA
888  // JA/JNBE
889  // JS
890  // JNS
891  // JP/JPE
892  // JNP/JPO
893  // JL/JNGE
894  // JGE/JNL
895  // JLE/JNG
896  // JG/JNLE
897  case 0x70 ... 0x7f:
898  {
899  int inv = *opcode_stream & 1; // inv is the invert flag, e.g. i_w == 1 means JNAE, whereas i_w == 0 means JAE
900  int idx = (*opcode_stream >> 1) & 7;
901  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]]));
902  break;
903  }
904 
905  // JMP disp8
906  case 0xeb:
907  reg_ip += 2 + (int8_t)opcode_stream[1];
908  break;
909 
910  // CLC|STC|CLI|STI|CLD|STD
911  case 0xf8 ... 0xfd:
912  {
913  static const int FADDR[3] = { CF_ADDR, IF_ADDR, DF_ADDR };
914  flags[FADDR[(*opcode_stream >> 1) & 3]] = *opcode_stream & 1;
915  ++reg_ip;
916  break;
917  }
918 
919  // JCXZ
920  case 0xe3:
921  reg_ip += 2 + !regs16[REG_CX] * (int8_t)opcode_stream[1];
922  break;
923 
924  // CALL disp16
925  case 0xe8:
926  regs16[REG_SP] -= 2;
927  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = reg_ip + 3;
928  #ifndef TESTING_CPU
929  ASM_MEMW
930  #endif
931  reg_ip += 3 + *(uint16_t*)(opcode_stream + 1);
932  break;
933 
934  // RET (intrasegment)
935  case 0xc3:
936  reg_ip = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
937  regs16[REG_SP] += 2;
938  break;
939 
940  // POP reg
941  case 0x58 ... 0x5f:
942  regs16[REG_SP] += 2; // SP may be read from stack, so we have to increment here
943  regs16[*opcode_stream & 7] = MEM16(16 * regs16[REG_SS] + (uint16_t)(regs16[REG_SP] - 2));
944  ++reg_ip;
945  break;
946 
947  // PUSH reg
948  case 0x50 ... 0x57:
949  regs16[REG_SP] -= 2;
950  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[*opcode_stream & 7];
951  ++reg_ip;
952  break;
953 
954  // MOV reg8, data8
955  case 0xb0 ... 0xb7:
956  regs8[((*opcode_stream >> 2) & 1) + (*opcode_stream & 3) * 2] = *(opcode_stream + 1);
957  reg_ip += 2;
958  break;
959 
960  // MOV reg16, data16
961  case 0xb8 ... 0xbf:
962  regs16[*opcode_stream & 0x7] = *(uint16_t*)(opcode_stream + 1);
963  reg_ip += 3;
964  break;
965 
966  // POP ES
967  // POP CS (actually undefined on 8086)
968  // POP SS
969  // POP DS
970  case 0x07:
971  case 0x0f:
972  case 0x17:
973  case 0x1f:
974  regs16[REG_ES + (*opcode_stream >> 3)] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
975  regs16[REG_SP] += 2;
976  ++reg_ip;
977  break;
978 
979  default:
980  stepEx(opcode_stream);
981  break;
982 
983  }
984 
985  } while (seg_override_en > 1 || rep_override_en > 1);
986 
987  // Application has set trap flag, so fire INT 1
988  if (trap_flag) {
989  pc_interrupt(1);
990  }
991 
992  trap_flag = FLAG_TF;
993 
994  // Check for interrupts triggered by system interfaces
995  if (FLAG_IF && !FLAG_TF && s_pendingIRQ) {
996  pc_interrupt(s_pendingIRQIndex);
997  s_pendingIRQ = false;
998  }
999 
1000 }
1001 
1002 
1003 void i8086::stepEx(uint8_t const * opcode_stream)
1004 {
1005  set_opcode(*opcode_stream);
1006 
1007  // Extract fields from instruction
1008  uint8_t i_reg4bit = raw_opcode_id & 7;
1009  i_w = i_reg4bit & 1;
1010  i_d = i_reg4bit / 2 & 1;
1011 
1012  // Extract instruction data fields
1013  uint16_t i_data0 = * (int16_t *) & opcode_stream[1];
1014  uint16_t i_data1 = * (int16_t *) & opcode_stream[2];
1015  uint16_t i_data2 = * (int16_t *) & opcode_stream[3];
1016 
1017  uint8_t i_mod = 0, i_rm = 0, i_reg = 0;
1018  int32_t op_result = 0;
1019  int32_t rm_addr = 0;
1020 
1021  bool calcIP = true;
1022 
1023  // i_mod_size > 0 indicates that opcode uses i_mod/i_rm/i_reg, so decode them
1024  if (i_mod_size) {
1025  i_mod = (i_data0 & 0xFF) >> 6;
1026  i_rm = i_data0 & 7;
1027  i_reg = i_data0 / 8 & 7;
1028 
1029  if ((!i_mod && i_rm == 6) || (i_mod == 2))
1030  i_data2 = * (int16_t *) & opcode_stream[4];
1031  else if (i_mod != 1)
1032  i_data2 = i_data1;
1033  else // If i_mod is 1, operand is (usually) 8 bits rather than 16 bits
1034  i_data1 = (int8_t) i_data1;
1035 
1036  int idx = 4 * !i_mod;
1037  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));
1038  op_from_addr = regs_offset + (i_w ? 2 * i_reg : (2 * i_reg + i_reg / 4) & 7);
1039  if (i_d) {
1040  auto t = op_from_addr;
1041  op_from_addr = rm_addr;
1042  op_to_addr = t;
1043  }
1044  }
1045 
1046  // Instruction execution unit
1047  switch (xlat_opcode_id) {
1048  case 2: // INC|DEC regs16
1049  {
1050  i_w = 1;
1051  i_d = 0;
1052  i_reg = i_reg4bit;
1053  int idx = 4 * !i_mod;
1054  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);
1055  op_from_addr = regs_offset + 2 * i_reg;
1056  i_reg = extra;
1057  } // not break!
1058  case 5: // INC|DEC|JMP|CALL|PUSH
1059  if (i_reg < 2) {
1060  // INC|DEC
1061  if (i_w) {
1062  op_dest = RMEM16(op_from_addr);
1063  op_result = WMEM16(op_from_addr, (uint16_t)op_dest + 1 - 2 * i_reg);
1064  } else {
1065  op_dest = RMEM8(op_from_addr);
1066  op_result = WMEM8(op_from_addr, (uint16_t)op_dest + 1 - 2 * i_reg);
1067  }
1068  op_source = 1;
1069  set_AF_OF_arith(op_result, i_w);
1070  set_OF(op_dest + 1 - i_reg == 1 << (8 * (i_w + 1) - 1));
1071  if (xlat_opcode_id == 5)
1072  set_opcode(0x10); // Decode like ADC
1073  } else if (i_reg != 6) {
1074  // JMP|CALL
1075  uint16_t jumpTo = i_w ? MEM16(op_from_addr) : MEM8(op_from_addr); // to avoid ASM_MEMW
1076  if (i_reg - 3 == 0) {
1077  // CALL (far)
1078  i_w = 1;
1079  regs16[REG_SP] -= 2;
1080  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_CS];
1081  }
1082  if (i_reg & 2) {
1083  // CALL (near or far)
1084  i_w = 1;
1085  regs16[REG_SP] -= 2;
1086  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = (reg_ip + 2 + i_mod * (i_mod != 3) + 2 * (!i_mod && i_rm == 6));
1087  }
1088  if (i_reg & 1) {
1089  // JMP|CALL (far)
1090  regs16[REG_CS] = MEM16(op_from_addr + 2);
1091  }
1092  reg_ip = jumpTo;
1093  return; // no calc IP, no flags
1094  } else {
1095  // PUSH
1096  i_w = 1;
1097  regs16[REG_SP] -= 2;
1098  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = MEM16(rm_addr);
1099  }
1100  break;
1101  case 6: // TEST r/m, imm16 / NOT|NEG|MUL|IMUL|DIV|IDIV reg
1102  op_to_addr = op_from_addr;
1103 
1104  switch (i_reg) {
1105  case 0: // TEST
1106  set_opcode(0x20); // Decode like AND
1107  reg_ip += i_w + 1;
1108  if (i_w) {
1109  op_dest = RMEM16(op_to_addr);
1110  op_source = (uint16_t)i_data2;
1111  op_result = (uint16_t)(op_dest & op_source);
1112  } else {
1113  op_dest = RMEM8(op_to_addr);
1114  op_source = (uint8_t)i_data2;
1115  op_result = (uint8_t)(op_dest & op_source);
1116  }
1117  break;
1118  case 2: // NOT
1119  if (i_w)
1120  WMEM16(op_to_addr, ~RMEM16(op_from_addr));
1121  else
1122  WMEM8(op_to_addr, ~RMEM8(op_from_addr));
1123  break;
1124  case 3: // NEG
1125  if (i_w)
1126  op_result = WMEM16(op_to_addr, -(op_source = RMEM16(op_from_addr)));
1127  else
1128  op_result = WMEM8(op_to_addr, -(op_source = RMEM8(op_from_addr)));
1129  op_dest = 0;
1130  set_opcode(0x28); // Decode like SUB
1131  FLAG_CF = op_result > op_dest;
1132  break;
1133  case 4: // MUL
1134  if (i_w) {
1135  set_opcode(0x10);
1136  regs16[REG_DX] = (op_result = RMEM16(rm_addr) * regs16[REG_AX]) >> 16;
1137  regs16[REG_AX] = op_result;
1138  set_OF(set_CF(op_result - (uint16_t)op_result));
1139  } else {
1140  set_opcode(0x10);
1141  regs16[REG_AX] = op_result = RMEM8(rm_addr) * regs8[REG_AL];
1142  set_OF(set_CF(op_result - (uint8_t) op_result));
1143  }
1144  break;
1145  case 5: // IMUL
1146  {
1147  if (i_w) {
1148  set_opcode(0x10);
1149  regs16[REG_DX] = (op_result = (int16_t)RMEM16(rm_addr) * (int16_t)regs16[REG_AX]) >> 16;
1150  regs16[REG_AX] = op_result;
1151  set_OF(set_CF(op_result - (int16_t)op_result));
1152  } else {
1153  set_opcode(0x10);
1154  regs16[REG_AX] = op_result = (int8_t)RMEM8(rm_addr) * (int8_t)regs8[REG_AL];
1155  set_OF(set_CF(op_result - (int8_t) op_result));
1156  }
1157  break;
1158  }
1159  case 6: // DIV
1160  {
1161  int32_t scratch_int;
1162  int32_t scratch_uint, scratch2_uint;
1163  if (i_w) {
1164  (scratch_int = RMEM16(rm_addr))
1165  &&
1166  !(scratch2_uint = (uint32_t)(scratch_uint = (regs16[REG_DX] << 16) + regs16[REG_AX]) / scratch_int, scratch2_uint - (uint16_t) scratch2_uint)
1167  ?
1168  regs16[REG_DX] = scratch_uint - scratch_int * (regs16[REG_AX] = scratch2_uint)
1169  :
1170  (raiseDivideByZeroInterrupt(), calcIP = false);
1171  } else {
1172  (scratch_int = RMEM8(rm_addr))
1173  &&
1174  !(scratch2_uint = (uint16_t)(scratch_uint = regs16[REG_AX]) / scratch_int, scratch2_uint - (uint8_t) scratch2_uint)
1175  ?
1176  regs8[REG_AH] = scratch_uint - scratch_int * (regs8[REG_AL] = scratch2_uint)
1177  :
1178  (raiseDivideByZeroInterrupt(), calcIP = false);
1179  }
1180  break;
1181  }
1182  case 7: // IDIV
1183  {
1184  int32_t scratch_int;
1185  int32_t scratch2_uint, scratch_uint;
1186  if (i_w) {
1187  (scratch_int = (int16_t)RMEM16(rm_addr))
1188  &&
1189  !(scratch2_uint = (int)(scratch_uint = (regs16[REG_DX] << 16) + regs16[REG_AX]) / scratch_int, scratch2_uint - (int16_t) scratch2_uint)
1190  ?
1191  regs16[REG_DX] = scratch_uint - scratch_int * (regs16[REG_AX] = scratch2_uint)
1192  :
1193  (raiseDivideByZeroInterrupt(), calcIP = false);
1194  } else {
1195  (scratch_int = (int8_t)RMEM8(rm_addr))
1196  &&
1197  !(scratch2_uint = (int16_t)(scratch_uint = regs16[REG_AX]) / scratch_int, scratch2_uint - (int8_t) scratch2_uint)
1198  ?
1199  regs8[REG_AH] = scratch_uint - scratch_int * (regs8[REG_AL] = scratch2_uint)
1200  :
1201  (raiseDivideByZeroInterrupt(), calcIP = false);
1202  }
1203  break;
1204  }
1205  };
1206  break;
1207  case 7: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP AL/AX, immed
1208  rm_addr = regs_offset;
1209  i_data2 = i_data0;
1210  i_mod = 3;
1211  i_reg = extra;
1212  reg_ip--;
1213  // not break!
1214  case 8: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP reg, immed
1215  op_to_addr = rm_addr;
1216  regs16[REG_SCRATCH] = (i_d |= !i_w) ? (int8_t) i_data2 : i_data2;
1217  op_from_addr = regs_offset + 2 * REG_SCRATCH;
1218  reg_ip += !i_d + 1;
1219  set_opcode(0x08 * (extra = i_reg));
1220  // not break!
1221  case 9: // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP|MOV reg, r/m
1222  switch (extra) {
1223  case 0: // ADD
1224  {
1225  if (i_w) {
1226  op_dest = RMEM16(op_to_addr);
1227  op_source = RMEM16(op_from_addr);
1228  op_result = (uint16_t)(op_dest + op_source);
1229  WMEM16(op_to_addr, op_result);
1230  } else {
1231  op_dest = RMEM8(op_to_addr);
1232  op_source = RMEM8(op_from_addr);
1233  op_result = (uint8_t)(op_dest + op_source);
1234  WMEM8(op_to_addr, op_result);
1235  }
1236  FLAG_CF = op_result < op_dest;
1237  break;
1238  }
1239  case 1: // OR
1240  {
1241  if (i_w) {
1242  op_dest = RMEM16(op_to_addr);
1243  op_source = RMEM16(op_from_addr);
1244  op_result = op_dest | op_source;
1245  WMEM16(op_to_addr, op_result);
1246  } else {
1247  op_dest = RMEM8(op_to_addr);
1248  op_source = RMEM8(op_from_addr);
1249  op_result = op_dest | op_source;
1250  WMEM8(op_to_addr, op_result);
1251  }
1252  break;
1253  }
1254  case 2: // ADC
1255  if (i_w) {
1256  op_dest = RMEM16(op_to_addr);
1257  op_source = RMEM16(op_from_addr);
1258  op_result = WMEM16(op_to_addr, op_dest + FLAG_CF + op_source);
1259  } else {
1260  op_dest = RMEM8(op_to_addr);
1261  op_source = RMEM8(op_from_addr);
1262  op_result = WMEM8(op_to_addr, op_dest + FLAG_CF + op_source);
1263  }
1264  set_CF((FLAG_CF && (op_result == op_dest)) || (+op_result < +(int) op_dest));
1265  set_AF_OF_arith(op_result, i_w);
1266  break;
1267  case 3: // SBB
1268  if (i_w) {
1269  op_dest = RMEM16(op_to_addr);
1270  op_source = RMEM16(op_from_addr);
1271  op_result = WMEM16(op_to_addr, op_dest - (FLAG_CF + op_source));
1272  } else {
1273  op_dest = RMEM8(op_to_addr);
1274  op_source = RMEM8(op_from_addr);
1275  op_result = WMEM8(op_to_addr, op_dest - (FLAG_CF + op_source));
1276  }
1277  set_CF((FLAG_CF && (op_result == op_dest)) || (-op_result < -(int) op_dest));
1278  set_AF_OF_arith(op_result, i_w);
1279  break;
1280  case 4: // AND
1281  {
1282  if (i_w) {
1283  op_dest = RMEM16(op_to_addr);
1284  op_source = RMEM16(op_from_addr);
1285  op_result = op_dest & op_source;
1286  WMEM16(op_to_addr, op_result);
1287  } else {
1288  op_dest = RMEM8(op_to_addr);
1289  op_source = RMEM8(op_from_addr);
1290  op_result = op_dest & op_source;
1291  WMEM8(op_to_addr, op_result);
1292  }
1293  break;
1294  }
1295  case 5: // SUB
1296  if (i_w) {
1297  op_dest = RMEM16(op_to_addr);
1298  op_source = RMEM16(op_from_addr);
1299  op_result = WMEM16(op_to_addr, op_dest - op_source);
1300  } else {
1301  op_dest = RMEM8(op_to_addr);
1302  op_source = RMEM8(op_from_addr);
1303  op_result = WMEM8(op_to_addr, op_dest - op_source);
1304  }
1305  FLAG_CF = op_result > op_dest;
1306  break;
1307  case 6: // XOR
1308  {
1309  if (i_w) {
1310  op_dest = RMEM16(op_to_addr);
1311  op_source = RMEM16(op_from_addr);
1312  op_result = op_dest ^ op_source;
1313  WMEM16(op_to_addr, op_result);
1314  } else {
1315  op_dest = RMEM8(op_to_addr);
1316  op_source = RMEM8(op_from_addr);
1317  op_result = op_dest ^ op_source;
1318  WMEM8(op_to_addr, op_result);
1319  }
1320  break;
1321  }
1322  case 7: // CMP
1323  if (i_w) {
1324  op_dest = RMEM16(op_to_addr);
1325  op_source = RMEM16(op_from_addr);
1326  } else {
1327  op_dest = RMEM8(op_to_addr);
1328  op_source = RMEM8(op_from_addr);
1329  }
1330  op_result = op_dest - op_source;
1331  FLAG_CF = op_result > op_dest;
1332  break;
1333  case 8: // MOV
1334  if (i_w) {
1335  WMEM16(op_to_addr, RMEM16(op_from_addr));
1336  } else {
1337  WMEM8(op_to_addr, RMEM8(op_from_addr));
1338  }
1339  break;
1340  };
1341  break;
1342  case 10: // MOV sreg, r/m | POP r/m | LEA reg, r/m
1343  if (!i_w) { // i_w == 0
1344  // MOV
1345  i_w = 1;
1346  i_reg += 8;
1347  int32_t scratch2_uint = 4 * !i_mod;
1348  rm_addr = i_mod < 3 ?
1349  16 * regs16[seg_override_en ?
1350  seg_override
1351  : 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]])
1352  : (regs_offset + (2 * i_rm));
1353  if (i_d) {
1354  regs16[i_reg] = RMEM16(rm_addr);
1355  } else {
1356  WMEM16(rm_addr, regs16[i_reg]);
1357  }
1358  } else if (!i_d) { // i_w == 1 && i_d == 0
1359  // LEA
1360  int idx = 4 * !i_mod;
1361  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]];
1362  } else { // i_w == 1 && i_d == 1
1363  // POP
1364  regs16[REG_SP] += 2;
1365  WMEM16(rm_addr, RMEM16(16 * regs16[REG_SS] + (uint16_t)(-2 + regs16[REG_SP])));
1366  }
1367  break;
1368  case 11: // MOV AL/AX, [loc]
1369  rm_addr = 16 * regs16[seg_override_en ? seg_override : REG_DS] + i_data0;
1370  if (i_d) {
1371  if (i_w) {
1372  WMEM16(rm_addr, regs16[REG_AX]);
1373  } else {
1374  WMEM8(rm_addr, regs8[REG_AL]);
1375  }
1376  } else {
1377  if (i_w) {
1378  regs16[REG_AX] = RMEM16(rm_addr);
1379  } else {
1380  regs8[REG_AL] = RMEM8(rm_addr);
1381  }
1382  }
1383  reg_ip += 3;
1384  return; // no calc IP, no flags
1385  case 12: // ROL|ROR|RCL|RCR|SHL|SHR|???|SAR reg/MEM, 1/CL/imm (80186)
1386  {
1387  uint16_t scratch2_uint = (1 & (i_w ? (int16_t)RMEM16(rm_addr) : RMEM8(rm_addr)) >> (8 * (i_w + 1) - 1));
1388  uint16_t scratch_uint = extra ? // xxx reg/MEM, imm
1389  (int8_t) i_data1 : // xxx reg/MEM, CL
1390  i_d ?
1391  31 & regs8[REG_CL] : // xxx reg/MEM, 1
1392  1;
1393  if (scratch_uint) {
1394  if (i_reg < 4) {
1395  // Rotate operations
1396  scratch_uint %= i_reg / 2 + 8 * (i_w + 1);
1397  scratch2_uint = i_w ? RMEM16(rm_addr) : RMEM8(rm_addr);
1398  }
1399  if (i_reg & 1) {
1400  // Rotate/shift right operations
1401  if (i_w) {
1402  op_dest = RMEM16(rm_addr);
1403  op_result = WMEM16(rm_addr, (uint16_t)op_dest >> scratch_uint);
1404  } else {
1405  op_dest = RMEM8(rm_addr);
1406  op_result = WMEM8(rm_addr, (uint8_t)op_dest >> (uint8_t)scratch_uint);
1407  }
1408  } else {
1409  // Rotate/shift left operations
1410  if (i_w) {
1411  op_dest = RMEM16(rm_addr);
1412  op_result = WMEM16(rm_addr, (uint16_t)op_dest << scratch_uint);
1413  } else {
1414  op_dest = RMEM8(rm_addr);
1415  op_result = WMEM8(rm_addr, (uint8_t)op_dest << (uint8_t)scratch_uint);
1416  }
1417  }
1418  if (i_reg > 3) // Shift operations
1419  set_flags_type = 1; // Shift instructions affect SZP
1420  if (i_reg > 4) // SHR or SAR
1421  set_CF(op_dest >> (scratch_uint - 1) & 1);
1422  }
1423 
1424  switch (i_reg) {
1425  case 0: // ROL
1426  if (i_w) {
1427  op_dest = RMEM16(rm_addr);
1428  op_result = WMEM16(rm_addr, (uint16_t)op_dest + (op_source = scratch2_uint >> (16 - scratch_uint)));
1429  } else {
1430  op_dest = RMEM8(rm_addr);
1431  op_result = WMEM8(rm_addr, (uint8_t)op_dest + (op_source = (uint8_t)scratch2_uint >> (8 - scratch_uint)));
1432  }
1433  if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1434  set_OF((1 & op_result >> (8 * (i_w + 1) - 1)) ^ set_CF(op_result & 1));
1435  break;
1436  case 1: // ROR
1437  scratch2_uint &= (1 << scratch_uint) - 1;
1438  if (i_w) {
1439  op_dest = RMEM16(rm_addr);
1440  op_result = WMEM16(rm_addr, (uint16_t)op_dest + (op_source = scratch2_uint << (16 - scratch_uint)));
1441  } else {
1442  op_dest = RMEM8(rm_addr);
1443  op_result = WMEM8(rm_addr, (uint8_t)op_dest + (op_source = (uint8_t)scratch2_uint << (8 - scratch_uint)));
1444  }
1445  if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1446  set_OF((1 & (i_w ? (int16_t)op_result * 2 : op_result * 2) >> (8 * (i_w + 1) - 1)) ^ set_CF((1 & (i_w ? (int16_t)op_result : op_result) >> (8 * (i_w + 1) - 1))));
1447  break;
1448  case 2: // RCL
1449  if (i_w) {
1450  op_dest = RMEM16(rm_addr);
1451  op_result = WMEM16(rm_addr, (uint16_t)op_dest + (FLAG_CF << (scratch_uint - 1)) + (op_source = scratch2_uint >> (17 - scratch_uint)));
1452  } else {
1453  op_dest = RMEM8(rm_addr);
1454  op_result = WMEM8(rm_addr, (uint8_t)op_dest + (FLAG_CF << (scratch_uint - 1)) + (op_source = (uint8_t)scratch2_uint >> (9 - scratch_uint)));
1455  }
1456  if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1457  set_OF((1 & op_result >> (8 * (i_w + 1) - 1)) ^ set_CF(scratch2_uint & 1 << (8 * (i_w + 1) - scratch_uint)));
1458  break;
1459  case 3: // RCR
1460  if (i_w) {
1461  op_dest = RMEM16(rm_addr);
1462  op_result = WMEM16(rm_addr, (uint16_t)op_dest + (FLAG_CF << (16 - scratch_uint)) + (op_source = scratch2_uint << (17 - scratch_uint)));
1463  } else {
1464  op_dest = RMEM8(rm_addr);
1465  op_result = WMEM8(rm_addr, (uint8_t)op_dest + (FLAG_CF << (8 - scratch_uint)) + (op_source = (uint8_t)scratch2_uint << (9 - scratch_uint)));
1466  }
1467  if (scratch_uint) { // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1468  set_CF(scratch2_uint & 1 << (scratch_uint - 1));
1469  set_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)));
1470  }
1471  break;
1472  case 4: // SHL
1473  if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1474  set_OF((1 & op_result >> (8 * (i_w + 1) - 1)) ^ set_CF((1 & (op_dest << (scratch_uint - 1)) >> (8 * (i_w + 1) - 1))));
1475  break;
1476  case 5: // SHR
1477  if (scratch_uint) // fab: zero shift/rotation doesn't change CF or OF ("rotate.asm" and "shift.asm" tests)
1478  set_OF((1 & op_dest >> (8 * (i_w + 1) - 1)));
1479  break;
1480  case 7: // SAR
1481  scratch_uint < 8 * (i_w + 1) || set_CF(scratch2_uint);
1482  FLAG_OF = 0;
1483  if (i_w) {
1484  op_dest = RMEM16(rm_addr);
1485  uint16_t u16 = (uint16_t)scratch2_uint * ~(((1 << 16) - 1) >> scratch_uint);
1486  op_result = WMEM16(rm_addr, op_dest + (op_source = u16));
1487  } else {
1488  op_dest = RMEM8(rm_addr);
1489  uint8_t u8 = (uint8_t)scratch2_uint * ~(((1 << 8) - 1) >> scratch_uint);
1490  op_result = WMEM8(rm_addr, op_dest + (op_source = u8));
1491  }
1492  break;
1493  };
1494  break;
1495  }
1496  case 13: // LOOPxx / JCXZ
1497  {
1498  int32_t scratch_uint = !!--regs16[REG_CX];
1499  switch (i_reg4bit) {
1500  case 0: // LOOPNZ
1501  scratch_uint &= !FLAG_ZF;
1502  break;
1503  case 1: // LOOPZ
1504  scratch_uint &= FLAG_ZF;
1505  break;
1506  // case 2 is LOOP
1507  }
1508  reg_ip += scratch_uint * (int8_t) i_data0;
1509  break;
1510  }
1511  case 14: // JMP | CALL int16_t/near
1512  reg_ip += 3 - i_d;
1513  if (!i_w) {
1514  if (i_d) {
1515  // JMP far
1516  reg_ip = 0;
1517  regs16[REG_CS] = i_data2;
1518  } else {
1519  // CALL
1520  i_w = 1;
1521  regs16[REG_SP] -= 2;
1522  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = reg_ip;
1523  }
1524  }
1525  reg_ip += i_d && i_w ? (int8_t) i_data0 : i_data0;
1526  return; // no calc IP, no flags
1527  case 15: // TEST reg, r/m
1528  if (i_w) {
1529  op_result = RMEM16(op_from_addr) & RMEM16(op_to_addr);
1530  } else {
1531  op_result = RMEM8(op_from_addr) & RMEM8(op_to_addr);
1532  }
1533  break;
1534  case 16: // XCHG AX, regs16
1535  if (i_reg4bit != REG_AX) {
1536  uint16_t t = regs16[REG_AX];
1537  regs16[REG_AX] = regs16[i_reg4bit];
1538  regs16[i_reg4bit] = t;
1539  }
1540  ++reg_ip;
1541  return; // no calc ip, no flags
1542  case 24: // NOP|XCHG reg, r/m
1543  if (op_to_addr != op_from_addr) {
1544  if (i_w) {
1545  uint16_t t = RMEM16(op_to_addr);
1546  WMEM16(op_to_addr, RMEM16(op_from_addr));
1547  WMEM16(op_from_addr, t);
1548  } else {
1549  uint16_t t = RMEM8(op_to_addr);
1550  WMEM8(op_to_addr, RMEM8(op_from_addr));
1551  WMEM8(op_from_addr, t);
1552  }
1553  }
1554  break;
1555  case 17: // MOVSx (extra=0)|STOSx (extra=1)|LODSx (extra=2)
1556  {
1557  int32_t seg = seg_override_en ? seg_override : REG_DS;
1558  if (i_w) {
1559  const int dec = (2 * FLAG_DF - 1) * 2;
1560  for (int32_t i = rep_override_en ? regs16[REG_CX] : 1; i; --i) {
1561  uint16_t src = extra & 1 ? regs16[REG_AX] : RMEM16(16 * regs16[seg] + regs16[REG_SI]);
1562  if (extra < 2)
1563  WMEM16(16 * regs16[REG_ES] + regs16[REG_DI], src);
1564  else
1565  regs16[REG_AX] = src;
1566  extra & 1 || (regs16[REG_SI] -= dec);
1567  extra & 2 || (regs16[REG_DI] -= dec);
1568  }
1569  } else {
1570  const int dec = (2 * FLAG_DF - 1);
1571  for (int32_t i = rep_override_en ? regs16[REG_CX] : 1; i; --i) {
1572  uint8_t src = extra & 1 ? regs8[REG_AL] : RMEM8(16 * regs16[seg] + regs16[REG_SI]);
1573  if (extra < 2)
1574  WMEM8(16 * regs16[REG_ES] + regs16[REG_DI], src);
1575  else
1576  regs8[REG_AL] = src;
1577  extra & 1 || (regs16[REG_SI] -= dec);
1578  extra & 2 || (regs16[REG_DI] -= dec);
1579  }
1580  }
1581  if (rep_override_en)
1582  regs16[REG_CX] = 0;
1583  ++reg_ip;
1584  return; // no calc ip, no flags
1585  }
1586  case 18: // CMPSx (extra=0)|SCASx (extra=1)
1587  {
1588  int count = rep_override_en ? regs16[REG_CX] : 1;
1589  if (count) {
1590  int incval = (2 * FLAG_DF - 1) * (i_w + 1);
1591  if (extra) {
1592  // SCASx
1593  op_dest = i_w ? regs16[REG_AX] : regs8[REG_AL];
1594  for (; count; rep_override_en || count--) {
1595  if (i_w) {
1596  op_result = op_dest - (op_source = RMEM16(16 * regs16[REG_ES] + regs16[REG_DI]));
1597  } else {
1598  op_result = op_dest - (op_source = RMEM8(16 * regs16[REG_ES] + regs16[REG_DI]));
1599  }
1600  regs16[REG_DI] -= incval;
1601  rep_override_en && !(--regs16[REG_CX] && ((!op_result) == rep_mode)) && (count = 0);
1602  }
1603  } else {
1604  // CMPSx
1605  int scratch2_uint = seg_override_en ? seg_override : REG_DS;
1606  for (; count; rep_override_en || count--) {
1607  if (i_w) {
1608  op_dest = RMEM16(16 * regs16[scratch2_uint] + regs16[REG_SI]);
1609  op_result = op_dest - (op_source = RMEM16(16 * regs16[REG_ES] + regs16[REG_DI]));
1610  } else {
1611  op_dest = RMEM8(16 * regs16[scratch2_uint] + regs16[REG_SI]);
1612  op_result = op_dest - (op_source = RMEM8(16 * regs16[REG_ES] + regs16[REG_DI]));
1613  }
1614  regs16[REG_SI] -= incval;
1615  regs16[REG_DI] -= incval;
1616  rep_override_en && !(--regs16[REG_CX] && ((!op_result) == rep_mode)) && (count = 0);
1617  }
1618  }
1619  set_flags_type = 1 | 2; // Funge to set SZP/AO flags
1620  FLAG_CF = op_result > op_dest;
1621  };
1622  ++reg_ip;
1623  calcIP = false;
1624  break;
1625  }
1626  case 19: // RET|RETF|IRET
1627  i_d = i_w;
1628  reg_ip = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1629  regs16[REG_SP] += 2;
1630  if (extra) {
1631  // IRET|RETF|RETF imm16
1632  regs16[REG_CS] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1633  regs16[REG_SP] += 2;
1634  }
1635  if (extra & 2) {
1636  // IRET
1637  set_flags(MEM16(16 * regs16[REG_SS] + regs16[REG_SP]));
1638  regs16[REG_SP] += 2;
1639  } else if (!i_d) // RET|RETF imm16
1640  regs16[REG_SP] += i_data0;
1641  return; // no calc ip, no flags
1642  case 20: // MOV r/m, immed
1643  if (i_w) {
1644  WMEM16(op_from_addr, i_data2);
1645  } else {
1646  WMEM8(op_from_addr, i_data2);
1647  }
1648  break;
1649  case 21: // IN AL/AX, DX/imm8
1650  {
1651  int32_t port = extra ? regs16[REG_DX] : (uint8_t) i_data0;
1652  regs8[REG_AL] = s_readPort(s_context, port);
1653  if (i_w)
1654  regs8[REG_AH] = s_readPort(s_context, port + 1);
1655  break;
1656  }
1657  case 22: // OUT DX/imm8, AL/AX
1658  {
1659  int32_t port = extra ? regs16[REG_DX] : (uint8_t) i_data0;
1660  s_writePort(s_context, port, regs8[REG_AL]);
1661  if (i_w)
1662  s_writePort(s_context, port + 1, regs8[REG_AH]);
1663  break;
1664  }
1665  case 23: // REPxx
1666  rep_override_en = 2;
1667  rep_mode = i_w;
1668  seg_override_en && seg_override_en++;
1669  ++reg_ip;
1670  return; // no calc ip, no flags
1671  case 25: // PUSH segreg
1672  regs16[REG_SP] -= 2;
1673  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[extra];
1674  ++reg_ip;
1675  return; // no calc ip, no flags
1676  case 28: // DAA/DAS
1677  // fab: fixed to pass test186
1678  i_w = 0;
1679  FLAG_AF = (regs8[REG_AL] & 0x0f) > 9 || FLAG_AF;
1680  FLAG_CF = regs8[REG_AL] > 0x99 || FLAG_CF;
1681  if (extra) {
1682  // DAS
1683  if (FLAG_CF)
1684  regs8[REG_AL] -= 0x60;
1685  else if (FLAG_AF)
1686  FLAG_CF = (regs8[REG_AL] < 6);
1687  if (FLAG_AF)
1688  regs8[REG_AL] -= 6;
1689  } else {
1690  // DAA
1691  if (FLAG_CF)
1692  regs8[REG_AL] += 0x60;
1693  if (FLAG_AF)
1694  regs8[REG_AL] += 6;
1695  }
1696  op_result = regs8[REG_AL];
1697  break;
1698  case 29: // AAA/AAS
1699  op_result = AAA_AAS(extra - 1);
1700  break;
1701  case 30: // CBW
1702  regs8[REG_AH] = -(1 & (i_w ? * (int16_t *) & regs8[REG_AL] : regs8[REG_AL]) >> (8 * (i_w + 1) - 1));
1703  break;
1704  case 31: // CWD
1705  regs16[REG_DX] = -(1 & (i_w ? * (int16_t *) & regs16[REG_AX] : regs16[REG_AX]) >> (8 * (i_w + 1) - 1));
1706  break;
1707  case 32: // CALL FAR imm16:imm16
1708  regs16[REG_SP] -= 2;
1709  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_CS];
1710  regs16[REG_SP] -= 2;
1711  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = reg_ip + 5;
1712  regs16[REG_CS] = i_data2;
1713  reg_ip = i_data0;
1714  return; // no calc ip, no flags
1715  case 33: // PUSHF
1716  regs16[REG_SP] -= 2;
1717  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = make_flags();
1718  ++reg_ip;
1719  return; // no calc ip, no flags
1720  case 34: // POPF
1721  regs16[REG_SP] += 2;
1722  set_flags(MEM16(16 * regs16[REG_SS] + (uint16_t)(-2 + regs16[REG_SP])));
1723  ++reg_ip;
1724  return; // no calc ip, no flags
1725  case 35: // SAHF
1726  set_flags((make_flags() & 0xFF00) + regs8[REG_AH]);
1727  break;
1728  case 36: // LAHF
1729  regs8[REG_AH] = make_flags();
1730  break;
1731  case 37: // LES|LDS reg, r/m
1732  i_w = i_d = 1;
1733  regs16[i_reg] = RMEM16(rm_addr);
1734  regs16[extra / 2] = RMEM16(rm_addr + 2);
1735  break;
1736  case 38: // INT 3
1737  ++reg_ip;
1738  pc_interrupt(3);
1739  return; // no calc ip, no flags
1740  case 39: // INT imm8
1741  reg_ip += 2;
1742  pc_interrupt(i_data0);
1743  return; // no calc ip, no flags
1744  case 40: // INTO
1745  ++reg_ip;
1746  FLAG_OF && pc_interrupt(4);
1747  return; // no calc ip, no flags
1748  case 41: // AAM;
1749  if (i_data0 &= 0xFF) {
1750  regs8[REG_AH] = regs8[REG_AL] / i_data0;
1751  op_result = regs8[REG_AL] %= i_data0;
1752  } else {
1753  // Divide by zero
1754  raiseDivideByZeroInterrupt();
1755  return; // no calc ip, no flags
1756  }
1757  break;
1758  case 42: // AAD
1759  i_w = 0;
1760  regs16[REG_AX] = op_result = 0xFF & (regs8[REG_AL] + i_data0 * regs8[REG_AH]);
1761  break;
1762  case 43: // SALC
1763  regs8[REG_AL] = -FLAG_CF;
1764  break;
1765  case 44: // XLAT
1766  regs8[REG_AL] = RMEM8(16 * regs16[seg_override_en ? seg_override : REG_DS] + (uint16_t)(regs8[REG_AL] + regs16[REG_BX]));
1767  ++reg_ip;
1768  return; // no calc ip, no flags
1769  case 45: // CMC
1770  FLAG_CF ^= 1;
1771  ++reg_ip;
1772  return; // no calc ip, no flags
1773  case 47: // TEST AL/AX, immed
1774  if (i_w) {
1775  op_result = regs16[REG_AX] & i_data0;
1776  } else {
1777  op_result = regs8[REG_AL] & (uint8_t)i_data0;
1778  }
1779  break;
1780  case 48: // LOCK:
1781  ;
1782  break;
1783  case 49: // HLT
1784  //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]);
1785  s_halted = true;
1786  return; // no calc ip, no flags
1787  case 51: // 80186, NEC V20: ENTER
1788  {
1789  //printf("80186, NEC V20: ENTER\n");
1790  regs16[REG_SP] -= 2;
1791  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_BP];
1792  uint16_t framePtr = regs16[REG_SP];
1793  int16_t level = i_data2 & 31;
1794  if (level > 0) {
1795  while (--level) {
1796  regs16[REG_BP] -= 2;
1797  regs16[REG_SP] -= 2;
1798  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = MEM16(16 * regs16[REG_SS] + regs16[REG_BP]);
1799  }
1800  regs16[REG_SP] -= 2;
1801  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = framePtr;
1802  }
1803  regs16[REG_BP] = framePtr;
1804  regs16[REG_SP] -= i_data0;
1805  break;
1806  }
1807  case 52: // 80186, NEC V20: LEAVE
1808  //printf("80186, NEC V20: LEAVE\n");
1809  regs16[REG_SP] = regs16[REG_BP];
1810  regs16[REG_BP] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1811  regs16[REG_SP] += 2;
1812  break;
1813  case 53: // 80186, NEC V20: PUSHA
1814  {
1815  //printf("80186, NEC V20: PUSHA\n");
1816  uint16_t temp = regs16[REG_SP];
1817  regs16[REG_SP] -= 2;
1818  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_AX];
1819  regs16[REG_SP] -= 2;
1820  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_CX];
1821  regs16[REG_SP] -= 2;
1822  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_DX];
1823  regs16[REG_SP] -= 2;
1824  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_BX];
1825  regs16[REG_SP] -= 2;
1826  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = temp;
1827  regs16[REG_SP] -= 2;
1828  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_BP];
1829  regs16[REG_SP] -= 2;
1830  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_SI];
1831  regs16[REG_SP] -= 2;
1832  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = regs16[REG_DI];
1833  break;
1834  }
1835  case 54: // 80186, NEC V20: POPA
1836  {
1837  //printf("80186, NEC V20: POPA\n");
1838  regs16[REG_DI] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1839  regs16[REG_SP] += 2;
1840  regs16[REG_SI] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1841  regs16[REG_SP] += 2;
1842  regs16[REG_BP] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1843  regs16[REG_SP] += 2;
1844  regs16[REG_SP] += 2; // SP ignored
1845  regs16[REG_BX] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1846  regs16[REG_SP] += 2;
1847  regs16[REG_DX] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1848  regs16[REG_SP] += 2;
1849  regs16[REG_CX] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1850  regs16[REG_SP] += 2;
1851  regs16[REG_AX] = MEM16(16 * regs16[REG_SS] + regs16[REG_SP]);
1852  regs16[REG_SP] += 2;
1853  break;
1854  }
1855  case 55: // 80186: BOUND
1856  printf("80186: BOUND - not implemented!\n");
1857  break;
1858  case 56: // 80186, NEC V20: PUSH imm16
1859  //printf("80186, NEC V20: PUSH imm16\n");
1860  regs16[REG_SP] -= 2;
1861  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = i_data0;
1862  break;
1863  case 57: // 80186, NEC V20: PUSH imm8
1864  //printf("80186, NEC V20: PUSH imm8\n");
1865  regs16[REG_SP] -= 2;
1866  MEM16(16 * regs16[REG_SS] + regs16[REG_SP]) = (i_data0 & 0xff) | (i_data0 & 0x80 ? 0xff00 : 0); // 8->16 bit with sign extension
1867  break;
1868  case 58: // 80186 IMUL
1869  printf("80186 IMUL - not implemented!\n");
1870  break;
1871  case 59: // 80186: INSB INSW
1872  printf("80186: INSB INSW - not implemented!\n");
1873  break;
1874  case 60: // 80186: OUTSB OUTSW
1875  printf("80186: OUTSB OUTSW - not implemented!\n");
1876  break;
1877  case 69: // 8087 MATH Coprocessor
1878  printf("8087 MATH Coprocessor %02X %02X %02X %02X - not implemented!\n", opcode_stream[0], opcode_stream[1], opcode_stream[2], opcode_stream[3]);
1879  break;
1880  /*
1881  case 70: // 80286+
1882  printf("80286+\n");
1883  break;
1884  case 71: // 80386+
1885  printf("80386+\n");
1886  break;
1887  case 72: // BAD OP CODE
1888  printf("Bad 8086 opcode %02X %02X\n", opcode_stream[0], opcode_stream[1]);
1889  break;
1890  */
1891  default:
1892  printf("Unsupported 8086 opcode %02X %02X\n", opcode_stream[0], opcode_stream[1]);
1893  break;
1894  }
1895 
1896  // Increment instruction pointer by computed instruction length.
1897  if (calcIP)
1898  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);
1899 
1900  // If instruction needs to update SF, ZF and PF, set them as appropriate
1901  if (set_flags_type & 1) {
1902  FLAG_SF = (1 & op_result >> (8 * (i_w + 1) - 1));
1903  FLAG_ZF = !op_result;
1904  FLAG_PF = parity[(uint8_t) op_result];
1905 
1906  // If instruction is an arithmetic or logic operation, also set AF/OF/CF as appropriate.
1907  if (set_flags_type & 2)
1908  set_AF_OF_arith(op_result, i_w);
1909  if (set_flags_type & 4) {
1910  FLAG_CF = 0;
1911  FLAG_OF = 0;
1912  }
1913  }
1914 
1915 }
1916 
1917 
1918 } // namespace fabgl
Definition: canvas.cpp:36