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