From cab4ae2b6532176fd5593763ddaac115d4ee1503 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Tue, 5 Mar 2013 21:41:30 -0500 Subject: [PATCH] real sane extended support --- toolbox/sane.cpp | 227 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 204 insertions(+), 23 deletions(-) diff --git a/toolbox/sane.cpp b/toolbox/sane.cpp index a133f95..f45f524 100644 --- a/toolbox/sane.cpp +++ b/toolbox/sane.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "stackframe.h" @@ -15,15 +16,114 @@ using ToolBox::Log; namespace SANE { - double to_double(uint64_t x) + // long double is an 80-bit extended with an extra 48-bits of 0 padding. + typedef long double extended; + + template + T readnum(uint32_t address); + + template<> + int16_t readnum(uint32_t address) { + return memoryReadWord(address); + } + + template<> + int32_t readnum(uint32_t address) + { + return memoryReadLong(address); + } + + template<> + float readnum(uint32_t address) + { + static_assert(sizeof(float) == 4, "unexpected long double size"); + + uint32_t x = memoryReadLong(address); + return *((float *)&x); + } + + template<> + double readnum(uint32_t address) + { + static_assert(sizeof(double) == 8, "unexpected long double size"); + + uint64_t x = memoryReadLongLong(address); return *((double *)&x); } - uint64_t to_int64(double d) + + template<> + long double readnum(uint32_t address) { - return *((uint64_t *)&d); + char buffer[16]; + + static_assert(sizeof(long double) == 16, "unexpected long double size"); + + + // read and swap 10 bytes + // this is very much little endian. + + for (unsigned i = 0; i < 10; ++i) + { + buffer[9 - i] = memoryReadByte(address + i); + } + // remainder are 0-filled. + for (unsigned i = 10; i < 16; ++i) + buffer[i] = 0; + + // now cast... + + return *((long double *)buffer); } + template + void writenum(T value, uint32_t address); + + template<> + void writenum(int16_t value, uint32_t address) + { + memoryWriteWord(value, address); + } + + template<> + void writenum(int32_t value, uint32_t address) + { + memoryWriteLong(value, address); + } + + template<> + void writenum(float value, uint32_t address) + { + static_assert(sizeof(value) == 4, "unexpected float size"); + + memoryWriteLong(*((uint32_t *)&value), address); + } + + template<> + void writenum(double value, uint32_t address) + { + static_assert(sizeof(value) == 8, "unexpected double size"); + + memoryWriteLongLong(*((uint64_t *)&value), address); + } + + template<> + void writenum(long double value, uint32_t address) + { + static_assert(sizeof(value) == 16, "unexpected long double size"); + + char buffer[16]; + + std::memcpy(buffer, &value, sizeof(value)); + + // copy 10 bytes over + // little-endian specific. + for(unsigned i = 0; i < 10; ++i) + memoryWriteByte(buffer[9 - i], address + i); + } + + + uint16_t fl2x() { // long to extended (80-bit fp) @@ -32,17 +132,18 @@ namespace SANE uint32_t src; StackFrame<10>(src, dest, op); - //80-bit isn't popular anymore, so convert to double (64-bit) - Log(" FL2X(%08x, %08x, %084x)\n", src, dest, op); + Log(" FL2X(%08x, %08x, %04x)\n", src, dest, op); - int32_t i = memoryReadLong(src); - double d = (double)i; + int32_t i = readnum(src); - int64_t i64 = to_int64(d); + if (ToolBox::Trace) + { + std::string tmp1 = std::to_string(i); + Log(" %s\n", tmp1.c_str()); + } - memoryWriteLongLong(i64, dest); - memoryWriteWord(0, dest + 8); + writenum((extended)i, dest); return 0; } @@ -55,27 +156,56 @@ namespace SANE uint32_t src; StackFrame<10>(src, dest, op); - //80-bit isn't popular anymore, so convert to double (64-bit) - Log(" FDIVX(%08x, %08x, %084x)\n", src, dest, op); + Log(" FDIVX(%08x, %08x, %04x)\n", src, dest, op); - uint64_t si = memoryReadLongLong(src); - uint64_t di = memoryReadLongLong(dest); + extended s = readnum(src); + extended d = readnum(dest); - - double sd = to_double(si); - double dd = to_double(di); + if (ToolBox::Trace) + { + std::string tmp1 = std::to_string(d); + std::string tmp2 = std::to_string(s); + Log(" %s / %s\n", tmp1.c_str(), tmp2.c_str()); + } // dest = dest / src - dd = dd / sd; + d = d / s; - di = to_int64(dd); - memoryWriteLongLong(di, dest); - memoryWriteWord(0, dest + 8); + writenum((extended)d, dest); return 0; } + uint16_t fmulx() + { + // multiply extended (80-bit fp) + uint16_t op; + uint32_t dest; + uint32_t src; + + StackFrame<10>(src, dest, op); + + Log(" FMULX(%08x, %08x, %04x)\n", src, dest, op); + + extended s = readnum(src); + extended d = readnum(dest); + + if (ToolBox::Trace) + { + std::string tmp1 = std::to_string(d); + std::string tmp2 = std::to_string(s); + Log(" %s * %s\n", tmp1.c_str(), tmp2.c_str()); + } + + d = d * s; + + writenum((extended)d, dest); + + return 0; + return 0; + } + uint16_t fx2dec() { // extended (80-bit fp) to decimal @@ -87,8 +217,17 @@ namespace SANE StackFrame<14>(f_adr, a_adr, d_adr, op); - uint64_t si = memoryReadLongLong(a_adr); - double sd = to_double(si); + 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(a_adr); + + if (ToolBox::Trace) + { + std::string tmp1 = std::to_string(s); + Log(" %s\n", tmp1.c_str()); + } // ugh, really don't want to write this code right now. memoryWriteWord(0, d_adr); @@ -98,6 +237,37 @@ namespace SANE return 0; } + + template + uint16_t fadd(const char *name) + { + // faddi, etc. + // destination is always extended. + uint16_t op; + uint32_t dest; + uint32_t src; + + StackFrame<10>(src, dest, op); + + Log(" %s(%08x, %08x, %04x)\n", name, src, dest, op); + + SRCTYPE s = readnum(src); + extended d = readnum(dest); + + if (ToolBox::Trace) + { + std::string tmp1 = std::to_string(d); + std::string tmp2 = std::to_string(s); + Log(" %s + %s\n", tmp1.c_str(), tmp2.c_str()); + } + + d = d + s; + + writenum((extended)d, dest); + return 0; + } + + uint16_t fp68k(uint16_t trap) { uint16_t op; @@ -112,6 +282,17 @@ namespace SANE if (op == 0x000b) return fx2dec(); if (op == 0x280e) return fl2x(); + if (op == 0x0004) return fmulx(); + + switch(op) + { + + case 0x2000: // faddi + return fadd("FADDI"); + break; + + } + fprintf(stderr, "fp68k -- op %04x is not yet supported\n", op); exit(1);