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 #include "dosbox.h"
20 
21 #if C_FPU
22 
FPU_FLD_16(PhysPt addr)23 static void FPU_FLD_16(PhysPt addr) {
24 	dyn_dh_fpu.temp.m1 = (Bit32u)mem_readw(addr);
25 }
26 
FPU_FST_16(PhysPt addr)27 static void FPU_FST_16(PhysPt addr) {
28 	mem_writew(addr,(Bit16u)dyn_dh_fpu.temp.m1);
29 }
30 
FPU_FLD_32(PhysPt addr)31 static void FPU_FLD_32(PhysPt addr) {
32 	dyn_dh_fpu.temp.m1 = mem_readd(addr);
33 }
34 
FPU_FST_32(PhysPt addr)35 static void FPU_FST_32(PhysPt addr) {
36 	mem_writed(addr,dyn_dh_fpu.temp.m1);
37 }
38 
FPU_FLD_64(PhysPt addr)39 static void FPU_FLD_64(PhysPt addr) {
40 	dyn_dh_fpu.temp.m1 = mem_readd(addr);
41 	dyn_dh_fpu.temp.m2 = mem_readd(addr+4);
42 }
43 
FPU_FST_64(PhysPt addr)44 static void FPU_FST_64(PhysPt addr) {
45 	mem_writed(addr,dyn_dh_fpu.temp.m1);
46 	mem_writed(addr+4,dyn_dh_fpu.temp.m2);
47 }
48 
FPU_FLD_80(PhysPt addr)49 static void FPU_FLD_80(PhysPt addr) {
50 	dyn_dh_fpu.temp.m1 = mem_readd(addr);
51 	dyn_dh_fpu.temp.m2 = mem_readd(addr+4);
52 	dyn_dh_fpu.temp.m3 = mem_readw(addr+8);
53 }
54 
FPU_FST_80(PhysPt addr)55 static void FPU_FST_80(PhysPt addr) {
56 	mem_writed(addr,dyn_dh_fpu.temp.m1);
57 	mem_writed(addr+4,dyn_dh_fpu.temp.m2);
58 	mem_writew(addr+8,dyn_dh_fpu.temp.m3);
59 }
60 
FPU_FLDCW_DH(PhysPt addr)61 static void FPU_FLDCW_DH(PhysPt addr){
62 	dyn_dh_fpu.cw = mem_readw(addr);
63 	dyn_dh_fpu.temp.m1 = (Bit32u)(dyn_dh_fpu.cw|0x3f);
64 }
65 
FPU_FNSTCW_DH(PhysPt addr)66 static void FPU_FNSTCW_DH(PhysPt addr){
67 	mem_writew(addr,(Bit16u)(dyn_dh_fpu.cw&0xffff));
68 }
69 
FPU_FNINIT_DH(void)70 static void FPU_FNINIT_DH(void){
71 	dyn_dh_fpu.cw = 0x37f;
72 }
73 
FPU_FSTENV_DH(PhysPt addr)74 static void FPU_FSTENV_DH(PhysPt addr){
75 	if(!cpu.code.big) {
76 		mem_writew(addr+0,dyn_dh_fpu.cw);
77 		mem_writew(addr+2,(Bit16u)dyn_dh_fpu.temp.m2);
78 		mem_writew(addr+4,dyn_dh_fpu.temp.m3);
79 	} else {
80 		mem_writed(addr+0,dyn_dh_fpu.temp.m1);
81 		mem_writew(addr+0,dyn_dh_fpu.cw);
82 		mem_writed(addr+4,dyn_dh_fpu.temp.m2);
83 		mem_writed(addr+8,dyn_dh_fpu.temp.m3);
84 	}
85 }
86 
FPU_FLDENV_DH(PhysPt addr)87 static void FPU_FLDENV_DH(PhysPt addr){
88 	if(!cpu.code.big) {
89 		dyn_dh_fpu.cw = (Bit32u)mem_readw(addr);
90 		dyn_dh_fpu.temp.m1 = dyn_dh_fpu.cw|0x3f;
91 		dyn_dh_fpu.temp.m2 = (Bit32u)mem_readw(addr+2);
92 		dyn_dh_fpu.temp.m3 = mem_readw(addr+4);
93 	} else {
94 		dyn_dh_fpu.cw = (Bit32u)mem_readw(addr);
95 		dyn_dh_fpu.temp.m1 = mem_readd(addr)|0x3f;
96 		dyn_dh_fpu.temp.m2 = mem_readd(addr+4);
97 		dyn_dh_fpu.temp.m3 = mem_readw(addr+8);
98 		dyn_dh_fpu.temp.d1 = mem_readw(addr+10);
99 	}
100 }
101 
FPU_FSAVE_DH(PhysPt addr)102 static void FPU_FSAVE_DH(PhysPt addr){
103 	if (!cpu.code.big) {
104 		mem_writew(addr,dyn_dh_fpu.cw);
105 		addr+=2;
106 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x04]);
107 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x05]);
108 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x08]);
109 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x09]);
110 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x0c]);
111 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x0d]);
112 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x10]);
113 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x11]);
114 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x14]);
115 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x15]);
116 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x18]);
117 		mem_writeb(addr++,dyn_dh_fpu.temp_state[0x19]);
118 		for(Bitu i=28;i<108;i++) mem_writeb(addr++,dyn_dh_fpu.temp_state[i]);
119 	} else {
120 		mem_writew(addr,dyn_dh_fpu.cw);
121 		addr+=2;
122 		for(Bitu i=2;i<108;i++) mem_writeb(addr++,dyn_dh_fpu.temp_state[i]);
123 	}
124 }
125 
FPU_FRSTOR_DH(PhysPt addr)126 static void FPU_FRSTOR_DH(PhysPt addr){
127 	if (!cpu.code.big) {
128 		dyn_dh_fpu.cw = (Bit32u)mem_readw(addr);
129 		dyn_dh_fpu.temp_state[0x00] = mem_readb(addr++)|0x3f;
130 		dyn_dh_fpu.temp_state[0x01] = mem_readb(addr++);
131 		dyn_dh_fpu.temp_state[0x04] = mem_readb(addr++);
132 		dyn_dh_fpu.temp_state[0x05] = mem_readb(addr++);
133 		dyn_dh_fpu.temp_state[0x08] = mem_readb(addr++);
134 		dyn_dh_fpu.temp_state[0x09] = mem_readb(addr++);
135 		dyn_dh_fpu.temp_state[0x0c] = mem_readb(addr++);
136 		dyn_dh_fpu.temp_state[0x0d] = mem_readb(addr++);
137 		dyn_dh_fpu.temp_state[0x10] = mem_readb(addr++);
138 		dyn_dh_fpu.temp_state[0x11] = mem_readb(addr++);
139 		dyn_dh_fpu.temp_state[0x14] = mem_readb(addr++);
140 		dyn_dh_fpu.temp_state[0x15] = mem_readb(addr++);
141 		dyn_dh_fpu.temp_state[0x18] = mem_readb(addr++);
142 		dyn_dh_fpu.temp_state[0x19] = mem_readb(addr++);
143 		for(Bitu i=28;i<108;i++) dyn_dh_fpu.temp_state[i] = mem_readb(addr++);
144 	} else {
145 		dyn_dh_fpu.cw = (Bit32u)mem_readw(addr);
146 		for(Bitu i=0;i<108;i++) dyn_dh_fpu.temp_state[i] = mem_readb(addr++);
147 		dyn_dh_fpu.temp_state[0]|=0x3f;
148 	}
149 }
150 
151 static void dh_fpu_mem(Bit8u inst, Bitu reg=decode.modrm.reg, void* mem=&dyn_dh_fpu.temp.m1) {
152 #if C_TARGETCPU == X86
153 	cache_addb(inst);
154 	cache_addb(0x05|(reg<<3));
155 	cache_addd((Bit32u)(mem));
156 #else // X86_64
157 	opcode(reg).setabsaddr(mem).Emit8(inst);
158 #endif
159 }
160 
dh_fpu_esc0()161 static void dh_fpu_esc0(){
162 	dyn_get_modrm();
163 	if (decode.modrm.val >= 0xc0) {
164 		cache_addb(0xd8);
165 		cache_addb(decode.modrm.val);
166 	} else {
167 		dyn_fill_ea();
168 		gen_call_function((void*)&FPU_FLD_32,"%Drd",DREG(EA));
169 		dh_fpu_mem(0xd8);
170 	}
171 }
172 
dh_fpu_esc1()173 static void dh_fpu_esc1(){
174 	dyn_get_modrm();
175 	if (decode.modrm.val >= 0xc0) {
176 		cache_addb(0xd9);
177 		cache_addb(decode.modrm.val);
178 	} else {
179 		Bitu group=(decode.modrm.val >> 3) & 7;
180 		Bitu sub=(decode.modrm.val & 7);
181 		dyn_fill_ea();
182 		switch(group){
183 		case 0x00: /* FLD float*/
184 			gen_call_function((void*)&FPU_FLD_32,"%Drd",DREG(EA));
185 			dh_fpu_mem(0xd9);
186 			break;
187 		case 0x01: /* UNKNOWN */
188 			FPU_LOG_WARN(1,true,group,sub);
189 			break;
190 		case 0x02: /* FST float*/
191 		case 0x03: /* FSTP float*/
192 			dh_fpu_mem(0xd9);
193 			gen_call_function((void*)&FPU_FST_32,"%Drd",DREG(EA));
194 			break;
195 		case 0x04: /* FLDENV */
196 			gen_call_function((void*)&FPU_FLDENV_DH,"%Drd",DREG(EA));
197 			dh_fpu_mem(0xd9);
198 			break;
199 		case 0x05: /* FLDCW */
200 			gen_call_function((void *)&FPU_FLDCW_DH,"%Drd",DREG(EA));
201 			dh_fpu_mem(0xd9);
202 			break;
203 		case 0x06: /* FSTENV */
204 			dh_fpu_mem(0xd9);
205 			gen_call_function((void*)&FPU_FSTENV_DH,"%Drd",DREG(EA));
206 			break;
207 		case 0x07:  /* FNSTCW*/
208 			gen_call_function((void*)&FPU_FNSTCW_DH,"%Drd",DREG(EA));
209 			break;
210 		default:
211 			FPU_LOG_WARN(1,true,group,sub);
212 			break;
213 		}
214 	}
215 }
216 
dh_fpu_esc2()217 static void dh_fpu_esc2(){
218 	dyn_get_modrm();
219 	if (decode.modrm.val >= 0xc0) {
220 		cache_addb(0xda);
221 		cache_addb(decode.modrm.val);
222 	} else {
223 		dyn_fill_ea();
224 		gen_call_function((void*)&FPU_FLD_32,"%Drd",DREG(EA));
225 		dh_fpu_mem(0xda);
226 	}
227 }
228 
dh_fpu_esc3()229 static void dh_fpu_esc3(){
230 	dyn_get_modrm();
231 	const unsigned group = (decode.modrm.val >> 3) & 7;
232 	const unsigned sub = (decode.modrm.val & 7);
233 	if (decode.modrm.val >= 0xc0) {
234 		switch (group) {
235 		case 0x04:
236 			switch (sub) {
237 			case 0x00:				//FNENI
238 			case 0x01:				//FNDIS
239 				LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfunction: %u", sub);
240 				break;
241 			case 0x02:				//FNCLEX FCLEX
242 				cache_addb(0xdb);
243 				cache_addb(decode.modrm.val);
244 				break;
245 			case 0x03:				//FNINIT FINIT
246 				gen_call_function((void*)&FPU_FNINIT_DH,"");
247 				cache_addb(0xdb);
248 				cache_addb(decode.modrm.val);
249 				break;
250 			case 0x04:				//FNSETPM
251 			case 0x05:				//FRSTPM
252 				// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done");
253 				break;
254 			default:
255 				E_Exit("ESC 3:ILLEGAL OPCODE group %u subfunction %u", group, sub);
256 			}
257 			break;
258 		default:
259 			FPU_LOG_WARN(3, false, group, sub);
260 			break;
261 		}
262 	} else {
263 		dyn_fill_ea();
264 		switch (group) {
265 		case 0x00:	/* FILD */
266 			gen_call_function((void*)&FPU_FLD_32,"%Drd",DREG(EA));
267 			dh_fpu_mem(0xdb);
268 			break;
269 		case 0x01:	/* FISTTP */
270 			FPU_LOG_WARN(3, true, 1, sub);
271 			break;
272 		case 0x02:	/* FIST */
273 		case 0x03:	/* FISTP */
274 			dh_fpu_mem(0xdb);
275 			gen_call_function((void*)&FPU_FST_32,"%Drd",DREG(EA));
276 			break;
277 		case 0x05:	/* FLD 80 Bits Real */
278 			gen_call_function((void*)&FPU_FLD_80,"%Drd",DREG(EA));
279 			dh_fpu_mem(0xdb);
280 			break;
281 		case 0x07:	/* FSTP 80 Bits Real */
282 			dh_fpu_mem(0xdb);
283 			gen_call_function((void*)&FPU_FST_80,"%Drd",DREG(EA));
284 			break;
285 		default:
286 			FPU_LOG_WARN(3, true, group, sub);
287 			break;
288 		}
289 	}
290 }
291 
dh_fpu_esc4()292 static void dh_fpu_esc4(){
293 	dyn_get_modrm();
294 	if (decode.modrm.val >= 0xc0) {
295 		cache_addb(0xdc);
296 		cache_addb(decode.modrm.val);
297 	} else {
298 		dyn_fill_ea();
299 		gen_call_function((void*)&FPU_FLD_64,"%Drd",DREG(EA));
300 		dh_fpu_mem(0xdc);
301 	}
302 }
303 
dh_fpu_esc5()304 static void dh_fpu_esc5(){
305 	dyn_get_modrm();
306 	if (decode.modrm.val >= 0xc0) {
307 		cache_addb(0xdd);
308 		cache_addb(decode.modrm.val);
309 	} else {
310 		dyn_fill_ea();
311 		Bitu group=(decode.modrm.val >> 3) & 7;
312 		Bitu sub=(decode.modrm.val & 7);
313 		switch(group){
314 		case 0x00:  /* FLD double real*/
315 			gen_call_function((void*)&FPU_FLD_64,"%Drd",DREG(EA));
316 			dh_fpu_mem(0xdd);
317 			break;
318 		case 0x01:  /* FISTTP longint*/
319 			FPU_LOG_WARN(5,true,1,sub);
320 			break;
321 		case 0x02:   /* FST double real*/
322 		case 0x03:	/* FSTP double real*/
323 			dh_fpu_mem(0xdd);
324 			gen_call_function((void*)&FPU_FST_64,"%Drd",DREG(EA));
325 			break;
326 		case 0x04:	/* FRSTOR */
327 			gen_call_function((void*)&FPU_FRSTOR_DH,"%Drd",DREG(EA));
328 			dh_fpu_mem(0xdd, decode.modrm.reg, &(dyn_dh_fpu.temp_state[0]));
329 			break;
330 		case 0x06:	/* FSAVE */
331 			dh_fpu_mem(0xdd, decode.modrm.reg, &(dyn_dh_fpu.temp_state[0]));
332 			gen_call_function((void*)&FPU_FSAVE_DH,"%Drd",DREG(EA));
333 			cache_addw(0xE3DB);
334 			break;
335 		case 0x07:   /* FNSTSW */
336 			dh_fpu_mem(0xdd);
337 			gen_call_function((void*)&FPU_FST_16,"%Drd",DREG(EA));
338 			break;
339 		default:
340 			FPU_LOG_WARN(5,true,group,sub);
341 			break;
342 		}
343 	}
344 }
345 
dh_fpu_esc6()346 static void dh_fpu_esc6(){
347 	dyn_get_modrm();
348 	if (decode.modrm.val >= 0xc0) {
349 		cache_addb(0xde);
350 		cache_addb(decode.modrm.val);
351 	} else {
352 		dyn_fill_ea();
353 		gen_call_function((void*)&FPU_FLD_16,"%Drd",DREG(EA));
354 		dh_fpu_mem(0xde);
355 	}
356 }
357 
dh_fpu_esc7()358 static void dh_fpu_esc7(){
359 	dyn_get_modrm();
360 	Bitu group=(decode.modrm.val >> 3) & 7;
361 	Bitu sub=(decode.modrm.val & 7);
362 	if (decode.modrm.val >= 0xc0) {
363 		switch (group){
364 		case 0x00: /* FFREEP STi*/
365 		case 0x01: /* FXCH STi*/
366 		case 0x02:  /* FSTP STi*/
367 		case 0x03:  /* FSTP STi*/
368 			cache_addb(0xdf);
369 			cache_addb(decode.modrm.val);
370 			break;
371 		case 0x04:
372 			switch(sub){
373 				case 0x00:     /* FNSTSW AX*/
374 					dh_fpu_mem(0xdd, 7);
375 					gen_load_host(&(dyn_dh_fpu.temp.m1),DREG(TMPB),4);
376 					gen_dop_word(DOP_MOV,false,DREG(EAX),DREG(TMPB));
377 					gen_releasereg(DREG(TMPB));
378 					break;
379 				default:
380 					FPU_LOG_WARN(7,false,4,sub);
381 					break;
382 			}
383 			break;
384 		default:
385 			FPU_LOG_WARN(7,false,group,sub);
386 			break;
387 		}
388 	} else {
389 		dyn_fill_ea();
390 		switch(group){
391 		case 0x00:  /* FILD Bit16s */
392 			gen_call_function((void*)&FPU_FLD_16,"%Drd",DREG(EA));
393 			dh_fpu_mem(0xdf);
394 			break;
395 		case 0x01:
396 			FPU_LOG_WARN(7,true,1,sub);
397 			break;
398 		case 0x02:   /* FIST Bit16s */
399 		case 0x03:	/* FISTP Bit16s */
400 			dh_fpu_mem(0xdf);
401 			gen_call_function((void*)&FPU_FST_16,"%Drd",DREG(EA));
402 			break;
403 		case 0x04:   /* FBLD packed BCD */
404 			gen_call_function((void*)&FPU_FLD_80,"%Drd",DREG(EA));
405 			dh_fpu_mem(0xdf);
406 			break;
407 		case 0x05:  /* FILD Bit64s */
408 			gen_call_function((void*)&FPU_FLD_64,"%Drd",DREG(EA));
409 			dh_fpu_mem(0xdf);
410 			break;
411 		case 0x06:	/* FBSTP packed BCD */
412 			dh_fpu_mem(0xdf);
413 			gen_call_function((void*)&FPU_FST_80,"%Drd",DREG(EA));
414 			break;
415 		case 0x07:  /* FISTP Bit64s */
416 			dh_fpu_mem(0xdf);
417 			gen_call_function((void*)&FPU_FST_64,"%Drd",DREG(EA));
418 			break;
419 		default:
420 			FPU_LOG_WARN(7,true,group,sub);
421 			break;
422 		}
423 	}
424 }
425 
426 #endif // C_FPU
427