1 /*
2 * Copyright (C) 2002-2021 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19
20 #include <stdio.h>
21
22 #include "dosbox.h"
23 #include "mem.h"
24 #include "cpu.h"
25 #include "lazyflags.h"
26 #include "inout.h"
27 #include "callback.h"
28 #include "pic.h"
29 #include "fpu.h"
30 #include "paging.h"
31
32 #if C_DEBUG
33 #include "debug.h"
34 #endif
35
36 #if (!C_CORE_INLINE)
37 #define LoadMb(off) mem_readb(off)
38 #define LoadMw(off) mem_readw(off)
39 #define LoadMd(off) mem_readd(off)
40 #define SaveMb(off,val) mem_writeb(off,val)
41 #define SaveMw(off,val) mem_writew(off,val)
42 #define SaveMd(off,val) mem_writed(off,val)
43 #else
44 #include "paging.h"
45 #define LoadMb(off) mem_readb_inline(off)
46 #define LoadMw(off) mem_readw_inline(off)
47 #define LoadMd(off) mem_readd_inline(off)
48 #define SaveMb(off,val) mem_writeb_inline(off,val)
49 #define SaveMw(off,val) mem_writew_inline(off,val)
50 #define SaveMd(off,val) mem_writed_inline(off,val)
51 #endif
52
53 extern Bitu cycle_count;
54
55 #if C_FPU
56 #define CPU_FPU 1 //Enable FPU escape instructions
57 #endif
58
59 #define CPU_PIC_CHECK 1
60 #define CPU_TRAP_CHECK 1
61
62 #define CPU_TRAP_DECODER CPU_Core_Prefetch_Trap_Run
63
64 #define OPCODE_NONE 0x000
65 #define OPCODE_0F 0x100
66 #define OPCODE_SIZE 0x200
67
68 #define PREFIX_ADDR 0x1
69 #define PREFIX_REP 0x2
70
71 #define TEST_PREFIX_ADDR (core.prefixes & PREFIX_ADDR)
72 #define TEST_PREFIX_REP (core.prefixes & PREFIX_REP)
73
74 #define DO_PREFIX_SEG(_SEG) \
75 BaseDS=SegBase(_SEG); \
76 BaseSS=SegBase(_SEG); \
77 core.base_val_ds=_SEG; \
78 goto restart_opcode;
79
80 #define DO_PREFIX_ADDR() \
81 core.prefixes=(core.prefixes & ~PREFIX_ADDR) | \
82 (cpu.code.big ^ PREFIX_ADDR); \
83 core.ea_table=&EATable[(core.prefixes&1) * 256]; \
84 goto restart_opcode;
85
86 #define DO_PREFIX_REP(_ZERO) \
87 core.prefixes|=PREFIX_REP; \
88 core.rep_zero=_ZERO; \
89 goto restart_opcode;
90
91 typedef PhysPt (*GetEAHandler)(void);
92
93 static const Bit32u AddrMaskTable[2]={0x0000ffff,0xffffffff};
94
95 static struct {
96 Bitu opcode_index;
97 PhysPt cseip;
98 PhysPt base_ds,base_ss;
99 SegNames base_val_ds;
100 bool rep_zero;
101 Bitu prefixes;
102 GetEAHandler * ea_table;
103 } core;
104
105 #define GETIP (core.cseip-SegBase(cs))
106 #define SAVEIP reg_eip=GETIP;
107 #define LOADIP core.cseip=(SegBase(cs)+reg_eip);
108
109 #define SegBase(c) SegPhys(c)
110 #define BaseDS core.base_ds
111 #define BaseSS core.base_ss
112
113
114 #define MAX_PQ_SIZE 32
115 static Bit8u prefetch_buffer[MAX_PQ_SIZE];
116 static bool pq_valid=false;
117 static Bitu pq_start;
118
Fetchb()119 static Bit8u Fetchb() {
120 Bit8u temp;
121 if (pq_valid && (core.cseip>=pq_start) && (core.cseip<pq_start+CPU_PrefetchQueueSize)) {
122 temp=prefetch_buffer[core.cseip-pq_start];
123 if ((core.cseip+1>=pq_start+CPU_PrefetchQueueSize-4) &&
124 (core.cseip+1<pq_start+CPU_PrefetchQueueSize)) {
125 Bitu remaining_bytes=pq_start+CPU_PrefetchQueueSize-(core.cseip+1);
126 for (Bitu i=0; i<remaining_bytes; i++) prefetch_buffer[i]=prefetch_buffer[core.cseip+1-pq_start+i];
127 for (Bitu i=remaining_bytes; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+1+i);
128 pq_start=core.cseip+1;
129 pq_valid=true;
130 }
131 } else {
132 for (Bitu i=0; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+i);
133 pq_start=core.cseip;
134 pq_valid=true;
135 temp=prefetch_buffer[0];
136 }
137 /* if (temp!=LoadMb(core.cseip)) {
138 LOG_MSG("prefetch queue content!=memory at %x:%x",SegValue(cs),reg_eip);
139 } */
140 core.cseip+=1;
141 return temp;
142 }
143
Fetchw()144 static Bit16u Fetchw() {
145 Bit16u temp;
146 if (pq_valid && (core.cseip>=pq_start) && (core.cseip+2<pq_start+CPU_PrefetchQueueSize)) {
147 temp=prefetch_buffer[core.cseip-pq_start]|
148 (prefetch_buffer[core.cseip-pq_start+1]<<8);
149 if ((core.cseip+2>=pq_start+CPU_PrefetchQueueSize-4) &&
150 (core.cseip+2<pq_start+CPU_PrefetchQueueSize)) {
151 Bitu remaining_bytes=pq_start+CPU_PrefetchQueueSize-(core.cseip+2);
152 for (Bitu i=0; i<remaining_bytes; i++) prefetch_buffer[i]=prefetch_buffer[core.cseip+2-pq_start+i];
153 for (Bitu i=remaining_bytes; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+2+i);
154 pq_start=core.cseip+2;
155 pq_valid=true;
156 }
157 } else {
158 for (Bitu i=0; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+i);
159 pq_start=core.cseip;
160 pq_valid=true;
161 temp=prefetch_buffer[0] | (prefetch_buffer[1]<<8);
162 }
163 /* if (temp!=LoadMw(core.cseip)) {
164 LOG_MSG("prefetch queue content!=memory at %x:%x",SegValue(cs),reg_eip);
165 } */
166 core.cseip+=2;
167 return temp;
168 }
169
Fetchd()170 static Bit32u Fetchd() {
171 Bit32u temp;
172 if (pq_valid && (core.cseip>=pq_start) && (core.cseip+4<pq_start+CPU_PrefetchQueueSize)) {
173 temp=prefetch_buffer[core.cseip-pq_start]|
174 (prefetch_buffer[core.cseip-pq_start+1]<<8)|
175 (prefetch_buffer[core.cseip-pq_start+2]<<16)|
176 (prefetch_buffer[core.cseip-pq_start+3]<<24);
177 if ((core.cseip+4>=pq_start+CPU_PrefetchQueueSize-4) &&
178 (core.cseip+4<pq_start+CPU_PrefetchQueueSize)) {
179 Bitu remaining_bytes=pq_start+CPU_PrefetchQueueSize-(core.cseip+4);
180 for (Bitu i=0; i<remaining_bytes; i++) prefetch_buffer[i]=prefetch_buffer[core.cseip+4-pq_start+i];
181 for (Bitu i=remaining_bytes; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+4+i);
182 pq_start=core.cseip+4;
183 pq_valid=true;
184 }
185 } else {
186 for (Bitu i=0; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+i);
187 pq_start=core.cseip;
188 pq_valid=true;
189 temp=prefetch_buffer[0] | (prefetch_buffer[1]<<8) |
190 (prefetch_buffer[2]<<16) | (prefetch_buffer[3]<<24);
191 }
192 /* if (temp!=LoadMd(core.cseip)) {
193 LOG_MSG("prefetch queue content!=memory at %x:%x",SegValue(cs),reg_eip);
194 } */
195 core.cseip+=4;
196 return temp;
197 }
198
199 #define Push_16 CPU_Push16
200 #define Push_32 CPU_Push32
201 #define Pop_16 CPU_Pop16
202 #define Pop_32 CPU_Pop32
203
204 #include "instructions.h"
205 #include "core_normal/support.h"
206 #include "core_normal/string.h"
207
208
209 #define EALookupTable (core.ea_table)
210
CPU_Core_Prefetch_Run(void)211 Bits CPU_Core_Prefetch_Run(void) {
212 bool invalidate_pq=false;
213 while (CPU_Cycles-->0) {
214 if (invalidate_pq) {
215 pq_valid=false;
216 invalidate_pq=false;
217 }
218 LOADIP;
219 core.opcode_index=cpu.code.big*0x200;
220 core.prefixes=cpu.code.big;
221 core.ea_table=&EATable[cpu.code.big*256];
222 BaseDS=SegBase(ds);
223 BaseSS=SegBase(ss);
224 core.base_val_ds=ds;
225 #if C_DEBUG
226 #if C_HEAVY_DEBUG
227 if (DEBUG_HeavyIsBreakpoint()) {
228 FillFlags();
229 return debugCallback;
230 };
231 #endif
232 cycle_count++;
233 #endif
234 restart_opcode:
235 Bit8u next_opcode=Fetchb();
236 invalidate_pq=false;
237 if (core.opcode_index&OPCODE_0F) invalidate_pq=true;
238 else switch (next_opcode) {
239 case 0x70: case 0x71: case 0x72: case 0x73:
240 case 0x74: case 0x75: case 0x76: case 0x77:
241 case 0x78: case 0x79: case 0x7a: case 0x7b:
242 case 0x7c: case 0x7d: case 0x7e: case 0x7f: // jcc
243 case 0x9a: // call
244 case 0xc2: case 0xc3: // retn
245 case 0xc8: // enter
246 case 0xc9: // leave
247 case 0xca: case 0xcb: // retf
248 case 0xcc: // int3
249 case 0xcd: // int
250 case 0xce: // into
251 case 0xcf: // iret
252 case 0xe0: // loopnz
253 case 0xe1: // loopz
254 case 0xe2: // loop
255 case 0xe3: // jcxz
256 case 0xe8: // call
257 case 0xe9: case 0xea: case 0xeb: // jmp
258 case 0xff:
259 invalidate_pq=true;
260 break;
261 default:
262 break;
263 }
264 switch (core.opcode_index+next_opcode) {
265 #include "core_normal/prefix_none.h"
266 #include "core_normal/prefix_0f.h"
267 #include "core_normal/prefix_66.h"
268 #include "core_normal/prefix_66_0f.h"
269 default:
270 illegal_opcode:
271 #if C_DEBUG
272 {
273 Bitu len=(GETIP-reg_eip);
274 LOADIP;
275 if (len>16) len=16;
276 char tempcode[16*2+1];char * writecode=tempcode;
277 for (;len>0;len--) {
278 sprintf(writecode,"%02X",mem_readb(core.cseip++));
279 writecode+=2;
280 }
281 LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode);
282 }
283 #endif
284 CPU_Exception(6,0);
285 invalidate_pq=true;
286 continue;
287 }
288 SAVEIP;
289 }
290 FillFlags();
291 return CBRET_NONE;
292 decode_end:
293 SAVEIP;
294 FillFlags();
295 return CBRET_NONE;
296 }
297
CPU_Core_Prefetch_Trap_Run(void)298 Bits CPU_Core_Prefetch_Trap_Run(void) {
299 Bits oldCycles = CPU_Cycles;
300 CPU_Cycles = 1;
301 cpu.trap_skip = false;
302
303 Bits ret=CPU_Core_Prefetch_Run();
304 if (!cpu.trap_skip) CPU_DebugException(DBINT_STEP,reg_eip);
305 CPU_Cycles = oldCycles-1;
306 cpudecoder = &CPU_Core_Prefetch_Run;
307
308 return ret;
309 }
310
311
312
CPU_Core_Prefetch_Init(void)313 void CPU_Core_Prefetch_Init(void) {
314
315 }
316
317