@aptre/v86 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.MIT +22 -0
  3. package/Readme.md +237 -0
  4. package/dist/v86.browser.js +26666 -0
  5. package/dist/v86.browser.js.map +7 -0
  6. package/dist/v86.js +26632 -0
  7. package/dist/v86.js.map +7 -0
  8. package/gen/generate_analyzer.ts +512 -0
  9. package/gen/generate_interpreter.ts +522 -0
  10. package/gen/generate_jit.ts +624 -0
  11. package/gen/rust_ast.ts +107 -0
  12. package/gen/util.ts +35 -0
  13. package/gen/x86_table.ts +1836 -0
  14. package/lib/9p.ts +1547 -0
  15. package/lib/filesystem.ts +1879 -0
  16. package/lib/marshall.ts +168 -0
  17. package/lib/softfloat/softfloat.c +32501 -0
  18. package/lib/zstd/zstddeclib.c +13520 -0
  19. package/package.json +75 -0
  20. package/src/acpi.ts +267 -0
  21. package/src/browser/dummy_screen.ts +106 -0
  22. package/src/browser/fake_network.ts +1771 -0
  23. package/src/browser/fetch_network.ts +361 -0
  24. package/src/browser/filestorage.ts +124 -0
  25. package/src/browser/inbrowser_network.ts +57 -0
  26. package/src/browser/keyboard.ts +564 -0
  27. package/src/browser/main.ts +3415 -0
  28. package/src/browser/mouse.ts +255 -0
  29. package/src/browser/network.ts +142 -0
  30. package/src/browser/print_stats.ts +336 -0
  31. package/src/browser/screen.ts +978 -0
  32. package/src/browser/serial.ts +316 -0
  33. package/src/browser/speaker.ts +1223 -0
  34. package/src/browser/starter.ts +1688 -0
  35. package/src/browser/wisp_network.ts +332 -0
  36. package/src/browser/worker_bus.ts +64 -0
  37. package/src/buffer.ts +652 -0
  38. package/src/bus.ts +78 -0
  39. package/src/const.ts +128 -0
  40. package/src/cpu.ts +2891 -0
  41. package/src/dma.ts +474 -0
  42. package/src/elf.ts +251 -0
  43. package/src/floppy.ts +1778 -0
  44. package/src/ide.ts +3455 -0
  45. package/src/io.ts +504 -0
  46. package/src/iso9660.ts +317 -0
  47. package/src/kernel.ts +250 -0
  48. package/src/lib.ts +645 -0
  49. package/src/log.ts +149 -0
  50. package/src/main.ts +199 -0
  51. package/src/ne2k.ts +1589 -0
  52. package/src/pci.ts +815 -0
  53. package/src/pit.ts +406 -0
  54. package/src/ps2.ts +820 -0
  55. package/src/rtc.ts +537 -0
  56. package/src/rust/analysis.rs +101 -0
  57. package/src/rust/codegen.rs +2660 -0
  58. package/src/rust/config.rs +3 -0
  59. package/src/rust/control_flow.rs +425 -0
  60. package/src/rust/cpu/apic.rs +658 -0
  61. package/src/rust/cpu/arith.rs +1207 -0
  62. package/src/rust/cpu/call_indirect.rs +2 -0
  63. package/src/rust/cpu/cpu.rs +4501 -0
  64. package/src/rust/cpu/fpu.rs +923 -0
  65. package/src/rust/cpu/global_pointers.rs +112 -0
  66. package/src/rust/cpu/instructions.rs +2486 -0
  67. package/src/rust/cpu/instructions_0f.rs +5261 -0
  68. package/src/rust/cpu/ioapic.rs +316 -0
  69. package/src/rust/cpu/memory.rs +351 -0
  70. package/src/rust/cpu/misc_instr.rs +613 -0
  71. package/src/rust/cpu/mod.rs +16 -0
  72. package/src/rust/cpu/modrm.rs +133 -0
  73. package/src/rust/cpu/pic.rs +402 -0
  74. package/src/rust/cpu/sse_instr.rs +361 -0
  75. package/src/rust/cpu/string.rs +701 -0
  76. package/src/rust/cpu/vga.rs +175 -0
  77. package/src/rust/cpu_context.rs +69 -0
  78. package/src/rust/dbg.rs +98 -0
  79. package/src/rust/gen/analyzer.rs +3807 -0
  80. package/src/rust/gen/analyzer0f.rs +3992 -0
  81. package/src/rust/gen/interpreter.rs +4447 -0
  82. package/src/rust/gen/interpreter0f.rs +5404 -0
  83. package/src/rust/gen/jit.rs +5080 -0
  84. package/src/rust/gen/jit0f.rs +5547 -0
  85. package/src/rust/gen/mod.rs +14 -0
  86. package/src/rust/jit.rs +2443 -0
  87. package/src/rust/jit_instructions.rs +7881 -0
  88. package/src/rust/js_api.rs +6 -0
  89. package/src/rust/leb.rs +46 -0
  90. package/src/rust/lib.rs +29 -0
  91. package/src/rust/modrm.rs +330 -0
  92. package/src/rust/opstats.rs +249 -0
  93. package/src/rust/page.rs +15 -0
  94. package/src/rust/paging.rs +25 -0
  95. package/src/rust/prefix.rs +15 -0
  96. package/src/rust/profiler.rs +155 -0
  97. package/src/rust/regs.rs +38 -0
  98. package/src/rust/softfloat.rs +286 -0
  99. package/src/rust/state_flags.rs +27 -0
  100. package/src/rust/wasmgen/mod.rs +2 -0
  101. package/src/rust/wasmgen/wasm_builder.rs +1047 -0
  102. package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
  103. package/src/rust/zstd.rs +105 -0
  104. package/src/sb16.ts +1928 -0
  105. package/src/state.ts +359 -0
  106. package/src/uart.ts +472 -0
  107. package/src/vga.ts +2791 -0
  108. package/src/virtio.ts +1756 -0
  109. package/src/virtio_balloon.ts +273 -0
  110. package/src/virtio_console.ts +372 -0
  111. package/src/virtio_net.ts +326 -0
