@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.
- package/LICENSE +22 -0
- package/LICENSE.MIT +22 -0
- package/Readme.md +237 -0
- package/dist/v86.browser.js +26666 -0
- package/dist/v86.browser.js.map +7 -0
- package/dist/v86.js +26632 -0
- package/dist/v86.js.map +7 -0
- package/gen/generate_analyzer.ts +512 -0
- package/gen/generate_interpreter.ts +522 -0
- package/gen/generate_jit.ts +624 -0
- package/gen/rust_ast.ts +107 -0
- package/gen/util.ts +35 -0
- package/gen/x86_table.ts +1836 -0
- package/lib/9p.ts +1547 -0
- package/lib/filesystem.ts +1879 -0
- package/lib/marshall.ts +168 -0
- package/lib/softfloat/softfloat.c +32501 -0
- package/lib/zstd/zstddeclib.c +13520 -0
- package/package.json +75 -0
- package/src/acpi.ts +267 -0
- package/src/browser/dummy_screen.ts +106 -0
- package/src/browser/fake_network.ts +1771 -0
- package/src/browser/fetch_network.ts +361 -0
- package/src/browser/filestorage.ts +124 -0
- package/src/browser/inbrowser_network.ts +57 -0
- package/src/browser/keyboard.ts +564 -0
- package/src/browser/main.ts +3415 -0
- package/src/browser/mouse.ts +255 -0
- package/src/browser/network.ts +142 -0
- package/src/browser/print_stats.ts +336 -0
- package/src/browser/screen.ts +978 -0
- package/src/browser/serial.ts +316 -0
- package/src/browser/speaker.ts +1223 -0
- package/src/browser/starter.ts +1688 -0
- package/src/browser/wisp_network.ts +332 -0
- package/src/browser/worker_bus.ts +64 -0
- package/src/buffer.ts +652 -0
- package/src/bus.ts +78 -0
- package/src/const.ts +128 -0
- package/src/cpu.ts +2891 -0
- package/src/dma.ts +474 -0
- package/src/elf.ts +251 -0
- package/src/floppy.ts +1778 -0
- package/src/ide.ts +3455 -0
- package/src/io.ts +504 -0
- package/src/iso9660.ts +317 -0
- package/src/kernel.ts +250 -0
- package/src/lib.ts +645 -0
- package/src/log.ts +149 -0
- package/src/main.ts +199 -0
- package/src/ne2k.ts +1589 -0
- package/src/pci.ts +815 -0
- package/src/pit.ts +406 -0
- package/src/ps2.ts +820 -0
- package/src/rtc.ts +537 -0
- package/src/rust/analysis.rs +101 -0
- package/src/rust/codegen.rs +2660 -0
- package/src/rust/config.rs +3 -0
- package/src/rust/control_flow.rs +425 -0
- package/src/rust/cpu/apic.rs +658 -0
- package/src/rust/cpu/arith.rs +1207 -0
- package/src/rust/cpu/call_indirect.rs +2 -0
- package/src/rust/cpu/cpu.rs +4501 -0
- package/src/rust/cpu/fpu.rs +923 -0
- package/src/rust/cpu/global_pointers.rs +112 -0
- package/src/rust/cpu/instructions.rs +2486 -0
- package/src/rust/cpu/instructions_0f.rs +5261 -0
- package/src/rust/cpu/ioapic.rs +316 -0
- package/src/rust/cpu/memory.rs +351 -0
- package/src/rust/cpu/misc_instr.rs +613 -0
- package/src/rust/cpu/mod.rs +16 -0
- package/src/rust/cpu/modrm.rs +133 -0
- package/src/rust/cpu/pic.rs +402 -0
- package/src/rust/cpu/sse_instr.rs +361 -0
- package/src/rust/cpu/string.rs +701 -0
- package/src/rust/cpu/vga.rs +175 -0
- package/src/rust/cpu_context.rs +69 -0
- package/src/rust/dbg.rs +98 -0
- package/src/rust/gen/analyzer.rs +3807 -0
- package/src/rust/gen/analyzer0f.rs +3992 -0
- package/src/rust/gen/interpreter.rs +4447 -0
- package/src/rust/gen/interpreter0f.rs +5404 -0
- package/src/rust/gen/jit.rs +5080 -0
- package/src/rust/gen/jit0f.rs +5547 -0
- package/src/rust/gen/mod.rs +14 -0
- package/src/rust/jit.rs +2443 -0
- package/src/rust/jit_instructions.rs +7881 -0
- package/src/rust/js_api.rs +6 -0
- package/src/rust/leb.rs +46 -0
- package/src/rust/lib.rs +29 -0
- package/src/rust/modrm.rs +330 -0
- package/src/rust/opstats.rs +249 -0
- package/src/rust/page.rs +15 -0
- package/src/rust/paging.rs +25 -0
- package/src/rust/prefix.rs +15 -0
- package/src/rust/profiler.rs +155 -0
- package/src/rust/regs.rs +38 -0
- package/src/rust/softfloat.rs +286 -0
- package/src/rust/state_flags.rs +27 -0
- package/src/rust/wasmgen/mod.rs +2 -0
- package/src/rust/wasmgen/wasm_builder.rs +1047 -0
- package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
- package/src/rust/zstd.rs +105 -0
- package/src/sb16.ts +1928 -0
- package/src/state.ts +359 -0
- package/src/uart.ts +472 -0
- package/src/vga.ts +2791 -0
- package/src/virtio.ts +1756 -0
- package/src/virtio_balloon.ts +273 -0
- package/src/virtio_console.ts +372 -0
- 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
|
+
}
|