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