fpu.rs 24 KB

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