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