Skip to content

Commit d2133ee

Browse files
authored
Merge pull request #4 from mezantrop/dev
* FPU-emulation executes correctly * All the original functions re-implemented ## Issues * `fyl2x` seems to work properly on FPU, but when executed from `libc`, `log` functions bring incorrect results * Some operations have hard-to-detect issues with precision
2 parents c65422d + 051c999 commit d2133ee

File tree

11 files changed

+346
-130
lines changed

11 files changed

+346
-130
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# FPU Emulation Revival for i486SX on NetBSD
22

3+
<img src="media/i486sx_fpu_emulation.jpg" width="200" align="right" alt="NetBSD 10.x with FPU_emulation on i486sx" />
4+
35
This retro-computing project restores support for x87 floating-point unit (FPU) emulation in the NetBSD kernel,
46
targeting legacy 486SX-class processors without hardware FPUs. It brings back the original `MATH_EMULATE` option into
57
NetBSD 10.x and beyond, as well as reverts and reworks the changes introduced in
@@ -11,6 +13,11 @@ emulation support from the kernel.
1113
This project is a work in progress and may contain bugs or incomplete functionality. Use at your own risk.
1214
The author is not responsible for any issues caused by its use.
1315

16+
### Notes
17+
18+
- `fyl2x` seems to work properly on FPU, but when executed from `libc`, `log` functions bring incorrect results
19+
- Some operations have hard-to-detect issues with precision
20+
1421
## x87 FPU Emulated Instructions
1522

1623
### 🧠 Control & Initialization
@@ -73,7 +80,7 @@ The author is not responsible for any issues caused by its use.
7380
| `fyl2x` | ⏳ TBD | Compute y × log₂(x) (ST(1) × log₂(ST(0))) and pop | `D9 F1` | `fyl2x` |
7481
| `fyl2xp1` | ❌ N/A | Compute y × log₂(x+1) and pop | `D9 F9` | `fyl2xp1` |
7582
| `fxtract` | ❌ N/A | Extract: ST(0) → ST = significand, ST+1 = exponent | `D9 F4` | `fxtract` |
76-
| `f2xm1` | ❌ N/A | Compute 2^x - 1 for ST(0) | `D9 F0` | `f2xm1` |
83+
| `f2xm1` | ✅ OK | Compute 2^x - 1 for ST(0) | `D9 F0` | `f2xm1` |
7784
| `fpatan` | ❌ N/A | Compute arctangent(ST(1)/ST(0)) and pop | `D9 F3` | `fpatan` |
7885
| `fsqrt` | ❌ N/A | Compute square root of ST(0) | `D9 FA` | `fsqrt` |
7986

media/i486sx_fpu_emulation.jpg

3.07 MB
Loading

src/sys/arch/i386/i386/math_emu.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@ typedef struct {
2828
u_short exponent;
2929
} temp_real_unaligned;
3030

31-
/* #define real_to_real(a,b) \
32-
((*(long long *)(void *) (b) = *(long long *)(void *) (a)),((b)->exponent = (a)->exponent)) */
33-
/* XXX: TEST ME!!! */
34-
#define real_to_real(a, b) memcpy((b), (a), sizeof(temp_real))
31+
#define real_to_real(a,b) \
32+
((*(long long *)(void *) (b) = *(long long *)(void *) (a)),((b)->exponent = (a)->exponent))
3533