@@ -0,0 +1,923 @@
1
+ use crate::cpu::cpu::*;
2
+ use crate::cpu::global_pointers::*;
3
+ use crate::paging::OrPageFault;
4
+ use crate::softfloat::{Precision, RoundingMode, F80};
5
+
6
+ use std::f64;
7
+
8
+ const FPU_C0: u16 = 0x100;
9
+ const FPU_C1: u16 = 0x200;
10
+ const FPU_C2: u16 = 0x400;
11
+ const FPU_C3: u16 = 0x4000;
12
+ const FPU_RESULT_FLAGS: u16 = FPU_C0 | FPU_C1 | FPU_C2 | FPU_C3;
13
+
14
+ const FPU_EX_I: u16 = 1 << 0; // invalid operation
15
+ #[allow(dead_code)]
16
+ const FPU_EX_D: u16 = 1 << 1; // denormal operand
17
+ const FPU_EX_Z: u16 = 1 << 2; // zero divide
18
+ #[allow(dead_code)]
19
+ const FPU_EX_O: u16 = 1 << 3; // overflow
20
+ const FPU_EX_U: u16 = 1 << 4; // underflow
21
+ #[allow(dead_code)]
22
+ const FPU_EX_P: u16 = 1 << 5; // precision
23
+ const FPU_EX_SF: u16 = 1 << 6;
24
+
25
+ pub fn fpu_write_st(index: i32, value: F80) {
26
+ dbg_assert!(index >= 0 && index < 8);
27
+ unsafe {
28
+ *fpu_st.offset(index as isize) = value;
29
+ }
30
+ }
31
+
32
+ pub unsafe fn fpu_get_st0() -> F80 {
33
+ dbg_assert!(*fpu_stack_ptr < 8);
34
+ if 0 != *fpu_stack_empty >> *fpu_stack_ptr & 1 {
35
+ *fpu_status_word &= !FPU_C1;
36
+ fpu_stack_fault();
37
+ return F80::INDEFINITE_NAN;
38
+ }
39
+ else {
40
+ return *fpu_st.offset(*fpu_stack_ptr as isize);
41
+ };
42
+ }
43
+ pub unsafe fn fpu_stack_fault() {
44
+ // TODO: Interrupt
45
+ *fpu_status_word |= FPU_EX_SF | FPU_EX_I;
46
+ }
47
+
48
+ pub unsafe fn fpu_zero_fault() {
49
+ // TODO: Interrupt
50
+ *fpu_status_word |= FPU_EX_Z;
51
+ }
52
+
53
+ pub unsafe fn fpu_underflow_fault() {
54
+ // TODO: Interrupt
55
+ *fpu_status_word |= FPU_EX_U;
56
+ }
57
+
58
+ pub unsafe fn fpu_sti_empty(mut i: i32) -> bool {
59
+ dbg_assert!(i >= 0 && i < 8);
60
+ i = i + *fpu_stack_ptr as i32 & 7;
61
+ return 0 != *fpu_stack_empty >> i & 1;
62
+ }
63
+
64
+ #[no_mangle]
65
+ pub unsafe fn fpu_get_sti_jit(dst: *mut F80, i: i32) { *dst = fpu_get_sti(i); }
66
+
67
+ pub unsafe fn fpu_get_sti(mut i: i32) -> F80 {
68
+ dbg_assert!(i >= 0 && i < 8);
69
+ i = i + *fpu_stack_ptr as i32 & 7;
70
+ if 0 != *fpu_stack_empty >> i & 1 {
71
+ *fpu_status_word &= !FPU_C1;
72
+ fpu_stack_fault();
73
+ return F80::INDEFINITE_NAN;
74
+ }
75
+ else {
76
+ return *fpu_st.offset(i as isize);
77
+ };
78
+ }
79
+
80
+ // only used for debugging
81
+ #[no_mangle]
82
+ pub unsafe fn fpu_get_sti_f64(mut i: i32) -> f64 {
83
+ i = i + *fpu_stack_ptr as i32 & 7;
84
+ f64::from_bits((*fpu_st.offset(i as isize)).to_f64())
85
+ }
86
+
87
+ #[no_mangle]
88
+ pub unsafe fn f32_to_f80_jit(dst: *mut F80, v: i32) { *dst = f32_to_f80(v) }
89
+ pub unsafe fn f32_to_f80(v: i32) -> F80 {
90
+ F80::clear_exception_flags();
91
+ let x = F80::of_f32(v);
92
+ *fpu_status_word |= F80::get_exception_flags() as u16;
93
+ x
94
+ }
95
+ #[no_mangle]
96
+ pub unsafe fn f64_to_f80_jit(dst: *mut F80, v: u64) { *dst = f64_to_f80(v) }
97
+ pub unsafe fn f64_to_f80(v: u64) -> F80 {
98
+ F80::clear_exception_flags();
99
+ let x = F80::of_f64(v);
100
+ *fpu_status_word |= F80::get_exception_flags() as u16;
101
+ x
102
+ }
103
+ #[no_mangle]
104
+ pub unsafe fn f80_to_f32(v: F80) -> i32 {
105
+ F80::clear_exception_flags();
106
+ let x = v.to_f32();
107
+ *fpu_status_word |= F80::get_exception_flags() as u16;
108
+ x
109
+ }
110
+ #[no_mangle]
111
+ pub unsafe fn f80_to_f64(v: F80) -> u64 {
112
+ F80::clear_exception_flags();
113
+ let x = v.to_f64();
114
+ *fpu_status_word |= F80::get_exception_flags() as u16;
115
+ x
116
+ }
117
+
118
+ #[no_mangle]
119
+ pub unsafe fn i32_to_f80_jit(dst: *mut F80, v: i32) { *dst = i32_to_f80(v) }
120
+ pub unsafe fn i32_to_f80(v: i32) -> F80 { F80::of_i32(v) }
121
+ #[no_mangle]
122
+ pub unsafe fn i64_to_f80_jit(dst: *mut F80, v: i64) { *dst = i64_to_f80(v) }
123
+ pub unsafe fn i64_to_f80(v: i64) -> F80 { F80::of_i64(v) }
124
+
125
+ pub unsafe fn fpu_load_i16(addr: i32) -> OrPageFault<F80> {
126
+ let v = safe_read16(addr)? as i16 as i32;
127
+ Ok(F80::of_i32(v))
128
+ }
129
+ pub unsafe fn fpu_load_i32(addr: i32) -> OrPageFault<F80> {
130
+ let v = safe_read32s(addr)?;
131
+ Ok(F80::of_i32(v))
132
+ }
133
+ pub unsafe fn fpu_load_i64(addr: i32) -> OrPageFault<F80> {
134
+ let v = safe_read64s(addr)? as i64;
135
+ Ok(F80::of_i64(v))
136
+ }
137
+
138
+ pub unsafe fn fpu_load_m32(addr: i32) -> OrPageFault<F80> {
139
+ F80::clear_exception_flags();
140
+ let v = F80::of_f32(safe_read32s(addr)?);
141
+ *fpu_status_word |= F80::get_exception_flags() as u16;
142
+ Ok(v)
143
+ }
144
+ pub unsafe fn fpu_load_m64(addr: i32) -> OrPageFault<F80> {
145
+ F80::clear_exception_flags();
146
+ let v = F80::of_f64(safe_read64s(addr)?);
147
+ *fpu_status_word |= F80::get_exception_flags() as u16;
148
+ Ok(v)
149
+ }
150
+ pub unsafe fn fpu_load_m80(addr: i32) -> OrPageFault<F80> {
151
+ let mantissa = safe_read64s(addr)?;
152
+ let sign_exponent = safe_read16(addr + 8)? as u16;
153
+ // TODO: Canonical form
154
+ Ok(F80 {
155
+ mantissa,
156
+ sign_exponent,
157
+ })
158
+ }
159
+
160
+ #[no_mangle]
161
+ pub unsafe fn fpu_load_status_word() -> u16 {
162
+ dbg_assert!(*fpu_stack_ptr < 8);
163
+ return *fpu_status_word & !(7 << 11) | (*fpu_stack_ptr as u16) << 11;
164
+ }
165
+ #[no_mangle]
166
+ pub unsafe fn fpu_fadd(target_index: i32, val: F80) {
167
+ F80::clear_exception_flags();
168
+ let st0 = fpu_get_st0();
169
+ fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, st0 + val);
170
+ *fpu_status_word |= F80::get_exception_flags() as u16;
171
+ }
172
+ pub unsafe fn fpu_fclex() { *fpu_status_word = 0; }
173
+ pub unsafe fn fpu_fcmovcc(condition: bool, r: i32) {
174
+ // outside of the condition is correct: A stack fault happens even if the condition is not
175
+ // fulfilled
176
+ let x = fpu_get_sti(r);
177
+ if fpu_sti_empty(r) {
178
+ fpu_write_st(*fpu_stack_ptr as i32, F80::INDEFINITE_NAN)
179
+ }
180
+ else {
181
+ if condition {
182
+ fpu_write_st(*fpu_stack_ptr as i32, x);
183
+ *fpu_stack_empty &= !(1 << *fpu_stack_ptr)
184
+ };
185
+ }
186
+ }
187
+
188
+ #[no_mangle]
189
+ pub unsafe fn fpu_fcom(y: F80) {
190
+ F80::clear_exception_flags();
191
+ let x = fpu_get_st0();
192
+ *fpu_status_word &= !FPU_RESULT_FLAGS;
193
+ match x.partial_cmp(&y) {
194
+ Some(std::cmp::Ordering::Greater) => {},
195
+ Some(std::cmp::Ordering::Less) => *fpu_status_word |= FPU_C0,
196
+ Some(std::cmp::Ordering::Equal) => *fpu_status_word |= FPU_C3,
197
+ None => *fpu_status_word |= FPU_C0 | FPU_C2 | FPU_C3,
198
+ }
199
+ *fpu_status_word |= F80::get_exception_flags() as u16;
200
+ }
201
+
202
+ #[no_mangle]
203
+ pub unsafe fn fpu_fcomi(r: i32) {
204
+ F80::clear_exception_flags();
205
+ let x = fpu_get_st0();
206
+ let y = fpu_get_sti(r);
207
+ *flags_changed = 0;
208
+ *flags &= !FLAGS_ALL;
209
+ match x.partial_cmp(&y) {
210
+ Some(std::cmp::Ordering::Greater) => {},
211
+ Some(std::cmp::Ordering::Less) => *flags |= 1,
212
+ Some(std::cmp::Ordering::Equal) => *flags |= FLAG_ZERO,
213
+ None => *flags |= 1 | FLAG_PARITY | FLAG_ZERO,
214
+ }
215
+ *fpu_status_word |= F80::get_exception_flags() as u16;
216
+ }
217
+
218
+ #[no_mangle]
219
+ pub unsafe fn fpu_fcomip(r: i32) {
220
+ fpu_fcomi(r);
221
+ fpu_pop();
222
+ }
223
+
224
+ #[no_mangle]
225
+ pub unsafe fn fpu_pop() {
226
+ dbg_assert!(*fpu_stack_ptr < 8);
227
+ *fpu_stack_empty |= 1 << *fpu_stack_ptr;
228
+ *fpu_stack_ptr = *fpu_stack_ptr + 1 & 7;
229
+ }
230
+
231
+ #[no_mangle]
232
+ pub unsafe fn fpu_fcomp(val: F80) {
233
+ fpu_fcom(val);
234
+ fpu_pop();
235
+ }
236
+
237
+ #[no_mangle]
238
+ pub unsafe fn fpu_fdiv(target_index: i32, val: F80) {
239
+ F80::clear_exception_flags();
240
+ let st0 = fpu_get_st0();
241
+ fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, st0 / val);
242
+ *fpu_status_word |= F80::get_exception_flags() as u16;
243
+ }
244
+ #[no_mangle]
245
+ pub unsafe fn fpu_fdivr(target_index: i32, val: F80) {
246
+ F80::clear_exception_flags();
247
+ let st0 = fpu_get_st0();
248
+ fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, val / st0);
249
+ *fpu_status_word |= F80::get_exception_flags() as u16;
250
+ }
251
+ #[no_mangle]
252
+ pub unsafe fn fpu_ffree(r: i32) { *fpu_stack_empty |= 1 << (*fpu_stack_ptr as i32 + r & 7); }
253
+
254
+ pub unsafe fn fpu_fildm16(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_i16(addr))); }
255
+ pub unsafe fn fpu_fildm32(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_i32(addr))); }
256
+ pub unsafe fn fpu_fildm64(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_i64(addr))); }
257
+
258
+ #[no_mangle]
259
+ pub unsafe fn fpu_push(x: F80) {
260
+ *fpu_stack_ptr = *fpu_stack_ptr - 1 & 7;
261
+ if 0 != *fpu_stack_empty >> *fpu_stack_ptr & 1 {
262
+ *fpu_status_word &= !FPU_C1;
263
+ *fpu_stack_empty &= !(1 << *fpu_stack_ptr);
264
+ fpu_write_st(*fpu_stack_ptr as i32, x);
265
+ }
266
+ else {
267
+ *fpu_status_word |= FPU_C1;
268
+ fpu_stack_fault();
269
+ fpu_write_st(*fpu_stack_ptr as i32, F80::INDEFINITE_NAN);
270
+ };
271
+ }
272
+ pub unsafe fn fpu_finit() {
273
+ set_control_word(0x37F);
274
+ *fpu_status_word = 0;
275
+ *fpu_ip = 0;
276
+ *fpu_dp = 0;
277
+ *fpu_opcode = 0;
278
+ *fpu_stack_empty = 0xFF;
279
+ *fpu_stack_ptr = 0;
280
+ }
281
+
282
+ #[no_mangle]
283
+ pub unsafe fn set_control_word(cw: u16) {
284
+ *fpu_control_word = cw;
285
+
286
+ let rc = cw >> 10 & 3;
287
+ F80::set_rounding_mode(match rc {
288
+ 0 => RoundingMode::NearEven,
289
+ 1 => RoundingMode::Floor,
290
+ 2 => RoundingMode::Ceil,
291
+ 3 => RoundingMode::Trunc,
292
+ _ => {
293
+ dbg_assert!(false);
294
+ RoundingMode::NearEven
295
+ },
296
+ });
297
+
298
+ let precision_control = cw >> 8 & 3;
299
+ F80::set_precision(match precision_control {
300
+ 0 => Precision::P32,
301
+ 1 => Precision::P80, // undefined
302
+ 2 => Precision::P64,
303
+ 3 => Precision::P80,
304
+ _ => {
305
+ dbg_assert!(false);
306
+ Precision::P80
307
+ },
308
+ });
309
+ }
310
+
311
+ pub unsafe fn fpu_invalid_arithmetic() { *fpu_status_word |= FPU_EX_I; }
312
+
313
+ #[no_mangle]
314
+ pub unsafe fn fpu_convert_to_i16(f: F80) -> i16 {
315
+ let st0 = fpu_convert_to_i32(f);
316
+ if st0 < -0x8000 || st0 > 0x7FFF {
317
+ fpu_invalid_arithmetic();
318
+ -0x8000
319
+ }
320
+ else {
321
+ st0 as i16
322
+ }
323
+ }
324
+ pub unsafe fn fpu_fistm16(addr: i32) {
325
+ return_on_pagefault!(writable_or_pagefault(addr, 2));
326
+ let v = fpu_convert_to_i16(fpu_get_st0());
327
+ safe_write16(addr, v as i32 & 0xFFFF).unwrap();
328
+ }
329
+ pub unsafe fn fpu_fistm16p(addr: i32) {
330
+ return_on_pagefault!(writable_or_pagefault(addr, 2));
331
+ let v = fpu_convert_to_i16(fpu_get_st0());
332
+ safe_write16(addr, v as i32 & 0xFFFF).unwrap();
333
+ fpu_pop();
334
+ }
335
+ #[no_mangle]
336
+ pub unsafe fn fpu_truncate_to_i16(f: F80) -> i16 {
337
+ let st0 = fpu_truncate_to_i32(f);
338
+ if st0 < -0x8000 || st0 > 0x7FFF {
339
+ fpu_invalid_arithmetic();
340
+ -0x8000
341
+ }
342
+ else {
343
+ st0 as i16
344
+ }
345
+ }
346
+ pub unsafe fn fpu_fisttpm16(addr: i32) {
347
+ return_on_pagefault!(writable_or_pagefault(addr, 2));
348
+ let v = fpu_truncate_to_i16(fpu_get_st0());
349
+ safe_write16(addr, v as i32 & 0xFFFF).unwrap();
350
+ fpu_pop();
351
+ }
352
+
353
+ #[no_mangle]
354
+ pub unsafe fn fpu_convert_to_i32(f: F80) -> i32 {
355
+ F80::clear_exception_flags();
356
+ let x = f.to_i32();
357
+ *fpu_status_word |= F80::get_exception_flags() as u16;
358
+ x
359
+ }
360
+ pub unsafe fn fpu_fistm32(addr: i32) {
361
+ return_on_pagefault!(writable_or_pagefault(addr, 4));
362
+ let v = fpu_convert_to_i32(fpu_get_st0());
363
+ safe_write32(addr, v).unwrap();
364
+ }
365
+ pub unsafe fn fpu_fistm32p(addr: i32) {
366
+ return_on_pagefault!(writable_or_pagefault(addr, 4));
367
+ let v = fpu_convert_to_i32(fpu_get_st0());
368
+ safe_write32(addr, v).unwrap();
369
+ fpu_pop();
370
+ }
371
+ #[no_mangle]
372
+ pub unsafe fn fpu_truncate_to_i32(f: F80) -> i32 {
373
+ F80::clear_exception_flags();
374
+ let x = f.truncate_to_i32();
375
+ *fpu_status_word |= F80::get_exception_flags() as u16;
376
+ x
377
+ }
378
+ pub unsafe fn fpu_fisttpm32(addr: i32) {
379
+ return_on_pagefault!(writable_or_pagefault(addr, 4));
380
+ let v = fpu_truncate_to_i32(fpu_get_st0());
381
+ safe_write32(addr, v).unwrap();
382
+ fpu_pop();
383
+ }
384
+
385
+ #[no_mangle]
386
+ pub unsafe fn fpu_convert_to_i64(f: F80) -> i64 {
387
+ F80::clear_exception_flags();
388
+ let x = f.to_i64();
389
+ *fpu_status_word |= F80::get_exception_flags() as u16;
390
+ x
391
+ }
392
+ pub unsafe fn fpu_fistm64p(addr: i32) {
393
+ return_on_pagefault!(writable_or_pagefault(addr, 8));
394
+ let v = fpu_convert_to_i64(fpu_get_st0());
395
+ safe_write64(addr, v as u64).unwrap();
396
+ fpu_pop();
397
+ }
398
+ #[no_mangle]
399
+ pub unsafe fn fpu_truncate_to_i64(f: F80) -> i64 {
400
+ F80::clear_exception_flags();
401
+ let x = f.truncate_to_i64();
402
+ *fpu_status_word |= F80::get_exception_flags() as u16;
403
+ x
404
+ }
405
+ pub unsafe fn fpu_fisttpm64(addr: i32) {
406
+ return_on_pagefault!(writable_or_pagefault(addr, 8));
407
+ let v = fpu_truncate_to_i64(fpu_get_st0());
408
+ safe_write64(addr, v as u64).unwrap();
409
+ fpu_pop();
410
+ }
411
+
412
+ pub unsafe fn fpu_fldcw(addr: i32) {
413
+ let word = return_on_pagefault!(safe_read16(addr)) as u16;
414
+ set_control_word(word);
415
+ }
416
+
417
+ #[no_mangle]
418
+ pub unsafe fn fpu_fldenv16(_addr: i32) {
419
+ dbg_log!("fldenv16");
420
+ fpu_unimpl();
421
+ }
422
+ #[no_mangle]
423
+ pub unsafe fn fpu_fldenv32(addr: i32) {
424
+ if let Err(()) = readable_or_pagefault(addr, 28) {
425
+ *page_fault = true;
426
+ return;
427
+ }
428
+ *page_fault = false;
429
+ set_control_word(safe_read16(addr).unwrap() as u16);
430
+ fpu_set_status_word(safe_read16(addr + 4).unwrap() as u16);
431
+ fpu_set_tag_word(safe_read16(addr + 8).unwrap());
432
+ *fpu_ip = safe_read32s(addr + 12).unwrap();
433
+ *fpu_ip_selector = safe_read16(addr + 16).unwrap();
434
+ *fpu_opcode = safe_read16(addr + 18).unwrap();
435
+ *fpu_dp = safe_read32s(addr + 20).unwrap();
436
+ *fpu_dp_selector = safe_read16(addr + 24).unwrap()
437
+ }
438
+ pub unsafe fn fpu_unimpl() {
439
+ dbg_assert!(false);
440
+ trigger_ud();
441
+ }
442
+ pub unsafe fn fpu_set_tag_word(tag_word: i32) {
443
+ *fpu_stack_empty = 0;
444
+ for i in 0..8 {
445
+ let empty = tag_word >> (2 * i) & 3 == 3;
446
+ *fpu_stack_empty |= (empty as u8) << i;
447
+ }
448
+ }
449
+ pub unsafe fn fpu_set_status_word(sw: u16) {
450
+ *fpu_status_word = sw & !(7 << 11);
451
+ *fpu_stack_ptr = (sw >> 11 & 7) as u8;
452
+ }
453
+
454
+ pub unsafe fn fpu_fldm32(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_m32(addr))); }
455
+ pub unsafe fn fpu_fldm64(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_m64(addr))); }
456
+ #[no_mangle]
457
+ pub unsafe fn fpu_fldm80(addr: i32) {
458
+ match fpu_load_m80(addr) {
459
+ Ok(x) => {
460
+ *page_fault = false;
461
+ fpu_push(x)
462
+ },
463
+ Err(()) => {
464
+ *page_fault = true;
465
+ },
466
+ }
467
+ }
468
+
469
+ #[no_mangle]
470
+ pub unsafe fn fpu_fmul(target_index: i32, val: F80) {
471
+ let st0 = fpu_get_st0();
472
+ fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, st0 * val);
473
+ }
474
+ pub unsafe fn fpu_fnstsw_mem(addr: i32) {
475
+ return_on_pagefault!(safe_write16(addr, fpu_load_status_word().into()));
476
+ }
477
+ pub unsafe fn fpu_fnstsw_reg() { write_reg16(AX, fpu_load_status_word().into()); }
478
+ pub unsafe fn fpu_fprem(ieee: bool) {
479
+ // false: Faster, fails nasmtests
480
+ // true: Slower, fails qemutests
481
+ let intel_compatibility = false;
482
+
483
+ let st0 = fpu_get_st0();
484
+ let st1 = fpu_get_sti(1);
485
+
486
+ if st1 == F80::ZERO {
487
+ if st0 == F80::ZERO {
488
+ fpu_invalid_arithmetic();
489
+ }
490
+ else {
491
+ fpu_zero_fault();
492
+ }
493
+ fpu_write_st(*fpu_stack_ptr as i32, F80::INDEFINITE_NAN);
494
+ return;
495
+ }
496
+
497
+ let exp0 = st0.log2();
498
+ let exp1 = st1.log2();
499
+ let d = (exp0 - exp1).abs();
500
+ if !intel_compatibility || d < F80::of_f64(f64::to_bits(64.0)) {
501
+ let fprem_quotient =
502
+ (if ieee { (st0 / st1).round() } else { (st0 / st1).trunc() }).to_i32();
503
+ fpu_write_st(*fpu_stack_ptr as i32, st0 % st1);
504
+ *fpu_status_word &= !(FPU_C0 | FPU_C1 | FPU_C3);
505
+ if 0 != fprem_quotient & 1 {
506
+ *fpu_status_word |= FPU_C1
507
+ }
508
+ if 0 != fprem_quotient & 1 << 1 {
509
+ *fpu_status_word |= FPU_C3
510
+ }
511
+ if 0 != fprem_quotient & 1 << 2 {
512
+ *fpu_status_word |= FPU_C0
513
+ }
514
+ *fpu_status_word &= !FPU_C2;
515
+ }
516
+ else {
517
+ let n = F80::of_f64(f64::to_bits(32.0));
518
+ let fprem_quotient =
519
+ (if ieee { (st0 / st1).round() } else { (st0 / st1).trunc() } / (d - n).two_pow());
520
+ fpu_write_st(
521
+ *fpu_stack_ptr as i32,
522
+ st0 - st1 * fprem_quotient * (d - n).two_pow(),
523
+ );
524
+ *fpu_status_word |= FPU_C2;
525
+ }
526
+ }
527
+
528
+ pub unsafe fn fpu_frstor16(_addr: i32) {
529
+ dbg_log!("frstor16");
530
+ fpu_unimpl();
531
+ }
532
+ pub unsafe fn fpu_frstor32(mut addr: i32) {
533
+ return_on_pagefault!(readable_or_pagefault(addr, 28 + 8 * 10));
534
+ fpu_fldenv32(addr);
535
+ addr += 28;
536
+ for i in 0..8 {
537
+ let reg_index = *fpu_stack_ptr as i32 + i & 7;
538
+ *fpu_st.offset(reg_index as isize) = fpu_load_m80(addr).unwrap();
539
+ addr += 10;
540
+ }
541
+ }
542
+
543
+ pub unsafe fn fpu_fsave16(_addr: i32) {
544
+ dbg_log!("fsave16");
545
+ fpu_unimpl();
546
+ }
547
+ pub unsafe fn fpu_fsave32(mut addr: i32) {
548
+ return_on_pagefault!(writable_or_pagefault(addr, 108));
549
+ fpu_fstenv32(addr);
550
+ addr += 28;
551
+ for i in 0..8 {
552
+ let reg_index = i + *fpu_stack_ptr as i32 & 7;
553
+ fpu_store_m80(addr, *fpu_st.offset(reg_index as isize));
554
+ addr += 10;
555
+ }
556
+ fpu_finit();
557
+ }
558
+
559
+ pub unsafe fn fpu_store_m80(addr: i32, f: F80) {
560
+ // writable_or_pagefault must have checked called by the caller!
561
+ safe_write64(addr, f.mantissa).unwrap();
562
+ safe_write16(addr + 8, f.sign_exponent as i32).unwrap();
563
+ }
564
+
565
+ #[no_mangle]
566
+ pub unsafe fn fpu_fstenv16(_addr: i32) {
567
+ dbg_log!("fstenv16");
568
+ fpu_unimpl();
569
+ }
570
+
571
+ #[no_mangle]
572
+ pub unsafe fn fpu_fstenv32(addr: i32) {
573
+ match writable_or_pagefault(addr, 26) {
574
+ Ok(()) => *page_fault = false,
575
+ Err(()) => {
576
+ *page_fault = true;
577
+ return;
578
+ },
579
+ }
580
+ let high_bits = 0xFFFF0000u32 as i32;
581
+ safe_write32(addr + 0, high_bits + *fpu_control_word as i32).unwrap();
582
+ safe_write32(addr + 4, high_bits + fpu_load_status_word() as i32).unwrap();
583
+ safe_write32(addr + 8, high_bits + fpu_load_tag_word()).unwrap();
584
+ safe_write32(addr + 12, *fpu_ip).unwrap();
585
+ safe_write16(addr + 16, *fpu_ip_selector).unwrap();
586
+ safe_write16(addr + 18, *fpu_opcode).unwrap();
587
+ safe_write32(addr + 20, *fpu_dp).unwrap();
588
+ safe_write32(addr + 24, high_bits | *fpu_dp_selector).unwrap();
589
+ }
590
+ #[no_mangle]
591
+ pub unsafe fn fpu_load_tag_word() -> i32 {
592
+ let mut tag_word = 0;
593
+ for i in 0..8 {
594
+ let value = *fpu_st.offset(i as isize);
595
+ if 0 != *fpu_stack_empty >> i & 1 {
596
+ tag_word |= 3 << (i << 1)
597
+ }
598
+ else if value == F80::ZERO {
599
+ tag_word |= 1 << (i << 1)
600
+ }
601
+ else if !value.is_finite() {
602
+ tag_word |= 2 << (i << 1)
603
+ }
604
+ }
605
+ return tag_word;
606
+ }
607
+ #[no_mangle]
608
+ pub unsafe fn fpu_fst(r: i32) { fpu_write_st(*fpu_stack_ptr as i32 + r & 7, fpu_get_st0()); }
609
+ pub unsafe fn fpu_fst80p(addr: i32) {
610
+ return_on_pagefault!(writable_or_pagefault(addr, 10));
611
+ fpu_store_m80(addr, fpu_get_st0());
612
+ fpu_pop();
613
+ }
614
+
615
+ pub unsafe fn fpu_fstcw(addr: i32) {
616
+ return_on_pagefault!(safe_write16(addr, (*fpu_control_word).into()));
617
+ }
618
+
619
+ pub unsafe fn fpu_fstm32(addr: i32) {
620
+ return_on_pagefault!(fpu_store_m32(addr, fpu_get_st0()));
621
+ }
622
+ pub unsafe fn fpu_store_m32(addr: i32, x: F80) -> OrPageFault<()> {
623
+ F80::clear_exception_flags();
624
+ safe_write32(addr, x.to_f32())?;
625
+ *fpu_status_word |= F80::get_exception_flags() as u16;
626
+ Ok(())
627
+ }
628
+ pub unsafe fn fpu_fstm32p(addr: i32) {
629
+ return_on_pagefault!(fpu_store_m32(addr, fpu_get_st0()));
630
+ fpu_pop();
631
+ }
632
+ pub unsafe fn fpu_fstm64(addr: i32) {
633
+ return_on_pagefault!(fpu_store_m64(addr, fpu_get_st0()));
634
+ }
635
+ pub unsafe fn fpu_store_m64(addr: i32, x: F80) -> OrPageFault<()> { safe_write64(addr, x.to_f64()) }
636
+ pub unsafe fn fpu_fstm64p(addr: i32) {
637
+ // XXX: writable_or_pagefault before get_st0
638
+ return_on_pagefault!(fpu_store_m64(addr, fpu_get_st0()));
639
+ fpu_pop();
640
+ }
641
+ #[no_mangle]
642
+ pub unsafe fn fpu_fstp(r: i32) {
643
+ fpu_fst(r);
644
+ fpu_pop();
645
+ }
646
+
647
+ #[no_mangle]
648
+ pub unsafe fn fpu_fbstp(addr: i32) {
649
+ match writable_or_pagefault(addr, 26) {
650
+ Ok(()) => *page_fault = false,
651
+ Err(()) => {
652
+ *page_fault = true;
653
+ return;
654
+ },
655
+ }
656
+ let st0 = fpu_get_st0();
657
+ let mut x = st0.to_i64().unsigned_abs();
658
+ if x <= 99_9999_9999_9999_9999 {
659
+ for i in 0..=8 {
660
+ let low = x % 10;
661
+ x /= 10;
662
+ let high = x % 10;
663
+ x /= 10;
664
+ safe_write8(addr + i, (high as i32) << 4 | low as i32).unwrap();
665
+ }
666
+ safe_write8(addr + 9, if st0.sign() { 0x80 } else { 0 }).unwrap();
667
+ }
668
+ else {
669
+ fpu_invalid_arithmetic();
670
+ safe_write64(addr + 0, 0xC000_0000_0000_0000).unwrap();
671
+ safe_write16(addr + 8, 0xFFFF).unwrap();
672
+ }
673
+ fpu_pop();
674
+ }
675
+
676
+ #[no_mangle]
677
+ pub unsafe fn fpu_fsub(target_index: i32, val: F80) {
678
+ let st0 = fpu_get_st0();
679
+ fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, st0 - val)
680
+ }
681
+ #[no_mangle]
682
+ pub unsafe fn fpu_fsubr(target_index: i32, val: F80) {
683
+ let st0 = fpu_get_st0();
684
+ fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, val - st0)
685
+ }
686
+
687
+ pub unsafe fn fpu_ftst() {
688
+ let x = fpu_get_st0();
689
+ *fpu_status_word &= !FPU_RESULT_FLAGS;
690
+ if x.is_nan() {
691
+ *fpu_status_word |= FPU_C3 | FPU_C2 | FPU_C0
692
+ }
693
+ else if x == F80::ZERO {
694
+ *fpu_status_word |= FPU_C3
695
+ }
696
+ else if x < F80::ZERO {
697
+ *fpu_status_word |= FPU_C0
698
+ }
699
+ // TODO: unordered (x is nan, etc)
700
+ }
701
+
702
+ #[no_mangle]
703
+ pub unsafe fn fpu_fucom(r: i32) {
704
+ F80::clear_exception_flags();
705
+ let x = fpu_get_st0();
706
+ let y = fpu_get_sti(r);
707
+ *fpu_status_word &= !FPU_RESULT_FLAGS;
708
+ match x.partial_cmp_quiet(&y) {
709
+ Some(std::cmp::Ordering::Greater) => {},
710
+ Some(std::cmp::Ordering::Less) => *fpu_status_word |= FPU_C0,
711
+ Some(std::cmp::Ordering::Equal) => *fpu_status_word |= FPU_C3,
712
+ None => *fpu_status_word |= FPU_C0 | FPU_C2 | FPU_C3,
713
+ }
714
+ *fpu_status_word |= F80::get_exception_flags() as u16;
715
+ }
716
+
717
+ #[no_mangle]
718
+ pub unsafe fn fpu_fucomi(r: i32) {
719
+ F80::clear_exception_flags();
720
+ let x = fpu_get_st0();
721
+ let y = fpu_get_sti(r);
722
+ *flags_changed = 0;
723
+ *flags &= !FLAGS_ALL;
724
+ match x.partial_cmp_quiet(&y) {
725
+ Some(std::cmp::Ordering::Greater) => {},
726
+ Some(std::cmp::Ordering::Less) => *flags |= 1,
727
+ Some(std::cmp::Ordering::Equal) => *flags |= FLAG_ZERO,
728
+ None => *flags |= 1 | FLAG_PARITY | FLAG_ZERO,
729
+ }
730
+ *fpu_status_word |= F80::get_exception_flags() as u16;
731
+ }
732
+
733
+ #[no_mangle]
734
+ pub unsafe fn fpu_fucomip(r: i32) {
735
+ fpu_fucomi(r);
736
+ fpu_pop();
737
+ }
738
+
739
+ #[no_mangle]
740
+ pub unsafe fn fpu_fucomp(r: i32) {
741
+ fpu_fucom(r);
742
+ fpu_pop();
743
+ }
744
+
745
+ #[no_mangle]
746
+ pub unsafe fn fpu_fucompp() {
747
+ fpu_fucom(1);
748
+ fpu_pop();
749
+ fpu_pop();
750
+ }
751
+
752
+ pub unsafe fn fpu_fxam() {
753
+ let x = fpu_get_st0();
754
+ *fpu_status_word &= !FPU_RESULT_FLAGS;
755
+ *fpu_status_word |= (x.sign() as u16) << 9;
756
+ if 0 != *fpu_stack_empty >> *fpu_stack_ptr & 1 {
757
+ *fpu_status_word |= FPU_C3 | FPU_C0
758
+ }
759
+ else if x.is_nan() {
760
+ *fpu_status_word |= FPU_C0
761
+ }
762
+ else if x == F80::ZERO {
763
+ *fpu_status_word |= FPU_C3
764
+ }
765
+ else if !x.is_finite() {
766
+ *fpu_status_word |= FPU_C2 | FPU_C0
767
+ }
768
+ else {
769
+ *fpu_status_word |= FPU_C2
770
+ }
771
+ // TODO:
772
+ // Unsupported, Denormal
773
+ }
774
+
775
+ #[no_mangle]
776
+ pub unsafe fn fpu_fxch(i: i32) {
777
+ let sti = fpu_get_sti(i);
778
+ fpu_write_st(*fpu_stack_ptr as i32 + i & 7, fpu_get_st0());
779
+ fpu_write_st(*fpu_stack_ptr as i32, sti);
780
+ }
781
+ pub unsafe fn fpu_fyl2x() {
782
+ let st0 = fpu_get_st0();
783
+ if st0 < F80::ZERO {
784
+ fpu_invalid_arithmetic();
785
+ }
786
+ else if st0 == F80::ZERO {
787
+ fpu_zero_fault();
788
+ }
789
+ fpu_write_st(
790
+ *fpu_stack_ptr as i32 + 1 & 7,
791
+ fpu_get_sti(1) * st0.ln() / F80::LN_2,
792
+ );
793
+ fpu_pop();
794
+ }
795
+
796
+ pub unsafe fn fpu_fxtract() {
797
+ let st0 = fpu_get_st0();
798
+ if st0 == F80::ZERO {
799
+ fpu_zero_fault();
800
+ fpu_write_st(*fpu_stack_ptr as i32, F80::NEG_INFINITY);
801
+ fpu_push(st0);
802
+ }
803
+ else {
804
+ let exp = st0.exponent();
805
+ fpu_write_st(*fpu_stack_ptr as i32, F80::of_i32(exp.into()));
806
+ fpu_push(F80 {
807
+ sign_exponent: 0x3FFF,
808
+ mantissa: st0.mantissa,
809
+ });
810
+ }
811
+ }
812
+
813
+ pub unsafe fn fwait() {
814
+ // NOP unless FPU instructions run in parallel with CPU instructions
815
+ }
816
+
817
+ pub unsafe fn fpu_fchs() {
818
+ let st0 = fpu_get_st0();
819
+ fpu_write_st(*fpu_stack_ptr as i32, -st0);
820
+ }
821
+
822
+ pub unsafe fn fpu_fabs() {
823
+ let st0 = fpu_get_st0();
824
+ fpu_write_st(*fpu_stack_ptr as i32, st0.abs());
825
+ }
826
+
827
+ pub unsafe fn fpu_f2xm1() {
828
+ let st0 = fpu_get_st0();
829
+ let r = st0.two_pow() - F80::ONE;
830
+ fpu_write_st(*fpu_stack_ptr as i32, r)
831
+ }
832
+
833
+ pub unsafe fn fpu_fptan() {
834
+ let st0 = fpu_get_st0();
835
+ //if -pow(2.0, 63.0) < st0 && st0 < pow(2.0, 63.0) {
836
+ fpu_write_st(*fpu_stack_ptr as i32, st0.tan());
837
+ // no bug: push constant 1
838
+ fpu_push(F80::ONE);
839
+ *fpu_status_word &= !FPU_C2;
840
+ //}
841
+ //else {
842
+ // *fpu_status_word |= FPU_C2;
843
+ //}
844
+ }
845
+
846
+ pub unsafe fn fpu_fpatan() {
847
+ let st0 = fpu_get_st0();
848
+ let st1 = fpu_get_sti(1);
849
+ fpu_write_st(*fpu_stack_ptr as i32 + 1 & 7, st1.atan2(st0));
850
+ fpu_pop();
851
+ }
852
+
853
+ pub unsafe fn fpu_fyl2xp1() {
854
+ // fyl2xp1: y * log2(x+1) and pop
855
+ let st0 = fpu_get_st0();
856
+ let st1 = fpu_get_sti(1);
857
+ let y = st1 * (st0 + F80::ONE).ln() / F80::LN_2;
858
+ fpu_write_st(*fpu_stack_ptr as i32 + 1 & 7, y);
859
+ fpu_pop();
860
+ }
861
+
862
+ pub unsafe fn fpu_fsqrt() {
863
+ let st0 = fpu_get_st0();
864
+ //if st0 < 0.0 {
865
+ // fpu_invalid_arithmetic();
866
+ //}
867
+ fpu_write_st(*fpu_stack_ptr as i32, st0.sqrt())
868
+ }
869
+
870
+ pub unsafe fn fpu_fsincos() {
871
+ let st0 = fpu_get_st0();
872
+ //if pow(-2.0, 63.0) < st0 && st0 < pow(2.0, 63.0) {
873
+ fpu_write_st(*fpu_stack_ptr as i32, st0.sin());
874
+ fpu_push(st0.cos());
875
+ *fpu_status_word &= !FPU_C2;
876
+ //}
877
+ //else {
878
+ // *fpu_status_word |= FPU_C2;
879
+ //}
880
+ }
881
+
882
+ pub unsafe fn fpu_frndint() {
883
+ let st0 = fpu_get_st0();
884
+ fpu_write_st(*fpu_stack_ptr as i32, st0.round());
885
+ }
886
+
887
+ pub unsafe fn fpu_fscale() {
888
+ let st0 = fpu_get_st0();
889
+ let y = st0 * fpu_get_sti(1).trunc().two_pow();
890
+ fpu_write_st(*fpu_stack_ptr as i32, y);
891
+ }
892
+
893
+ pub unsafe fn fpu_fsin() {
894
+ let st0 = fpu_get_st0();
895
+ //if pow(-2.0, 63.0) < st0 && st0 < pow(2.0, 63.0) {
896
+ fpu_write_st(*fpu_stack_ptr as i32, st0.sin());
897
+ *fpu_status_word &= !FPU_C2;
898
+ //}
899
+ //else {
900
+ // *fpu_status_word |= FPU_C2;
901
+ //}
902
+ }
903
+
904
+ pub unsafe fn fpu_fcos() {
905
+ let st0 = fpu_get_st0();
906
+ //if pow(-2.0, 63.0) < st0 && st0 < pow(2.0, 63.0) {
907
+ fpu_write_st(*fpu_stack_ptr as i32, st0.cos());
908
+ *fpu_status_word &= !FPU_C2;
909
+ //}
910
+ //else {
911
+ // *fpu_status_word |= FPU_C2;
912
+ //}
913
+ }
914
+
915
+ pub unsafe fn fpu_fdecstp() {
916
+ *fpu_stack_ptr = *fpu_stack_ptr - 1 & 7;
917
+ *fpu_status_word &= !FPU_C1
918
+ }
919
+
920
+ pub unsafe fn fpu_fincstp() {
921
+ *fpu_stack_ptr = *fpu_stack_ptr + 1 & 7;
922
+ *fpu_status_word &= !FPU_C1
923
+ }