mirror of
https://github.com/ksherlock/mpw.git
synced 2024-11-24 13:32:39 +00:00
Implement FX2DEC. Not perfect, but good enough I think.
This commit is contained in:
parent
2a62ad32d2
commit
56fb5d9743
@ -5,6 +5,7 @@ MAKEFLAGS += --no-builtin-rules
|
|||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SECONDARY:
|
.SECONDARY:
|
||||||
|
|
||||||
|
MPWFLAGS = -DMPWVersion=3.2
|
||||||
MPW ?= mpw
|
MPW ?= mpw
|
||||||
|
|
||||||
LIBS = \
|
LIBS = \
|
||||||
@ -25,7 +26,7 @@ LDFLAGS = -w -c 'MPS ' -t MPST \
|
|||||||
SCFLAGS = -p
|
SCFLAGS = -p
|
||||||
|
|
||||||
TARGETS = test_new_handle test_new_handle_2 test_new_pointer test_volumes \
|
TARGETS = test_new_handle test_new_handle_2 test_new_pointer test_volumes \
|
||||||
test_createresfile test_hwpriv
|
test_createresfile test_hwpriv test_sane
|
||||||
|
|
||||||
all : $(TARGETS)
|
all : $(TARGETS)
|
||||||
|
|
||||||
@ -44,10 +45,16 @@ clean :
|
|||||||
# test_volumes : o/test_volumes.o
|
# test_volumes : o/test_volumes.o
|
||||||
# mpw Link $(LDFLAGS) -o $@ $^ $(LIBS)
|
# mpw Link $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
|
test_sane: o/nan.o o/test_sane.o
|
||||||
|
$(MPW) $(MPWFLAGS) Link $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
% : o/%.o
|
% : o/%.o
|
||||||
$(MPW) Link $(LDFLAGS) -o $@ $^ $(LIBS)
|
$(MPW) $(MPWFLAGS) Link $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
o/%.o : %.c
|
o/%.o : %.c
|
||||||
$(MPW) SC $(SCFLAGS) $< -o $@
|
$(MPW) $(MPWFLAGS) SC $(SCFLAGS) $< -o $@
|
||||||
|
|
||||||
|
o/%.o : %.asm
|
||||||
|
$(MPW) $(MPWFLAGS) Asm $(ASMFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
35
test/nan.asm
Normal file
35
test/nan.asm
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
case on
|
||||||
|
|
||||||
|
export nan, __inf, inf
|
||||||
|
|
||||||
|
nan proc
|
||||||
|
; The MPW 3.2 version of nan is broken. This what it's supposed to do.
|
||||||
|
; extended (80-bit) returns via d0, d1, a0
|
||||||
|
|
||||||
|
MOVEM.L data,D0/D1/A0
|
||||||
|
MOVE.W #$4000,D1
|
||||||
|
MOVE.B $0004(A7),D1
|
||||||
|
BNE.S swap
|
||||||
|
MOVE.B #$15,D1
|
||||||
|
swap
|
||||||
|
SWAP D1
|
||||||
|
RTS
|
||||||
|
|
||||||
|
entry inf
|
||||||
|
entry __inf
|
||||||
|
|
||||||
|
inf
|
||||||
|
__inf
|
||||||
|
|
||||||
|
MOVEM.L data,D0/D1/A0
|
||||||
|
RTS
|
||||||
|
|
||||||
|
data
|
||||||
|
dc.l $00007fff
|
||||||
|
dc.l $00000000
|
||||||
|
dc.l $00000000
|
||||||
|
|
||||||
|
end
|
||||||
|
endp
|
||||||
|
|
229
test/test_sane.c
Normal file
229
test/test_sane.c
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
#include <Math.h>
|
||||||
|
#include <SANE.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
//extern pascal extended NAN(short x);
|
||||||
|
|
||||||
|
void dump_decimal(const decimal *d)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "%d : %d : %.*s\n",
|
||||||
|
d->sgn, d->exp, d->sig.length, d->sig.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void test_fxc2dec(void)
|
||||||
|
{
|
||||||
|
decimal d;
|
||||||
|
decform df;
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 100;
|
||||||
|
num2dec(&df, 1.125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : -18 : 1125000000000000000
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, 1.125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : -9 : 1125000000
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 2;
|
||||||
|
num2dec(&df, 1.125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : -1 : 11
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 100;
|
||||||
|
num2dec(&df, 1.125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : -18 : 1125000000000000000
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, 1.125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : -10 : 11250000000
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 2;
|
||||||
|
num2dec(&df, 1.125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//0 : -2 : 112
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 100;
|
||||||
|
num2dec(&df, 1e25, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : 7 : 1000000000000000000
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, 1e25, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : 16 : 1000000000
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 2;
|
||||||
|
num2dec(&df, 1e25, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : 24 : 10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 100;
|
||||||
|
num2dec(&df, 1e25, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : 7 : 1000000000000000000
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, 1e25, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// 0 : 7 : 1000000000000000000
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 2;
|
||||||
|
num2dec(&df, 1e25, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//0 : 7 : 1000000000000000000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, 0, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, 0, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 0;
|
||||||
|
num2dec(&df, -0.0, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 0;
|
||||||
|
num2dec(&df, -0.0, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 0;
|
||||||
|
num2dec(&df,nan(1), &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 0;
|
||||||
|
num2dec(&df, nan(2), &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df,-nan(3), &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, nan(4), &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df,-inf(), &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, -inf(), &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 0;
|
||||||
|
num2dec(&df, inf(), &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 0;
|
||||||
|
num2dec(&df, inf(), &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, 0.125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 10;
|
||||||
|
num2dec(&df, 0.125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
//
|
||||||
|
|
||||||
|
df.style = 0;
|
||||||
|
df.digits = 4;
|
||||||
|
num2dec(&df, 0.00000125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// s/b -9 1250
|
||||||
|
|
||||||
|
df.style = 1;
|
||||||
|
df.digits = 4;
|
||||||
|
num2dec(&df, 0.00000125, &d);
|
||||||
|
dump_decimal(&d);
|
||||||
|
// s/b -4 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
extended x;
|
||||||
|
decimal d;
|
||||||
|
|
||||||
|
short index;
|
||||||
|
short valid;
|
||||||
|
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
valid = 0;
|
||||||
|
str2dec("1.125", &index, &d, &valid);
|
||||||
|
x = dec2num(&d);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
test_fxc2dec();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
169
toolbox/sane.cpp
169
toolbox/sane.cpp
@ -35,6 +35,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "stackframe.h"
|
#include "stackframe.h"
|
||||||
@ -50,6 +51,7 @@ namespace SANE
|
|||||||
using std::to_string;
|
using std::to_string;
|
||||||
using std::fpclassify;
|
using std::fpclassify;
|
||||||
using std::signbit;
|
using std::signbit;
|
||||||
|
using std::abs;
|
||||||
|
|
||||||
using its_complicated::to_string;
|
using its_complicated::to_string;
|
||||||
using its_complicated::fpclassify;
|
using its_complicated::fpclassify;
|
||||||
@ -310,6 +312,72 @@ using its_complicated::signbit;
|
|||||||
ToolBox::WritePString(address + _sig, sig);
|
ToolBox::WritePString(address + _sig, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void format_f(extended x, int precision, std::string &mm, std::string &nn)
|
||||||
|
{
|
||||||
|
char *buffer = nullptr;
|
||||||
|
|
||||||
|
mm.clear();
|
||||||
|
nn.clear();
|
||||||
|
|
||||||
|
if (precision < 0) precision = 0;
|
||||||
|
int length = asprintf(&buffer, "%.*Lf", precision, x);
|
||||||
|
std::string tmp(buffer, length);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
auto dot = tmp.find('.');
|
||||||
|
if (dot == tmp.npos)
|
||||||
|
{
|
||||||
|
mm = std::move(tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mm = tmp.substr(0, dot);
|
||||||
|
nn = tmp.substr(dot + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip mm if it's 0
|
||||||
|
if (mm.length() == 1 && mm.front() == '0') mm.clear();
|
||||||
|
|
||||||
|
// skip nn if it's 0000...
|
||||||
|
if (std::all_of(nn.begin(), nn.end(), [](char c){ return c == '0'; }))
|
||||||
|
nn.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void format_e(extended x, int precision, std::string &mm, std::string &nn, int &exp)
|
||||||
|
{
|
||||||
|
char *buffer = nullptr;
|
||||||
|
|
||||||
|
exp = 0;
|
||||||
|
mm.clear();
|
||||||
|
nn.clear();
|
||||||
|
|
||||||
|
if (precision < 0) precision = 0;
|
||||||
|
if (precision > 19) precision = 19;
|
||||||
|
|
||||||
|
int length = asprintf(&buffer, "%.*Le", precision, x);
|
||||||
|
// output mm . nn e[+-]exp
|
||||||
|
// mm e[+-]exp
|
||||||
|
std::string tmp(buffer, length);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
auto dot = tmp.find('.');
|
||||||
|
auto e = tmp.find('e');
|
||||||
|
|
||||||
|
if (dot == tmp.npos)
|
||||||
|
{
|
||||||
|
mm = tmp.substr(0, e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mm = tmp.substr(0, dot);
|
||||||
|
nn = tmp.substr(dot + 1, e - dot - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char sign = tmp[e+1];
|
||||||
|
tmp = tmp.substr(e + 2);
|
||||||
|
exp = std::stoi(tmp);
|
||||||
|
if (sign == '-') exp = -exp;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t fx2dec()
|
uint16_t fx2dec()
|
||||||
{
|
{
|
||||||
@ -331,8 +399,6 @@ using its_complicated::signbit;
|
|||||||
|
|
||||||
Log(" FX2DEC(%08x, %08x, %08x, %04x)\n", f_adr, a_adr, d_adr, op);
|
Log(" FX2DEC(%08x, %08x, %08x, %04x)\n", f_adr, a_adr, d_adr, op);
|
||||||
|
|
||||||
fprintf(stderr, "warning: FX2DEC not yet implemented\n");
|
|
||||||
|
|
||||||
extended s = readnum<extended>(a_adr);
|
extended s = readnum<extended>(a_adr);
|
||||||
df = decform::read(f_adr);
|
df = decform::read(f_adr);
|
||||||
|
|
||||||
@ -353,18 +419,20 @@ using its_complicated::signbit;
|
|||||||
* [-]mmm[.nnn]
|
* [-]mmm[.nnn]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// this doesn't entirely apply for fx2dec, though.
|
|
||||||
|
|
||||||
if (df.digits < 0) df.digits = 0;
|
if (df.digits < 0) df.digits = 0;
|
||||||
|
if (df.digits > 19) df.digits = 19;
|
||||||
|
|
||||||
fpinfo fpi(s);
|
fpinfo fpi(s);
|
||||||
//fprintf(stderr, "%02x %02x %08x %016llx\n", fpi.sign, fpi.one, fpi.exp, fpi.sig);
|
//fprintf(stderr, "%02x %02x %d %016llx\n", fpi.sign, fpi.one, fpi.exp, fpi.sig);
|
||||||
|
|
||||||
|
|
||||||
|
d.sgn = signbit(s);
|
||||||
|
|
||||||
// handle infinity, nan as a special case.
|
// handle infinity, nan as a special case.
|
||||||
switch (fpclassify(s))
|
switch (fpclassify(s))
|
||||||
{
|
{
|
||||||
case FP_ZERO:
|
case FP_ZERO:
|
||||||
d.sgn = signbit(s);
|
|
||||||
d.sig = "0";
|
d.sig = "0";
|
||||||
d.write(d_adr);
|
d.write(d_adr);
|
||||||
return 0;
|
return 0;
|
||||||
@ -374,7 +442,6 @@ using its_complicated::signbit;
|
|||||||
{
|
{
|
||||||
char buffer[20]; // 16 + 2 needed
|
char buffer[20]; // 16 + 2 needed
|
||||||
snprintf(buffer, 20, "N%016llx", fpi.sig);
|
snprintf(buffer, 20, "N%016llx", fpi.sig);
|
||||||
d.sgn = signbit(s);
|
|
||||||
d.sig = buffer;
|
d.sig = buffer;
|
||||||
d.write(d_adr);
|
d.write(d_adr);
|
||||||
}
|
}
|
||||||
@ -382,7 +449,6 @@ using its_complicated::signbit;
|
|||||||
|
|
||||||
case FP_INFINITE:
|
case FP_INFINITE:
|
||||||
|
|
||||||
d.sgn = signbit(s);
|
|
||||||
d.sig = "I";
|
d.sig = "I";
|
||||||
d.write(d_adr);
|
d.write(d_adr);
|
||||||
return 0;
|
return 0;
|
||||||
@ -394,21 +460,96 @@ using its_complicated::signbit;
|
|||||||
|
|
||||||
// normal and subnormal handled here....
|
// normal and subnormal handled here....
|
||||||
|
|
||||||
#if 0
|
// float decimal: df.digits refers to the total length
|
||||||
if (df.style == decform::FIXEDDECIMAL)
|
// fixed decimal: df.digits refers to the fractional part only.
|
||||||
|
|
||||||
|
s = abs(s);
|
||||||
|
|
||||||
|
|
||||||
|
if (s < 1.0 && df.style == decform::FLOATDECIMAL)
|
||||||
{
|
{
|
||||||
char buffer[decimal::SIGDIGLEN];
|
std::string mm;
|
||||||
snprintf(buffer, sizeof(buffer), "%.*Lg", df.digits, s);
|
std::string nn;
|
||||||
|
|
||||||
|
format_e(s, df.digits - 1, mm, nn, d.exp);
|
||||||
|
|
||||||
}
|
d.sig = mm + nn;
|
||||||
#endif
|
|
||||||
|
|
||||||
// ugh, really don't want to write this code right now.
|
// better be < 0...
|
||||||
|
if (d.exp < 0)
|
||||||
|
d.exp -= nn.length();
|
||||||
|
|
||||||
d.write(d_adr);
|
d.write(d_adr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else // s > 1
|
||||||
|
{
|
||||||
|
|
||||||
|
std::string mm;
|
||||||
|
std::string nn;
|
||||||
|
|
||||||
|
format_f(s, df.digits, mm, nn);
|
||||||
|
|
||||||
|
if (mm.empty() && nn.empty())
|
||||||
|
{
|
||||||
|
// very large 0.
|
||||||
|
d.sig = "0";
|
||||||
|
d.write(d_adr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if nn is empty (or 0s), this is a large number,
|
||||||
|
// and we don't have to worry about the fraction.
|
||||||
|
if (nn.empty())
|
||||||
|
{
|
||||||
|
d.exp = 0;
|
||||||
|
|
||||||
|
if (df.style == decform::FIXEDDECIMAL) df.digits = 19;
|
||||||
|
|
||||||
|
// limit the length.
|
||||||
|
if (mm.length() > df.digits)
|
||||||
|
{
|
||||||
|
d.exp = mm.length() - df.digits;
|
||||||
|
mm.resize(df.digits);
|
||||||
|
}
|
||||||
|
d.sig = std::move(mm);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (df.style == decform::FIXEDDECIMAL)
|
||||||
|
{
|
||||||
|
// digits is the total size, mm + nn
|
||||||
|
// re-format with new precision.
|
||||||
|
// this is getting repetitive...
|
||||||
|
|
||||||
|
if (mm.length())
|
||||||
|
{
|
||||||
|
int precision = df.digits - mm.length();
|
||||||
|
if (precision < 0) precision = 1;
|
||||||
|
|
||||||
|
format_f(s, precision, mm, nn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// todo -- if mm is empty and nn has leading 0s,
|
||||||
|
// drop the leading 0s and adjust the exponent
|
||||||
|
// accordingly.
|
||||||
|
|
||||||
|
d.sig = mm + nn;
|
||||||
|
d.exp = -nn.length();
|
||||||
|
|
||||||
|
if (d.sig.length() > 19)
|
||||||
|
{
|
||||||
|
d.exp += (d.sig.length() - 19);
|
||||||
|
d.sig.resize(19);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
d.write(d_adr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class SrcType, class DestType = extended>
|
template<class SrcType, class DestType = extended>
|
||||||
|
Loading…
Reference in New Issue
Block a user