Skip to content

Commit

Permalink
[Dis] Refactor floating point number disassemble output
Browse files Browse the repository at this point in the history
  • Loading branch information
tgtakaoka committed Jul 3, 2024
1 parent 1128308 commit 640129b
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 132 deletions.
110 changes: 72 additions & 38 deletions src/dis_mc68000.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

#include "reg_mc68000.h"
#include "table_mc68000.h"
#include "text_common.h"

namespace libasm {
namespace mc68000 {

using namespace reg;
using namespace text::common;

const ValueFormatter::Plugins &DisMc68000::defaultPlugins() {
return ValueFormatter::Plugins::motorola();
Expand All @@ -34,21 +36,23 @@ DisMc68000::DisMc68000(const ValueFormatter::Plugins &plugins)
}

namespace {

StrBuffer &outOprSize(StrBuffer &out, OprSize size) {
const auto suffix = sizeSuffix(size);
if (suffix)
out.letter('.').letter(suffix);
return out;
}

void outBcdDigit(DisInsn &insn, StrBuffer &out, uint8_t digit) {
void outBcdDigit(StrBuffer &out, uint8_t digit, ErrorAt &error) {
if (digit < 10) {
out.letter(digit + '0');
} else {
out.letter('0');
insn.setErrorIf(out, ILLEGAL_CONSTANT);
error.setErrorIf(out, ILLEGAL_CONSTANT);
}
}

} // namespace

void DisMc68000::decodeImmediateData(DisInsn &insn, StrBuffer &out, OprSize size) const {
Expand All @@ -64,47 +68,60 @@ void DisMc68000::decodeImmediateData(DisInsn &insn, StrBuffer &out, OprSize size
} else if (size == SZ_DUBL) {
out.float64(insn.readFloat64());
} else if (size == SZ_XTND) {
// | |15-bit exponent|16-bit zeroes|64-bit significand|
// ^- sign of significand
const auto exp = insn.readUint16();
(void)(insn.readUint16()); // read padding zeroes
const auto significand = insn.readUint64();
if (exp & 0x8000)
out.letter('-');
const auto exponent = static_cast<int16_t>(exp & 0x7FFF) - 16383 - 63;
out.float80(exponent, significand);
outFloat96(out, insn.readUint96(), insn);
} else if (size == SZ_PBCD) {
// | | | |3-digit exponebt|12-bit zeroes|1-digit integer|16-digit significand|
// ^ ^ ^- 2 bits used for infinity and NaNs
// | +---- sign of exponent
// +------ sign of significand
const auto exp = insn.readUint16();
const auto digit = insn.readUint16() & 0xF;
auto significand = insn.readUint64();
if (exp & 0x8000)
outPackedBcd96(out, insn.readUint96(), insn);
}
}

StrBuffer &DisMc68000::outFloat96(StrBuffer &out, const DisInsn::Uint96 &v, ErrorAt &error) const {
if (v.digit != 0) {
error.setErrorIf(out, ILLEGAL_CONSTANT);
return out;
}
if (v.exp & 0x8000)
out.letter('-');
if ((~v.exp & 0x7FFF) == 0)
return v.significand == 0 ? out.text_P(TEXT_INF) : out.text_P(TEXT_NAN);
const auto exponent = static_cast<int16_t>(v.exp & 0x7FFF) - 16383 - 63;
return out.float80(exponent, v.significand);
}

StrBuffer &DisMc68000::outPackedBcd96(
StrBuffer &out, const DisInsn::Uint96 &v, ErrorAt &error) const {
if ((v.digit & ~0xF) != 0) {
error.setErrorIf(out, ILLEGAL_CONSTANT);
return out;
}
if (v.exp & 0x8000)
out.letter('-');
if (v.exp & 0x2000) // INF?
return out.text_P(TEXT_INF);
if (v.exp & 0x1000) // NAN?
return out.text_P(TEXT_NAN);
outBcdDigit(out, v.digit & 0xF, error);
if (v.significand)
out.letter('.');
auto significand = v.significand;
while (significand) {
outBcdDigit(out, significand >> 60, error);
significand <<= 4;
}
if (v.exp & 0x0FFF) {
out.letter('E');
if (v.exp & 0x4000)
out.letter('-');
outBcdDigit(insn, out, digit);
if (significand)
out.letter('.');
while (significand) {
outBcdDigit(insn, out, significand >> 60);
significand <<= 4;
}
if (exp & 0x3FFF) {
out.letter('E');
if (exp & 0x4000)
out.letter('-');
auto exponent = exp << 4;
auto suppress = true;
for (auto i = 0; i < 3; ++i, exponent <<= 4) {
const auto digit = (exponent >> 12) & 0xF;
if (digit || !suppress) {
outBcdDigit(insn, out, digit);
suppress = false;
}
auto exponent = v.exp << 4;
auto suppress = true;
for (auto i = 0; i < 3; ++i, exponent <<= 4) {
const auto digit = (exponent >> 12) & 0xF;
if (digit || !suppress) {
outBcdDigit(out, digit, error);
suppress = false;
}
}
}
return out;
}

void DisMc68000::decodeEffectiveAddr(
Expand Down Expand Up @@ -580,6 +597,23 @@ Error DisMc68000::decodeImpl(DisMemory &memory, Insn &_insn, StrBuffer &out) con
return _insn.setError(insn);
}

DisInsn::Uint96 DisInsn::readUint96() {
/** Float96
* | |15-bit exponent|16-bit zeroes|64-bit significand|
* ^- sign of significand
*/
/** PackedBcd96
* | | | |3-digit exponent|12-bit zeroes|1-digit integer|16-digit significand|
* ^ ^ ^- 2 bits used for infinity and NaNs
* | +---- sign of exponent
* +------ sign of significand
*/
const auto exp = readUint16();
const auto digit = readUint16();
const auto significand = readUint64();
return {exp, digit, significand};
}

} // namespace mc68000
} // namespace libasm

Expand Down
3 changes: 3 additions & 0 deletions src/dis_mc68000.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ struct DisMc68000 final : Disassembler, Config {
void decodeOperand(DisInsn &insn, StrBuffer &out, AddrMode mode, OprPos pos, OprSize size,
uint16_t opr16 = 0, Error opr16Error = OK) const;

StrBuffer &outFloat96(StrBuffer &buf, const DisInsn::Uint96 &v, ErrorAt &error) const;
StrBuffer &outPackedBcd96(StrBuffer &buf, const DisInsn::Uint96 &v, ErrorAt &error) const;

Error decodeImpl(DisMemory &memory, Insn &insn, StrBuffer &out) const override;
const ConfigBase &config() const override { return *this; }
ConfigSetter &configSetter() override { return *this; }
Expand Down
88 changes: 88 additions & 0 deletions src/insn_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,94 @@ Error Insn::emitPackedBcd96Be(double value, uint8_t pos) {
}
#endif

void DisInsnBase::reset(uint8_t length) {
resetError();
_insn.reset(_insn.address(), length);
}

uint8_t DisInsnBase::readByte() {
if (!_memory.hasNext()) {
setErrorIf(_out, NO_MEMORY);
return 0;
}
const auto data = _memory.readByte();
if (_insn.emitByte(data))
setErrorIf(_out, NO_MEMORY);
return data;
}

uint16_t DisInsnBase::readUint16Be() {
const uint8_t msb = readByte();
const uint8_t lsb = readByte();
return static_cast<uint16_t>(msb) << 8 | lsb;
}

uint16_t DisInsnBase::readUint16Le() {
const uint8_t lsb = readByte();
const uint8_t msb = readByte();
return static_cast<uint16_t>(msb) << 8 | lsb;
}

uint32_t DisInsnBase::readUint32Be() {
const uint16_t msw = readUint16Be();
const uint16_t lsw = readUint16Be();
return static_cast<uint32_t>(msw) << 16 | lsw;
}

uint32_t DisInsnBase::readUint32Le() {
const uint16_t lsw = readUint16Le();
const uint16_t msw = readUint16Le();
return static_cast<uint32_t>(msw) << 16 | lsw;
}

uint64_t DisInsnBase::readUint64Be() {
const uint32_t msw = readUint32Be();
const uint32_t lsw = readUint32Be();
return static_cast<uint64_t>(msw) << 32 | lsw;
}

uint64_t DisInsnBase::readUint64Le() {
const uint32_t lsw = readUint32Le();
const uint32_t msw = readUint32Le();
return static_cast<uint64_t>(msw) << 32 | lsw;
}

double DisInsnBase::readFloat32Be() {
union {
float float32;
uint32_t data32;
} bytes;
bytes.data32 = readUint32Be();
return bytes.float32;
}

double DisInsnBase::readFloat32Le() {
union {
float float32;
uint32_t data32;
} bytes;
bytes.data32 = readUint32Le();
return bytes.float32;
}

double DisInsnBase::readFloat64Be() {
union {
double float64;
uint64_t data64;
} bytes;
bytes.data64 = readUint64Be();
return bytes.float64;
}

double DisInsnBase::readFloat64Le() {
union {
double float64;
uint64_t data64;
} bytes;
bytes.data64 = readUint64Le();
return bytes.float64;
}

} // namespace libasm

// Local Variables:
Expand Down
88 changes: 12 additions & 76 deletions src/insn_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,104 +239,40 @@ struct DisInsnBase : ErrorAt {
const char *name() const { return _insn.name(); }
StrBuffer &nameBuffer() { return _insn.nameBuffer(); }

void reset(uint8_t length = 0) {
resetError();
_insn.reset(_insn.address(), length);
}
void reset(uint8_t length = 0);

/** Read 8 bit data. */
virtual uint8_t readByte() {
if (!_memory.hasNext()) {
setErrorIf(_out, NO_MEMORY);
return 0;
}
const uint8_t data = _memory.readByte();
if (_insn.emitByte(data))
setErrorIf(_out, NO_MEMORY);
return data;
}
virtual uint8_t readByte();

/** Read 16 bit big endian data */
uint16_t readUint16Be() {
const uint8_t msb = readByte();
const uint8_t lsb = readByte();
return static_cast<uint16_t>(msb) << 8 | lsb;
}
uint16_t readUint16Be();

/** Read 16 bit little endian data */
uint16_t readUint16Le() {
const uint8_t lsb = readByte();
const uint8_t msb = readByte();
return static_cast<uint16_t>(msb) << 8 | lsb;
}
uint16_t readUint16Le();

/** Read 32 bit big endian data */
uint32_t readUint32Be() {
const uint16_t msw = readUint16Be();
const uint16_t lsw = readUint16Be();
return static_cast<uint32_t>(msw) << 16 | lsw;
}
uint32_t readUint32Be();

/** Read 32 bit little endian data */
uint32_t readUint32Le() {
const uint16_t lsw = readUint16Le();
const uint16_t msw = readUint16Le();
return static_cast<uint32_t>(msw) << 16 | lsw;
}
uint32_t readUint32Le();

/** Read 64 bit big endian data */
uint64_t readUint64Be() {
const uint32_t msw = readUint32Be();
const uint32_t lsw = readUint32Be();
return static_cast<uint64_t>(msw) << 32 | lsw;
}
uint64_t readUint64Be();

/** Read 64 bit little endian data */
uint64_t readUint64Le() {
const uint32_t lsw = readUint32Le();
const uint32_t msw = readUint32Le();
return static_cast<uint64_t>(msw) << 32 | lsw;
}
uint64_t readUint64Le();

/** Read 32 bit big endian floating point data */
float readFloat32Be() {
union {
float float32;
uint32_t data32;
} bytes;
bytes.data32 = readUint32Be();
return bytes.float32;
}
double readFloat32Be();

/** Read 32 bit little endian floating point data */
float readFloat32Le() {
union {
float float32;
uint32_t data32;
} bytes;
bytes.data32 = readUint32Le();
return bytes.float32;
}
double readFloat32Le();

/** Read 64 bit big endian floating point data */
double readFloat64Be() {
union {
double float64;
uint64_t data64;
} bytes;
bytes.data64 = readUint64Be();
return bytes.float64;
}
double readFloat64Be();

/** Read 64 bit little endian floating point data */
double readFloat64Le() {
union {
double float64;
uint64_t data64;
} bytes;
bytes.data64 = readUint64Le();
return bytes.float64;
}
double readFloat64Le();

protected:
DisInsnBase(Insn &insn, DisMemory &memory, const StrBuffer &out)
Expand Down
8 changes: 8 additions & 0 deletions src/insn_mc68000.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ struct DisInsn final : DisInsnImpl<Config>, EntryInsn {
if (!hasPostfix())
setPostfix(readUint16());
}

struct Uint96 {
uint16_t exp;
uint16_t digit;
uint64_t significand;
};

Uint96 readUint96();
};

} // namespace mc68000
Expand Down
Loading

0 comments on commit 640129b

Please sign in to comment.