fpu.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. use cpu::cpu::*;
  2. use cpu::global_pointers::*;
  3. use paging::OrPageFault;
  4. use softfloat::{Precision, RoundingMode, F80};
  5. use std::f64;
  6. const FPU_C0: u16 = 0x100;
  7. const FPU_C1: u16 = 0x200;
  8. const FPU_C2: u16 = 0x400;
  9. const FPU_C3: u16 = 0x4000;
  10. const FPU_RESULT_FLAGS: u16 = FPU_C0 | FPU_C1 | FPU_C2 | FPU_C3;
  11. const FPU_EX_I: u16 = 1 << 0; // invalid operation
  12. #[allow(dead_code)]
  13. const FPU_EX_D: u16 = 1 << 1; // denormal operand
  14. const FPU_EX_Z: u16 = 1 << 2; // zero divide
  15. #[allow(dead_code)]
  16. const FPU_EX_O: u16 = 1 << 3; // overflow
  17. const FPU_EX_U: u16 = 1 << 4; // underflow
  18. #[allow(dead_code)]
  19. const FPU_EX_P: u16 = 1 << 5; // precision
  20. const FPU_EX_SF: u16 = 1 << 6;
  21. pub fn fpu_write_st(index: i32, value: F80) {
  22. dbg_assert!(index >= 0 && index < 8);
  23. unsafe {
  24. *fpu_st.offset(index as isize) = value;
  25. }
  26. }
  27. #[no_mangle]
  28. pub unsafe fn fpu_get_st0() -> F80 {
  29. dbg_assert!(*fpu_stack_ptr < 8);
  30. if 0 != *fpu_stack_empty >> *fpu_stack_ptr & 1 {
  31. *fpu_status_word &= !FPU_C1;
  32. fpu_stack_fault();
  33. return F80::INDEFINITE_NAN;
  34. }
  35. else {
  36. return *fpu_st.offset(*fpu_stack_ptr as isize);
  37. };
  38. }
  39. #[no_mangle]
  40. pub unsafe fn fpu_stack_fault() {
  41. // TODO: Interrupt
  42. *fpu_status_word |= FPU_EX_SF | FPU_EX_I;
  43. }
  44. #[no_mangle]
  45. pub unsafe fn fpu_zero_fault() {
  46. // TODO: Interrupt
  47. *fpu_status_word |= FPU_EX_Z;
  48. }
  49. #[no_mangle]
  50. pub unsafe fn fpu_underflow_fault() {
  51. // TODO: Interrupt
  52. *fpu_status_word |= FPU_EX_U;
  53. }
  54. #[no_mangle]
  55. pub unsafe fn fpu_sti_empty(mut i: i32) -> bool {
  56. dbg_assert!(i >= 0 && i < 8);
  57. i = i + *fpu_stack_ptr as i32 & 7;
  58. return 0 != *fpu_stack_empty >> i & 1;
  59. }
  60. #[no_mangle]
  61. pub unsafe fn fpu_get_sti(mut i: i32) -> F80 {
  62. dbg_assert!(i >= 0 && i < 8);
  63. i = i + *fpu_stack_ptr as i32 & 7;
  64. if 0 != *fpu_stack_empty >> i & 1 {
  65. *fpu_status_word &= !FPU_C1;
  66. fpu_stack_fault();
  67. return F80::INDEFINITE_NAN;
  68. }
  69. else {
  70. return *fpu_st.offset(i as isize);
  71. };
  72. }
  73. #[no_mangle]
  74. pub unsafe fn fpu_get_sti_f64(mut i: i32) -> f64 {
  75. i = i + *fpu_stack_ptr as i32 & 7;
  76. std::mem::transmute((*fpu_st.offset(i as isize)).to_f64())
  77. }
  78. #[no_mangle]
  79. pub unsafe fn f32_to_f80(v: i32) -> F80 { F80::of_f32(v) }
  80. #[no_mangle]
  81. pub unsafe fn f64_to_f80(v: u64) -> F80 { F80::of_f64(v) }
  82. #[no_mangle]
  83. pub unsafe fn f80_to_f32(v: F80) -> i32 {
  84. F80::clear_exception_flags();
  85. let x = v.to_f32();
  86. *fpu_status_word |= F80::get_exception_flags() as u16;
  87. x
  88. }
  89. #[no_mangle]
  90. pub unsafe fn f80_to_f64(v: F80) -> u64 {
  91. F80::clear_exception_flags();
  92. let x = v.to_f64();
  93. *fpu_status_word |= F80::get_exception_flags() as u16;
  94. x
  95. }
  96. #[no_mangle]
  97. pub unsafe fn i32_to_f80(v: i32) -> F80 { F80::of_i32(v) }
  98. #[no_mangle]
  99. pub unsafe fn i64_to_f80(v: i64) -> F80 { F80::of_i64(v) }
  100. #[no_mangle]
  101. pub unsafe fn fpu_load_i16(addr: i32) -> OrPageFault<F80> {
  102. let v = safe_read16(addr)? as i16 as i32;
  103. Ok(F80::of_i32(v))
  104. }
  105. #[no_mangle]
  106. pub unsafe fn fpu_load_i32(addr: i32) -> OrPageFault<F80> {
  107. let v = safe_read32s(addr)?;
  108. Ok(F80::of_i32(v))
  109. }
  110. #[no_mangle]
  111. pub unsafe fn fpu_load_i64(addr: i32) -> OrPageFault<F80> {
  112. let v = safe_read64s(addr)? as i64;
  113. Ok(F80::of_i64(v))
  114. }
  115. #[no_mangle]
  116. pub unsafe fn fpu_load_m32(addr: i32) -> OrPageFault<F80> {
  117. let v = safe_read32s(addr)?;
  118. Ok(F80::of_f32(v))
  119. }
  120. #[no_mangle]
  121. pub unsafe fn fpu_load_m64(addr: i32) -> OrPageFault<F80> {
  122. F80::clear_exception_flags();
  123. let v = F80::of_f64(safe_read64s(addr)?);
  124. *fpu_status_word |= F80::get_exception_flags() as u16;
  125. Ok(v)
  126. }
  127. #[no_mangle]
  128. pub unsafe fn fpu_load_m80(addr: i32) -> OrPageFault<F80> {
  129. let mantissa = safe_read64s(addr)?;
  130. let sign_exponent = safe_read16(addr + 8)? as u16;
  131. // TODO: Canonical form
  132. Ok(F80 {
  133. mantissa,
  134. sign_exponent,
  135. })
  136. }
  137. #[no_mangle]
  138. pub unsafe fn fpu_load_status_word() -> u16 {
  139. dbg_assert!(*fpu_stack_ptr < 8);
  140. return *fpu_status_word & !(7 << 11) | (*fpu_stack_ptr as u16) << 11;
  141. }
  142. #[no_mangle]
  143. pub unsafe fn fpu_fadd(target_index: i32, val: F80) {
  144. F80::clear_exception_flags();
  145. let st0 = fpu_get_st0();
  146. fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, st0 + val);
  147. *fpu_status_word |= F80::get_exception_flags() as u16;
  148. }
  149. #[no_mangle]
  150. pub unsafe fn fpu_fclex() { *fpu_status_word = 0; }
  151. #[no_mangle]
  152. pub unsafe fn fpu_fcmovcc(condition: bool, r: i32) {
  153. // outside of the condition is correct: A stack fault happens even if the condition is not
  154. // fulfilled
  155. let x = fpu_get_sti(r);
  156. if fpu_sti_empty(r) {
  157. fpu_write_st(*fpu_stack_ptr as i32, F80::INDEFINITE_NAN)
  158. }
  159. else {
  160. if condition {
  161. fpu_write_st(*fpu_stack_ptr as i32, x);
  162. *fpu_stack_empty &= !(1 << *fpu_stack_ptr)
  163. };
  164. }
  165. }
  166. #[no_mangle]
  167. pub unsafe fn fpu_fcom(y: F80) {
  168. F80::clear_exception_flags();
  169. let x = fpu_get_st0();
  170. *fpu_status_word &= !FPU_RESULT_FLAGS;
  171. match x.partial_cmp(&y) {
  172. Some(std::cmp::Ordering::Greater) => {},
  173. Some(std::cmp::Ordering::Less) => *fpu_status_word |= FPU_C0,
  174. Some(std::cmp::Ordering::Equal) => *fpu_status_word |= FPU_C3,
  175. None => *fpu_status_word |= FPU_C0 | FPU_C2 | FPU_C3,
  176. }
  177. *fpu_status_word |= F80::get_exception_flags() as u16;
  178. }
  179. #[no_mangle]
  180. pub unsafe fn fpu_fcomi(r: i32) {
  181. F80::clear_exception_flags();
  182. let x = fpu_get_st0();
  183. let y = fpu_get_sti(r);
  184. *flags_changed = 0;
  185. *flags &= !FLAGS_ALL;
  186. match x.partial_cmp(&y) {
  187. Some(std::cmp::Ordering::Greater) => {},
  188. Some(std::cmp::Ordering::Less) => *flags |= 1,
  189. Some(std::cmp::Ordering::Equal) => *flags |= FLAG_ZERO,
  190. None => *flags |= 1 | FLAG_PARITY | FLAG_ZERO,
  191. }
  192. *fpu_status_word |= F80::get_exception_flags() as u16;
  193. }
  194. #[no_mangle]
  195. pub unsafe fn fpu_fcomip(r: i32) {
  196. fpu_fcomi(r);
  197. fpu_pop();
  198. }
  199. #[no_mangle]
  200. pub unsafe fn fpu_pop() {
  201. dbg_assert!(*fpu_stack_ptr < 8);
  202. *fpu_stack_empty |= 1 << *fpu_stack_ptr;
  203. *fpu_stack_ptr = *fpu_stack_ptr + 1 & 7;
  204. }
  205. #[no_mangle]
  206. pub unsafe fn fpu_fcomp(val: F80) {
  207. fpu_fcom(val);
  208. fpu_pop();
  209. }
  210. #[no_mangle]
  211. pub unsafe fn fpu_fdiv(target_index: i32, val: F80) {
  212. F80::clear_exception_flags();
  213. let st0 = fpu_get_st0();
  214. fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, st0 / val);
  215. *fpu_status_word |= F80::get_exception_flags() as u16;
  216. }
  217. #[no_mangle]
  218. pub unsafe fn fpu_fdivr(target_index: i32, val: F80) {
  219. F80::clear_exception_flags();
  220. let st0 = fpu_get_st0();
  221. fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, val / st0);
  222. *fpu_status_word |= F80::get_exception_flags() as u16;
  223. }
  224. #[no_mangle]
  225. pub unsafe fn fpu_ffree(r: i32) { *fpu_stack_empty |= 1 << (*fpu_stack_ptr as i32 + r & 7); }
  226. #[no_mangle]
  227. pub unsafe fn fpu_fildm16(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_i16(addr))); }
  228. #[no_mangle]
  229. pub unsafe fn fpu_fildm32(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_i32(addr))); }
  230. #[no_mangle]
  231. pub unsafe fn fpu_fildm64(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_i64(addr))); }
  232. #[no_mangle]
  233. pub unsafe fn fpu_push(x: F80) {
  234. *fpu_stack_ptr = *fpu_stack_ptr - 1 & 7;
  235. if 0 != *fpu_stack_empty >> *fpu_stack_ptr & 1 {
  236. *fpu_status_word &= !FPU_C1;
  237. *fpu_stack_empty &= !(1 << *fpu_stack_ptr);
  238. fpu_write_st(*fpu_stack_ptr as i32, x);
  239. }
  240. else {
  241. *fpu_status_word |= FPU_C1;
  242. fpu_stack_fault();
  243. fpu_write_st(*fpu_stack_ptr as i32, F80::INDEFINITE_NAN);
  244. };
  245. }
  246. #[no_mangle]
  247. pub unsafe fn fpu_finit() {
  248. set_control_word(0x37F);
  249. *fpu_status_word = 0;
  250. *fpu_ip = 0;
  251. *fpu_dp = 0;
  252. *fpu_opcode = 0;
  253. *fpu_stack_empty = 0xFF;
  254. *fpu_stack_ptr = 0;
  255. }
  256. #[no_mangle]
  257. pub unsafe fn set_control_word(cw: u16) {
  258. *fpu_control_word = cw;
  259. let rc = cw >> 10 & 3;
  260. F80::set_rounding_mode(match rc {
  261. 0 => RoundingMode::NearEven,
  262. 1 => RoundingMode::Floor,
  263. 2 => RoundingMode::Ceil,
  264. 3 => RoundingMode::Trunc,
  265. _ => {
  266. dbg_assert!(false);
  267. RoundingMode::NearEven
  268. },
  269. });
  270. let precision_control = cw >> 8 & 3;
  271. F80::set_precision(match precision_control {
  272. 0 => Precision::P32,
  273. 1 => Precision::P80, // undefined
  274. 2 => Precision::P64,
  275. 3 => Precision::P80,
  276. _ => {
  277. dbg_assert!(false);
  278. Precision::P80
  279. },
  280. });
  281. }
  282. #[no_mangle]
  283. pub unsafe fn fpu_invalid_arithmetic() { *fpu_status_word |= FPU_EX_I; }
  284. #[no_mangle]
  285. pub unsafe fn fpu_convert_to_i16(f: F80) -> i16 {
  286. let st0 = fpu_convert_to_i32(f);
  287. if st0 < -0x8000 || st0 > 0x7FFF {
  288. fpu_invalid_arithmetic();
  289. -0x8000
  290. }
  291. else {
  292. st0 as i16
  293. }
  294. }
  295. #[no_mangle]
  296. pub unsafe fn fpu_fistm16(addr: i32) {
  297. return_on_pagefault!(writable_or_pagefault(addr, 2));
  298. let v = fpu_convert_to_i16(fpu_get_st0());
  299. safe_write16(addr, v as i32).unwrap();
  300. }
  301. #[no_mangle]
  302. pub unsafe fn fpu_fistm16p(addr: i32) {
  303. return_on_pagefault!(writable_or_pagefault(addr, 2));
  304. let v = fpu_convert_to_i16(fpu_get_st0());
  305. safe_write16(addr, v as i32).unwrap();
  306. fpu_pop();
  307. }
  308. #[no_mangle]
  309. pub unsafe fn fpu_convert_to_i32(f: F80) -> i32 {
  310. F80::clear_exception_flags();
  311. let x = f.to_i32();
  312. *fpu_status_word |= F80::get_exception_flags() as u16;
  313. x
  314. }
  315. #[no_mangle]
  316. pub unsafe fn fpu_fistm32(addr: i32) {
  317. return_on_pagefault!(writable_or_pagefault(addr, 4));
  318. let v = fpu_convert_to_i32(fpu_get_st0());
  319. safe_write32(addr, v).unwrap();
  320. }
  321. #[no_mangle]
  322. pub unsafe fn fpu_fistm32p(addr: i32) {
  323. return_on_pagefault!(writable_or_pagefault(addr, 4));
  324. let v = fpu_convert_to_i32(fpu_get_st0());
  325. safe_write32(addr, v).unwrap();
  326. fpu_pop();
  327. }
  328. #[no_mangle]
  329. pub unsafe fn fpu_convert_to_i64(f: F80) -> i64 {
  330. F80::clear_exception_flags();
  331. let x = f.to_i64();
  332. *fpu_status_word |= F80::get_exception_flags() as u16;
  333. x
  334. }
  335. #[no_mangle]
  336. pub unsafe fn fpu_fistm64p(addr: i32) {
  337. return_on_pagefault!(writable_or_pagefault(addr, 8));
  338. let v = fpu_convert_to_i64(fpu_get_st0());
  339. safe_write64(addr, v as u64).unwrap();
  340. fpu_pop();
  341. }
  342. #[no_mangle]
  343. pub unsafe fn fpu_fldcw(addr: i32) {
  344. let word = return_on_pagefault!(safe_read16(addr)) as u16;
  345. set_control_word(word);
  346. }
  347. #[no_mangle]
  348. pub unsafe fn fpu_fldenv16(_addr: i32) {
  349. dbg_log!("fldenv16");
  350. fpu_unimpl();
  351. }
  352. #[no_mangle]
  353. pub unsafe fn fpu_fldenv32(addr: i32) {
  354. if let Err(()) = readable_or_pagefault(addr, 28) {
  355. *page_fault = true;
  356. return;
  357. }
  358. *page_fault = false;
  359. set_control_word(safe_read16(addr).unwrap() as u16);
  360. fpu_set_status_word(safe_read16(addr + 4).unwrap() as u16);
  361. fpu_set_tag_word(safe_read16(addr + 8).unwrap());
  362. *fpu_ip = safe_read32s(addr + 12).unwrap();
  363. *fpu_ip_selector = safe_read16(addr + 16).unwrap();
  364. *fpu_opcode = safe_read16(addr + 18).unwrap();
  365. *fpu_dp = safe_read32s(addr + 20).unwrap();
  366. *fpu_dp_selector = safe_read16(addr + 24).unwrap()
  367. }
  368. #[no_mangle]
  369. pub unsafe fn fpu_unimpl() {
  370. dbg_assert!(false);
  371. trigger_ud();
  372. }
  373. #[no_mangle]
  374. pub unsafe fn fpu_set_tag_word(tag_word: i32) {
  375. *fpu_stack_empty = 0;
  376. for i in 0..8 {
  377. let empty = tag_word >> (2 * i) & 3 == 3;
  378. *fpu_stack_empty |= (empty as u8) << i;
  379. }
  380. }
  381. #[no_mangle]
  382. pub unsafe fn fpu_set_status_word(sw: u16) {
  383. *fpu_status_word = sw & !(7 << 11);
  384. *fpu_stack_ptr = (sw >> 11 & 7) as u8;
  385. }
  386. #[no_mangle]
  387. pub unsafe fn fpu_fldm32(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_m32(addr))); }
  388. #[no_mangle]
  389. pub unsafe fn fpu_fldm64(addr: i32) { fpu_push(return_on_pagefault!(fpu_load_m64(addr))); }
  390. #[no_mangle]
  391. pub unsafe fn fpu_fldm80(addr: i32) {
  392. match fpu_load_m80(addr) {
  393. Ok(x) => {
  394. *page_fault = false;
  395. fpu_push(x)
  396. },
  397. Err(()) => {
  398. *page_fault = true;
  399. },
  400. }
  401. }
  402. #[no_mangle]
  403. pub unsafe fn fpu_fmul(target_index: i32, val: F80) {
  404. let st0 = fpu_get_st0();
  405. fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, st0 * val);
  406. }
  407. #[no_mangle]
  408. pub unsafe fn fpu_fnstsw_mem(addr: i32) {
  409. return_on_pagefault!(safe_write16(addr, fpu_load_status_word().into()));
  410. }
  411. #[no_mangle]
  412. pub unsafe fn fpu_fnstsw_reg() { write_reg16(AX, fpu_load_status_word().into()); }
  413. #[no_mangle]
  414. pub unsafe fn fpu_fprem(ieee: bool) {
  415. // false: Faster, fails nasmtests
  416. // true: Slower, fails qemutests
  417. let intel_compatibility = false;
  418. let st0 = fpu_get_st0();
  419. let st1 = fpu_get_sti(1);
  420. if st1 == F80::ZERO {
  421. if st0 == F80::ZERO {
  422. fpu_invalid_arithmetic();
  423. }
  424. else {
  425. fpu_zero_fault();
  426. }
  427. fpu_write_st(*fpu_stack_ptr as i32, F80::INDEFINITE_NAN);
  428. return;
  429. }
  430. let exp0 = st0.log2();
  431. let exp1 = st1.log2();
  432. let d = (exp0 - exp1).abs();
  433. if !intel_compatibility || d < F80::of_f64(std::mem::transmute(64.0)) {
  434. let fprem_quotient =
  435. (if ieee { (st0 / st1).round() } else { (st0 / st1).trunc() }).to_i32();
  436. fpu_write_st(*fpu_stack_ptr as i32, st0 % st1);
  437. *fpu_status_word &= !(FPU_C0 | FPU_C1 | FPU_C3);
  438. if 0 != fprem_quotient & 1 {
  439. *fpu_status_word |= FPU_C1
  440. }
  441. if 0 != fprem_quotient & 1 << 1 {
  442. *fpu_status_word |= FPU_C3
  443. }
  444. if 0 != fprem_quotient & 1 << 2 {
  445. *fpu_status_word |= FPU_C0
  446. }
  447. *fpu_status_word &= !FPU_C2;
  448. }
  449. else {
  450. let n = F80::of_f64(std::mem::transmute(32.0));
  451. let fprem_quotient =
  452. (if ieee { (st0 / st1).round() } else { (st0 / st1).trunc() } / (d - n).two_pow());
  453. fpu_write_st(
  454. *fpu_stack_ptr as i32,
  455. st0 - st1 * fprem_quotient * (d - n).two_pow(),
  456. );
  457. *fpu_status_word |= FPU_C2;
  458. }
  459. }
  460. #[no_mangle]
  461. pub unsafe fn fpu_frstor16(_addr: i32) {
  462. dbg_log!("frstor16");
  463. fpu_unimpl();
  464. }
  465. #[no_mangle]
  466. pub unsafe fn fpu_frstor32(mut addr: i32) {
  467. return_on_pagefault!(readable_or_pagefault(addr, 28 + 8 * 10));
  468. fpu_fldenv32(addr);
  469. addr += 28;
  470. for i in 0..8 {
  471. let reg_index = *fpu_stack_ptr as i32 + i & 7;
  472. *fpu_st.offset(reg_index as isize) = fpu_load_m80(addr).unwrap();
  473. addr += 10;
  474. }
  475. }
  476. #[no_mangle]
  477. pub unsafe fn fpu_fsave16(_addr: i32) {
  478. dbg_log!("fsave16");
  479. fpu_unimpl();
  480. }
  481. #[no_mangle]
  482. pub unsafe fn fpu_fsave32(mut addr: i32) {
  483. return_on_pagefault!(writable_or_pagefault(addr, 108));
  484. fpu_fstenv32(addr);
  485. addr += 28;
  486. for i in 0..8 {
  487. let reg_index = i + *fpu_stack_ptr as i32 & 7;
  488. fpu_store_m80(addr, *fpu_st.offset(reg_index as isize));
  489. addr += 10;
  490. }
  491. fpu_finit();
  492. }
  493. #[no_mangle]
  494. pub unsafe fn fpu_store_m80(addr: i32, f: F80) {
  495. // writable_or_pagefault must have checked called by the caller!
  496. safe_write64(addr, f.mantissa).unwrap();
  497. safe_write16(addr + 8, f.sign_exponent as i32).unwrap();
  498. }
  499. #[no_mangle]
  500. pub unsafe fn fpu_fstenv16(_addr: i32) {
  501. dbg_log!("fstenv16");
  502. fpu_unimpl();
  503. }
  504. #[no_mangle]
  505. pub unsafe fn fpu_fstenv32(addr: i32) {
  506. match writable_or_pagefault(addr, 26) {
  507. Ok(()) => *page_fault = false,
  508. Err(()) => {
  509. *page_fault = true;
  510. return;
  511. },
  512. }
  513. safe_write16(addr, (*fpu_control_word).into()).unwrap();
  514. safe_write16(addr + 4, fpu_load_status_word().into()).unwrap();
  515. safe_write16(addr + 8, fpu_load_tag_word()).unwrap();
  516. safe_write32(addr + 12, *fpu_ip).unwrap();
  517. safe_write16(addr + 16, *fpu_ip_selector).unwrap();
  518. safe_write16(addr + 18, *fpu_opcode).unwrap();
  519. safe_write32(addr + 20, *fpu_dp).unwrap();
  520. safe_write16(addr + 24, *fpu_dp_selector).unwrap();
  521. }
  522. #[no_mangle]
  523. pub unsafe fn fpu_load_tag_word() -> i32 {
  524. let mut tag_word: i32 = 0;
  525. for i in 0..8 {
  526. let value = *fpu_st.offset(i as isize);
  527. if 0 != *fpu_stack_empty >> i & 1 {
  528. tag_word |= 3 << (i << 1)
  529. }
  530. else if value == F80::ZERO {
  531. tag_word |= 1 << (i << 1)
  532. }
  533. else if !value.is_finite() {
  534. tag_word |= 2 << (i << 1)
  535. }
  536. }
  537. return tag_word;
  538. }
  539. #[no_mangle]
  540. pub unsafe fn fpu_fst(r: i32) { fpu_write_st(*fpu_stack_ptr as i32 + r & 7, fpu_get_st0()); }
  541. #[no_mangle]
  542. pub unsafe fn fpu_fst80p(addr: i32) {
  543. return_on_pagefault!(writable_or_pagefault(addr, 10));
  544. fpu_store_m80(addr, fpu_get_st0());
  545. fpu_pop();
  546. }
  547. #[no_mangle]
  548. pub unsafe fn fpu_fstcw(addr: i32) {
  549. return_on_pagefault!(safe_write16(addr, (*fpu_control_word).into()));
  550. }
  551. #[no_mangle]
  552. pub unsafe fn fpu_fstm32(addr: i32) {
  553. return_on_pagefault!(fpu_store_m32(addr, fpu_get_st0()));
  554. }
  555. #[no_mangle]
  556. pub unsafe fn fpu_store_m32(addr: i32, x: F80) -> OrPageFault<()> {
  557. F80::clear_exception_flags();
  558. safe_write32(addr, x.to_f32())?;
  559. *fpu_status_word |= F80::get_exception_flags() as u16;
  560. Ok(())
  561. }
  562. #[no_mangle]
  563. pub unsafe fn fpu_fstm32p(addr: i32) {
  564. return_on_pagefault!(fpu_store_m32(addr, fpu_get_st0()));
  565. fpu_pop();
  566. }
  567. #[no_mangle]
  568. pub unsafe fn fpu_fstm64(addr: i32) {
  569. return_on_pagefault!(fpu_store_m64(addr, fpu_get_st0()));
  570. }
  571. #[no_mangle]
  572. pub unsafe fn fpu_store_m64(addr: i32, x: F80) -> OrPageFault<()> { safe_write64(addr, x.to_f64()) }
  573. #[no_mangle]
  574. pub unsafe fn fpu_fstm64p(addr: i32) {
  575. // XXX: writable_or_pagefault before get_st0
  576. return_on_pagefault!(fpu_store_m64(addr, fpu_get_st0()));
  577. fpu_pop();
  578. }
  579. #[no_mangle]
  580. pub unsafe fn fpu_fstp(r: i32) {
  581. fpu_fst(r);
  582. fpu_pop();
  583. }
  584. #[no_mangle]
  585. pub unsafe fn fpu_fsub(target_index: i32, val: F80) {
  586. let st0 = fpu_get_st0();
  587. fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, st0 - val)
  588. }
  589. #[no_mangle]
  590. pub unsafe fn fpu_fsubr(target_index: i32, val: F80) {
  591. let st0 = fpu_get_st0();
  592. fpu_write_st(*fpu_stack_ptr as i32 + target_index & 7, val - st0)
  593. }
  594. #[no_mangle]
  595. pub unsafe fn fpu_ftst() {
  596. let x = fpu_get_st0();
  597. *fpu_status_word &= !FPU_RESULT_FLAGS;
  598. if x.is_nan() {
  599. *fpu_status_word |= FPU_C3 | FPU_C2 | FPU_C0
  600. }
  601. else if x == F80::ZERO {
  602. *fpu_status_word |= FPU_C3
  603. }
  604. else if x < F80::ZERO {
  605. *fpu_status_word |= FPU_C0
  606. }
  607. // TODO: unordered (x is nan, etc)
  608. }
  609. #[no_mangle]
  610. pub unsafe fn fpu_fucom(r: i32) {
  611. F80::clear_exception_flags();
  612. let x = fpu_get_st0();
  613. let y = fpu_get_sti(r);
  614. *fpu_status_word &= !FPU_RESULT_FLAGS;
  615. match x.partial_cmp_quiet(&y) {
  616. Some(std::cmp::Ordering::Greater) => {},
  617. Some(std::cmp::Ordering::Less) => *fpu_status_word |= FPU_C0,
  618. Some(std::cmp::Ordering::Equal) => *fpu_status_word |= FPU_C3,
  619. None => *fpu_status_word |= FPU_C0 | FPU_C2 | FPU_C3,
  620. }
  621. *fpu_status_word |= F80::get_exception_flags() as u16;
  622. }
  623. #[no_mangle]
  624. pub unsafe fn fpu_fucomi(r: i32) {
  625. F80::clear_exception_flags();
  626. let x = fpu_get_st0();
  627. let y = fpu_get_sti(r);
  628. *flags_changed = 0;
  629. *flags &= !FLAGS_ALL;
  630. match x.partial_cmp_quiet(&y) {
  631. Some(std::cmp::Ordering::Greater) => {},
  632. Some(std::cmp::Ordering::Less) => *flags |= 1,
  633. Some(std::cmp::Ordering::Equal) => *flags |= FLAG_ZERO,
  634. None => *flags |= 1 | FLAG_PARITY | FLAG_ZERO,
  635. }
  636. *fpu_status_word |= F80::get_exception_flags() as u16;
  637. }
  638. #[no_mangle]
  639. pub unsafe fn fpu_fucomip(r: i32) {
  640. fpu_fucomi(r);
  641. fpu_pop();
  642. }
  643. #[no_mangle]
  644. pub unsafe fn fpu_fucomp(r: i32) {
  645. fpu_fucom(r);
  646. fpu_pop();
  647. }
  648. #[no_mangle]
  649. pub unsafe fn fpu_fucompp() {
  650. fpu_fucom(1);
  651. fpu_pop();
  652. fpu_pop();
  653. }
  654. #[no_mangle]
  655. pub unsafe fn fpu_fxam() {
  656. let x = fpu_get_st0();
  657. *fpu_status_word &= !FPU_RESULT_FLAGS;
  658. *fpu_status_word |= (x.sign() as u16) << 9;
  659. if 0 != *fpu_stack_empty >> *fpu_stack_ptr & 1 {
  660. *fpu_status_word |= FPU_C3 | FPU_C0
  661. }
  662. else if x.is_nan() {
  663. *fpu_status_word |= FPU_C0
  664. }
  665. else if x == F80::ZERO {
  666. *fpu_status_word |= FPU_C3
  667. }
  668. else if !x.is_finite() {
  669. *fpu_status_word |= FPU_C2 | FPU_C0
  670. }
  671. else {
  672. *fpu_status_word |= FPU_C2
  673. }
  674. // TODO:
  675. // Unsupported, Denormal
  676. }
  677. #[no_mangle]
  678. pub unsafe fn fpu_fxch(i: i32) {
  679. let sti = fpu_get_sti(i);
  680. fpu_write_st(*fpu_stack_ptr as i32 + i & 7, fpu_get_st0());
  681. fpu_write_st(*fpu_stack_ptr as i32, sti);
  682. }
  683. pub unsafe fn fpu_fyl2x() {
  684. let st0 = fpu_get_st0();
  685. if st0 < F80::ZERO {
  686. fpu_invalid_arithmetic();
  687. }
  688. else if st0 == F80::ZERO {
  689. fpu_zero_fault();
  690. }
  691. fpu_write_st(
  692. *fpu_stack_ptr as i32 + 1 & 7,
  693. fpu_get_sti(1) * st0.ln() / F80::LN_2,
  694. );
  695. fpu_pop();
  696. }
  697. #[no_mangle]
  698. pub unsafe fn fpu_fxtract() {
  699. let st0 = fpu_get_st0();
  700. if st0 == F80::ZERO {
  701. fpu_zero_fault();
  702. fpu_write_st(*fpu_stack_ptr as i32, F80::NEG_INFINITY);
  703. fpu_push(st0);
  704. }
  705. else {
  706. let exp = st0.exponent();
  707. fpu_write_st(*fpu_stack_ptr as i32, F80::of_i32(exp.into()));
  708. fpu_push(F80 {
  709. sign_exponent: 0x3FFF,
  710. mantissa: st0.mantissa,
  711. });
  712. }
  713. }
  714. #[no_mangle]
  715. pub unsafe fn fwait() {
  716. // NOP unless FPU instructions run in parallel with CPU instructions
  717. }
  718. pub unsafe fn fpu_fchs() {
  719. let st0 = fpu_get_st0();
  720. fpu_write_st(*fpu_stack_ptr as i32, -st0);
  721. }
  722. pub unsafe fn fpu_fabs() {
  723. let st0 = fpu_get_st0();
  724. fpu_write_st(*fpu_stack_ptr as i32, st0.abs());
  725. }
  726. pub unsafe fn fpu_f2xm1() {
  727. let st0 = fpu_get_st0();
  728. let r = st0.two_pow() - F80::ONE;
  729. fpu_write_st(*fpu_stack_ptr as i32, r)
  730. }
  731. pub unsafe fn fpu_fptan() {
  732. let st0 = fpu_get_st0();
  733. //if -pow(2.0, 63.0) < st0 && st0 < pow(2.0, 63.0) {
  734. fpu_write_st(*fpu_stack_ptr as i32, st0.tan());
  735. // no bug: push constant 1
  736. fpu_push(F80::ONE);
  737. *fpu_status_word &= !FPU_C2;
  738. //}
  739. //else {
  740. // *fpu_status_word |= FPU_C2;
  741. //}
  742. }
  743. pub unsafe fn fpu_fpatan() {
  744. let st0 = fpu_get_st0();
  745. let st1 = fpu_get_sti(1);
  746. fpu_write_st(*fpu_stack_ptr as i32 + 1 & 7, st1.atan2(st0));
  747. fpu_pop();
  748. }
  749. pub unsafe fn fpu_fyl2xp1() {
  750. // fyl2xp1: y * log2(x+1) and pop
  751. let st0 = fpu_get_st0();
  752. let st1 = fpu_get_sti(1);
  753. let y = st1 * (st0 + F80::ONE).ln() / F80::LN_2;
  754. fpu_write_st(*fpu_stack_ptr as i32 + 1 & 7, y);
  755. fpu_pop();
  756. }
  757. pub unsafe fn fpu_fsqrt() {
  758. let st0 = fpu_get_st0();
  759. //if st0 < 0.0 {
  760. // fpu_invalid_arithmetic();
  761. //}
  762. fpu_write_st(*fpu_stack_ptr as i32, st0.sqrt())
  763. }
  764. pub unsafe fn fpu_fsincos() {
  765. let st0 = fpu_get_st0();
  766. //if pow(-2.0, 63.0) < st0 && st0 < pow(2.0, 63.0) {
  767. fpu_write_st(*fpu_stack_ptr as i32, st0.sin());
  768. fpu_push(st0.cos());
  769. *fpu_status_word &= !FPU_C2;
  770. //}
  771. //else {
  772. // *fpu_status_word |= FPU_C2;
  773. //}
  774. }
  775. pub unsafe fn fpu_frndint() {
  776. let st0 = fpu_get_st0();
  777. fpu_write_st(*fpu_stack_ptr as i32, st0.round());
  778. }
  779. pub unsafe fn fpu_fscale() {
  780. let st0 = fpu_get_st0();
  781. let y = st0 * fpu_get_sti(1).trunc().two_pow();
  782. fpu_write_st(*fpu_stack_ptr as i32, y);
  783. }
  784. pub unsafe fn fpu_fsin() {
  785. let st0 = fpu_get_st0();
  786. //if pow(-2.0, 63.0) < st0 && st0 < pow(2.0, 63.0) {
  787. fpu_write_st(*fpu_stack_ptr as i32, st0.sin());
  788. *fpu_status_word &= !FPU_C2;
  789. //}
  790. //else {
  791. // *fpu_status_word |= FPU_C2;
  792. //}
  793. }
  794. pub unsafe fn fpu_fcos() {
  795. let st0 = fpu_get_st0();
  796. //if pow(-2.0, 63.0) < st0 && st0 < pow(2.0, 63.0) {
  797. fpu_write_st(*fpu_stack_ptr as i32, st0.cos());
  798. *fpu_status_word &= !FPU_C2;
  799. //}
  800. //else {
  801. // *fpu_status_word |= FPU_C2;
  802. //}
  803. }
  804. pub unsafe fn fpu_fdecstp() {
  805. *fpu_stack_ptr = *fpu_stack_ptr - 1 & 7;
  806. *fpu_status_word &= !FPU_C1
  807. }
  808. pub unsafe fn fpu_fincstp() {
  809. *fpu_stack_ptr = *fpu_stack_ptr + 1 & 7;
  810. *fpu_status_word &= !FPU_C1
  811. }