risc5emu-fp.c (4458B)
1 // Copyright © 2014 Peter De Wachter 2 // 3 // Permission to use, copy, modify, and/or distribute this software for 4 // any purpose with or without fee is hereby granted, provided that the 5 // above copyright notice and this permission notice appear in all 6 // copies. 7 // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 9 // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 11 // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 // DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 // PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 // PERFORMANCE OF THIS SOFTWARE. 16 17 // based on src/risc-fp.c from git@github.com:pdewacht/oberon-risc-emu.git 18 19 #include "risc5emu-fp.h" 20 21 uint32_t fp_add(uint32_t x, uint32_t y, bool u, bool v) { 22 bool xs = (x & 0x80000000) != 0; 23 uint32_t xe; 24 int32_t x0; 25 if (!u) { 26 xe = (x >> 23) & 0xFF; 27 uint32_t xm = ((x & 0x7FFFFF) << 1) | 0x1000000; 28 x0 = (int32_t)(xs ? -xm : xm); 29 } else { 30 xe = 150; 31 x0 = (int32_t)(x & 0x00FFFFFF) << 8 >> 7; 32 } 33 34 bool ys = (y & 0x80000000) != 0; 35 uint32_t ye = (y >> 23) & 0xFF; 36 uint32_t ym = ((y & 0x7FFFFF) << 1); 37 if (!u && !v) ym |= 0x1000000; 38 int32_t y0 = (int32_t)(ys ? -ym : ym); 39 40 uint32_t e0; 41 int32_t x3, y3; 42 if (ye > xe) { 43 uint32_t shift = ye - xe; 44 e0 = ye; 45 x3 = shift > 31 ? x0 >> 31 : x0 >> shift; 46 y3 = y0; 47 } else { 48 uint32_t shift = xe - ye; 49 e0 = xe; 50 x3 = x0; 51 y3 = shift > 31 ? y0 >> 31 : y0 >> shift; 52 } 53 54 uint32_t sum = ((xs << 26) | (xs << 25) | (x3 & 0x01FFFFFF)) 55 + ((ys << 26) | (ys << 25) | (y3 & 0x01FFFFFF)); 56 57 uint32_t s = (((sum & (1 << 26)) ? -sum : sum) + 1) & 0x07FFFFFF; 58 59 uint32_t e1 = e0 + 1; 60 uint32_t t3 = s >> 1; 61 if ((s & 0x3FFFFFC) != 0) { 62 while ((t3 & (1<<24)) == 0) { 63 t3 <<= 1; 64 e1--; 65 } 66 } else { 67 t3 <<= 24; 68 e1 -= 24; 69 } 70 71 bool xn = (x & 0x7FFFFFFF) == 0; 72 bool yn = (y & 0x7FFFFFFF) == 0; 73 74 if (v) { 75 return (int32_t)(sum << 5) >> 6; 76 } else if (xn) { 77 return (u | yn) ? 0 : y; 78 } else if (yn) { 79 return x; 80 } else if ((t3 & 0x01FFFFFF) == 0 || (e1 & 0x100) != 0) { 81 return 0; 82 } else { 83 return ((sum & 0x04000000) << 5) | (e1 << 23) | ((t3 >> 1) & 0x7FFFFF); 84 } 85 } 86 87 uint32_t fp_mul(uint32_t x, uint32_t y) { 88 uint32_t sign = (x ^ y) & 0x80000000; 89 uint32_t xe = (x >> 23) & 0xFF; 90 uint32_t ye = (y >> 23) & 0xFF; 91 92 uint32_t xm = (x & 0x7FFFFF) | 0x800000; 93 uint32_t ym = (y & 0x7FFFFF) | 0x800000; 94 uint64_t m = (uint64_t)xm * ym; 95 96 uint32_t e1 = (xe + ye) - 127; 97 uint32_t z0; 98 if ((m & (1ULL << 47)) != 0) { 99 e1++; 100 z0 = ((m >> 23) + 1) & 0xFFFFFF; 101 } else { 102 z0 = ((m >> 22) + 1) & 0xFFFFFF; 103 } 104 105 if (xe == 0 || ye == 0) { 106 return 0; 107 } else if ((e1 & 0x100) == 0) { 108 return sign | ((e1 & 0xFF) << 23) | (z0 >> 1); 109 } else if ((e1 & 0x80) == 0) { 110 return sign | (0xFF << 23) | (z0 >> 1); 111 } else { 112 return 0; 113 } 114 } 115 116 uint32_t fp_div(uint32_t x, uint32_t y) { 117 uint32_t sign = (x ^ y) & 0x80000000; 118 uint32_t xe = (x >> 23) & 0xFF; 119 uint32_t ye = (y >> 23) & 0xFF; 120 121 uint32_t xm = (x & 0x7FFFFF) | 0x800000; 122 uint32_t ym = (y & 0x7FFFFF) | 0x800000; 123 uint32_t q1 = (uint32_t)(xm * (1ULL << 25) / ym); 124 125 uint32_t e1 = (xe - ye) + 126; 126 uint32_t q2; 127 if ((q1 & (1 << 25)) != 0) { 128 e1++; 129 q2 = (q1 >> 1) & 0xFFFFFF; 130 } else { 131 q2 = q1 & 0xFFFFFF; 132 } 133 uint32_t q3 = q2 + 1; 134 135 if (xe == 0) { 136 return 0; 137 } else if (ye == 0) { 138 return sign | (0xFF << 23); 139 } else if ((e1 & 0x100) == 0) { 140 return sign | ((e1 & 0xFF) << 23) | (q3 >> 1); 141 } else if ((e1 & 0x80) == 0) { 142 return sign | (0xFF << 23) | (q2 >> 1); 143 } else { 144 return 0; 145 } 146 } 147 148 struct idiv idiv(uint32_t x, uint32_t y, bool signed_div) { 149 bool sign = ((int32_t)x < 0) & signed_div; 150 uint32_t x0 = sign ? -x : x; 151 152 uint64_t RQ = x0; 153 for (int S = 0; S < 32; ++S) { 154 uint32_t w0 = (uint32_t)(RQ >> 31); 155 uint32_t w1 = w0 - y; 156 if ((int32_t)w1 < 0) { 157 RQ = ((uint64_t)w0 << 32) | ((RQ & 0x7FFFFFFFU) << 1); 158 } else { 159 RQ = ((uint64_t)w1 << 32) | ((RQ & 0x7FFFFFFFU) << 1) | 1; 160 } 161 } 162 163 struct idiv d = { (uint32_t)RQ, (uint32_t)(RQ >> 32) }; 164 if (sign) { 165 d.quot = -d.quot; 166 if (d.rem) { 167 d.quot -= 1; 168 d.rem = y - d.rem; 169 } 170 } 171 return d; 172 }