3634
typedef struct {
3735
long a,b;
@@ -174,8 +172,10 @@ void fucom(const temp_real *, const temp_real *);
174172
void ftst(const temp_real *);
175173

176174
/* Logartithm functions */
175+
void f2xm1(const temp_real *x, temp_real *result);
177176
void fyl2x(const temp_real *a, const temp_real *b, temp_real *c);
178177
void flog2(const temp_real *a, temp_real *result);
179178
void fexp(const temp_real *x, temp_real *result);
179+
void f2exp(const temp_real *x, temp_real *result);
180180
void fln(const temp_real *x, temp_real *result);
181181
#endif

src/sys/arch/i386/i386/math_emulate.c

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,13 @@ math_emulate(struct trapframe *info, ksiginfo_t *ksi) {
233233
fpush();
234234
ST(0) = CONSTZ;
235235
return(0);
236+
case 0x1f0: /* f2xm1 */
237+
f2xm1(PST(0), &tmp);
238+
real_to_real(&tmp, &ST(0));
239+
return(0);
236240
case 0x1f1: /* fyl2x */
237-
fyl2x(PST(0),PST(1),&tmp);
238-
real_to_real(&tmp,&ST(0));
241+
fyl2x(PST(0), PST(1), &tmp);
242+
real_to_real(&tmp, &ST(0));
239243
fpop();
240244
return(0);
241245
case 0x1fc: /* frndint */
@@ -273,10 +277,18 @@ math_emulate(struct trapframe *info, ksiginfo_t *ksi) {
273277
case 0x1e2: case 0x1e3: case 0x1e5:
274278
case 0x1e6: case 0x1e7:
275279
case 0x1ef:
276-
case 0x1f0: /* case 0x1f1: */ case 0x1f2: case 0x1f3:
277-
case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
278-
case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
279-
case 0x1fe: case 0x1ff:
280+
case 0x1f2: /* fptan */
281+
case 0x1f3: /* fpatan */
282+
case 0x1f4: /* fxtract */
283+
case 0x1f5: /* fprem1 */
284+
case 0x1f6: /* fdecstp */
285+
case 0x1f7: /* fincstp */
286+
case 0x1f8: /* fprem */
287+
case 0x1f9: /* fyl2xp1 */
288+
case 0x1fa: /* fsqrt */
289+
case 0x1fb: /* fsincos */
290+
case 0x1fe: /* fsin */
291+
case 0x1ff: /* fcos */
280292
uprintf("math_emulate: 0x%04x not implemented\n", code + 0xd800);
281293
math_abort(info, ksi, SIGILL, ILL_ILLOPC);
282294
}
@@ -1626,7 +1638,6 @@ void temp_to_short(const temp_real * a, short_real * b)
16261638
/* printf("DEBUG: temp_to_short() result: 0x%08lX\n", *b); */
16271639
}
16281640

1629-
16301641
void temp_to_long(const temp_real * a, long_real * b)
16311642
{
16321643
/* printf("DEBUG: temp_to_long() input: exponent=0x%04X, significand=0x%08lX %08lX\n",
@@ -1869,6 +1880,15 @@ void int_to_real(const temp_int * a, temp_real * b)
18691880

18701881
/* logarithm functions */
18711882

1883+
void f2xm1(const temp_real *x, temp_real *result)
1884+
{
1885+
temp_real exp2_x, one;
1886+
1887+
f2exp(x, &exp2_x); /* exp2_x = 2^x */
1888+
real_to_real(&CONST1, &one); /* one = 1.0 */
1889+
fsub(&exp2_x, &one, result); /* result = 2^x - 1 */
1890+
}
1891+
18721892
void fyl2x(const temp_real *a, const temp_real *b, temp_real *c)
18731893
{
18741894
temp_real log2_a;
@@ -1880,30 +1900,49 @@ void fyl2x(const temp_real *a, const temp_real *b, temp_real *c)
18801900
void flog2(const temp_real *a, temp_real *result) {
18811901
temp_real ln_a, ln2;
18821902

1883-
fln(a, &ln_a); // ln(x)
1884-
long_to_temp((const long_real *)&CONSTLN2, &ln2);
1903+
fln(a, &ln_a); /* ln(x) */
1904+
real_to_real(&CONSTLN2, &ln2);
18851905
fdiv(&ln_a, &ln2, result);
18861906
}
18871907

18881908
#define MAX_ITER 50
1889-
void fexp(const temp_real *x, temp_real *result) {
1890-
temp_real term, sum, factor;
1909+
void fexp(const temp_real *x, temp_real *result)
1910+
{
1911+
temp_real term, sum;
18911912
int i;
1913+
temp_int ti;
1914+
temp_real real_i;
1915+
temp_real x_copy = *x;
18921916

1893-
factor = *x; // x^1
1894-
long_to_temp((const long_real *)&CONST1, &sum);
1895-
term = factor;
1917+
real_to_real(&CONST1, &sum); /* sum = 1 */
1918+
real_to_real(&x_copy, &term); /* term = x */
18961919

1897-
for (i = 2; i < MAX_ITER; i++) {
1898-
fmul(&term, &factor, &term); // term = x^i / i!
1899-
fdiv(&term, (const temp_real *)&i, &term); // div i!
1920+
fadd(&sum, &term, &sum); /* sum += x */
19001921

1901-
fadd(&sum, &term, &sum);
1922+
for (i = 2; i < MAX_ITER; i++)
1923+
{
1924+
ti.a = (signed short)i;
1925+
ti.b = 0;
1926+
ti.sign = 0;
1927+
int_to_real(&ti, &real_i);
1928+
1929+
fmul(&term, &x_copy, &term); /* term = term * x */
1930+
fdiv(&term, &real_i, &term); /* term = term / i */
1931+
fadd(&sum, &term, &sum); /* sum += term */
19021932
}
19031933

19041934
*result = sum;
19051935
}
19061936

1937+
void f2exp(const temp_real *x, temp_real *result)
1938+
{
1939+
temp_real ln2, scaled;
1940+
1941+
real_to_real(&CONSTLN2, &ln2); /* ln2 = ln(2) */
1942+
fmul(x, &ln2, &scaled); /* scaled = x * ln(2) */
1943+
fexp(&scaled, result); /* result = e^(x * ln(2)) = 2^x */
1944+
}
1945+
19071946
void fln(const temp_real *x, temp_real *result)
19081947
{
19091948
temp_real guess;
@@ -1912,30 +1951,27 @@ void fln(const temp_real *x, temp_real *result)
19121951
temp_real diff;
19131952
temp_real one;
19141953

1915-
long_to_temp((const long_real *)&CONST1, &one);
1954+
real_to_real((temp_real*)&CONST1, &one);
19161955

19171956
if (x->exponent == 0 && x->a == 0 && x->b == 0) {
1918-
long_to_temp((const long_real *)&NEG_INF, result);
1957+
real_to_real(&NEG_INF, result);
19191958
return;
19201959
}
19211960

19221961
guess = *x;
19231962
fsub(&guess, &one, &guess);
19241963

19251964
while (iter < MAX_ITER) {
1926-
// f(guess) = e^guess - x
19271965
fexp(&guess, &f);
19281966
fsub(&f, x, &f);
19291967

1930-
// f'(guess) = e^guess
1931-
fexp(&guess, &f_prime); // f_prime = e^guess
1968+
fexp(&guess, &f_prime); /* f_prime = e^guess */
19321969

1933-
// New guess = guess - f / f_prime
1934-
fdiv(&f, &f_prime, &new_guess); // new_guess = f / f_prime
1935-
fsub(&guess, &new_guess, &new_guess); // new_guess = guess - f / f_prime
1970+
fdiv(&f, &f_prime, &new_guess); /* new_guess = f / f_prime */
1971+
fsub(&guess, &new_guess, &new_guess); /* new_guess = guess - f / f_prime */
19361972

1937-
fsub(&guess, &new_guess, &diff); // diff = guess - new_guess
1938-
diff.exponent &= 0x7fff; // fabs(diff)
1973+
fsub(&guess, &new_guess, &diff); /* diff = guess - new_guess */
1974+
diff.exponent &= 0x7fff; /* fabs(diff) */
19391975

19401976
if (diff.exponent == 0 && diff.a == 0 && diff.b == 0)
19411977
break;

0 commit comments

Comments
 (0)