Skip to content

Commit

Permalink
Add IBM hexadecimal floating point
Browse files Browse the repository at this point in the history
  • Loading branch information
tgtakaoka committed Oct 20, 2024
1 parent 5a4afeb commit f39bf6a
Show file tree
Hide file tree
Showing 13 changed files with 549 additions and 75 deletions.
4 changes: 2 additions & 2 deletions cli/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ CPPFLAGS = -I../src -I../driver -MD -MF [email protected]

OBJS_com = \
fixed64.o ieee_float.o float80_base.o float80_hard.o float80_soft.o \
dec_float.o str_buffer.o str_scanner.o option_base.o error_reporter.o \
insn_base.o formatters.o value_formatter.o \
dec_float.o ibm_float.o str_buffer.o str_scanner.o option_base.o \
error_reporter.o insn_base.o formatters.o value_formatter.o \
$(foreach a,$(ARCHS),$(OBJS_$(a))) \
bin_memory.o bin_decoder.o bin_encoder.o intel_hex.o moto_srec.o \
file_reader.o file_printer.o list_formatter.o text_common.o
Expand Down
4 changes: 2 additions & 2 deletions cli/build.ninja
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ build asm: link asm.o $
parsers.o reg_base.o str_buffer.o str_scanner.o symbol_store.o $
text_common.o value.o value_formatter.o value_parser.o $
fixed64.o ieee_float.o float80_base.o float80_hard.o float80_soft.o $
dec_float.o $
dec_float.o ibm_float.o $
asm_cdp1802.o reg_cdp1802.o table_cdp1802.o text_cdp1802.o $
asm_f3850.o reg_f3850.o table_f3850.o text_f3850.o $
asm_i8048.o reg_i8048.o table_i8048.o text_i8048.o $
Expand Down Expand Up @@ -60,7 +60,7 @@ build dis: link dis.o $
list_formatter.o moto_srec.o option_base.o reg_base.o str_buffer.o $
str_scanner.o text_common.o value.o value_formatter.o $
fixed64.o ieee_float.o float80_base.o float80_hard.o float80_soft.o $
dec_float.o $
dec_float.o ibm_float.o $
dis_cdp1802.o reg_cdp1802.o table_cdp1802.o text_cdp1802.o $
dis_f3850.o reg_f3850.o table_f3850.o text_f3850.o $
dis_i8048.o reg_i8048.o table_i8048.o text_i8048.o $
Expand Down
177 changes: 177 additions & 0 deletions src/ibm_float.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* Copyright 2024 Tadashi G. Takaoka
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "ibm_float.h"
#include "fixed64.h"
#include "str_buffer.h"

namespace libasm {

const char *__ibm_float32::str() const {
static char buf[16];
StrBuffer out{buf, sizeof(buf)};
const auto sig = _u32 & SIG_MASK;
out.hex(tag(), 2).letter('.').hex(sig, 6);
return buf;
}

__ibm_float32 &__ibm_float32::set(uint8_t tag, uint32_t sig) {
return set((static_cast<uint32_t>(tag) << TAG_POS) | (sig & SIG_MASK));
}

__ibm_float32 &__ibm_float32::set(uint32_t bits) {
_u32 = bits;
return *this;
}

Error __ibm_float32::set(const float80_t &f80) {
auto error = OK;
if (f80.isNan())
error = NOT_AN_EXPECTED;
if (f80.isInf())
error = OVERFLOW_RANGE;
if (f80.isZero() || error) {
_u32 = bits(f80.isNegative(), 0, 0);
return error;
}
fixed64_t sig;
// IBM float fraction is [1/16 .. 1.0)
// IEEE float fraction is [1.0 .. 2.0)
auto ieee_exp = f80.decompose(sig) + 1; // +1 for adjust
ieee_exp += sig.normalize();
while (ieee_exp % 4) {
ieee_exp++;
sig.shift_right(1);
}
sig.round_off(MANT_DIG);
auto ibm_exp = ieee_exp / 4;
auto ibm_sig = sig.value() >> (64 - TAG_POS); // has explicit MSB
if (ibm_exp >= EXP_BASE) {
error = OVERFLOW_RANGE;
ibm_exp = -EXP_BASE; // ibm_sig = 0
}
if (ibm_exp < -EXP_BASE) {
ibm_exp = -EXP_BASE;
ibm_sig = 0;
}
_u32 = bits(f80.isNegative(), ibm_exp + EXP_BASE, ibm_sig);
return error;
}

uint32_t __ibm_float32::bits(bool sign, uint8_t exp, uint32_t sig) {
const auto tag = (sign ? SGN_MASK : 0) | exp;
return (static_cast<uint32_t>(tag) << TAG_POS) | (sig & SIG_MASK);
}

__ibm_float32::operator float80_t() const {
const auto tag = static_cast<uint16_t>(_u32 >> TAG_POS);
const auto sign = (tag & SGN_MASK) != 0;
const auto bexp = tag & EXP_MASK;
const auto ibm_exp = static_cast<int16_t>(bexp) - EXP_BASE;
const auto ibm_sig = (_u32 & SIG_MASK);
if (bexp == 0 && ibm_sig == 0)
return float80_t::zero(sign);
fixed64_t ieee_sig{static_cast<uint64_t>(ibm_sig) << (64 - MANT_DIG)};
// IBM float fraction is [1/16 .. 1.0)
// IEEE float fraction is [1.0 .. 2.0)
auto ieee_exp = ibm_exp * 4 - 1; // -1 for adjust
ieee_exp += ieee_sig.normalize();
return float80_t::compose(sign, ieee_exp, ieee_sig);
}

const char *__ibm_float64::str() const {
static char buf[20];
StrBuffer out{buf, sizeof(buf)};
const auto sig = _u64 & SIG_MASK;
out.hex(tag(), 2)
.letter('.')
.hex(static_cast<uint32_t>(sig >> 32), 6)
.letter('-')
.hex(static_cast<uint32_t>(sig), 8);
return buf;
}

__ibm_float64 &__ibm_float64::set(uint8_t tag, uint64_t sig) {
return set((static_cast<uint64_t>(tag) << TAG_POS) | (sig & SIG_MASK));
}

__ibm_float64 &__ibm_float64::set(uint64_t bits) {
_u64 = bits;
return *this;
}

Error __ibm_float64::set(const float80_t &f80) {
auto error = OK;
if (f80.isNan())
error = NOT_AN_EXPECTED;
if (f80.isInf())
error = OVERFLOW_RANGE;
if (f80.isZero() || error) {
_u64 = bits(f80.isNegative(), 0, 0);
return error;
}
fixed64_t sig;
// IBM float fraction is [1/16 .. 1.0)
// IEEE float fraction is [1.0 .. 2.0)
auto ieee_exp = f80.decompose(sig) + 1; // +1 for adjust
while (ieee_exp % 4) {
ieee_exp++;
sig.shift_right(1);
}
sig.round_off(MANT_DIG);
auto ibm_exp = ieee_exp / 4;
auto ibm_sig = sig.value() >> (64 - TAG_POS); // has explicit MSB
if (ibm_exp >= EXP_BASE) {
error = OVERFLOW_RANGE;
ibm_exp = -EXP_BASE; // ibm_sig = 0
}
if (ibm_exp < -EXP_BASE) {
ibm_exp = -EXP_BASE;
ibm_sig = 0;
}
_u64 = bits(f80.isNegative(), ibm_exp + EXP_BASE, ibm_sig);
return error;
}

uint64_t __ibm_float64::bits(bool sign, uint8_t exp, uint64_t sig) {
const auto tag = (sign ? SGN_MASK : 0) | exp;
return (static_cast<uint64_t>(tag) << TAG_POS) | (sig & SIG_MASK);
}

__ibm_float64::operator float80_t() const {
const auto tag = static_cast<uint16_t>(_u64 >> TAG_POS);
const auto sign = (tag & SGN_MASK) != 0;
const auto bexp = tag & EXP_MASK;
const auto ibm_exp = static_cast<int16_t>(bexp) - EXP_BASE;
const auto ibm_sig = (_u64 & SIG_MASK);
if (bexp == 0 && ibm_sig == 0)
return float80_t::zero(sign);
fixed64_t ieee_sig{static_cast<uint64_t>(ibm_sig) << (64 - MANT_DIG)};
// IBM float fraction is [1/16 .. 1.0)
// IEEE float fraction is [1.0 .. 2.0)
auto ieee_exp = ibm_exp * 4 - 1; // -1 for adjust
ieee_exp += ieee_sig.normalize();
return float80_t::compose(sign, ieee_exp, ieee_sig);
}

} // namespace libasm

// Local Variables:
// mode: c++
// c-basic-offset: 4
// tab-width: 4
// End:
// vim: set ft=cpp et ts=4 sw=4:
109 changes: 109 additions & 0 deletions src/ibm_float.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright 2024 Tadashi G. Takaoka
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef __LIBASM_IBM_FLOAT_H__
#define __LIBASM_IBM_FLOAT_H__

#include <stdint.h>
#include "error_reporter.h"
#include "float80.h"

#define IBMF32_MAX 7.237005e+75
#define IBMF32_MIN 5.397605e-79
#define IBMF64_MAX 7.237005577332262114e+75
#define IBMF64_MIN 5.397605346934027891e-79

namespace libasm {

struct __ibm_float32 {
__ibm_float32(uint8_t tag = 0, uint32_t sig = 0) { set(tag, sig); }
__ibm_float32(const __ibm_float32 &f32) = default;
__ibm_float32 &operator=(const __ibm_float32 &f32) = default;

__ibm_float32 &set(uint8_t tag, uint32_t sig);
__ibm_float32 &set(uint32_t bits);

Error set(const float80_t &f80);
explicit operator float80_t() const;

uint32_t bits() const { return _u32; }
uint8_t tag() const { return _u32 >> TAG_POS; }
static uint32_t bits(bool sign, uint8_t exp, uint32_t sig);

const char *str() const;

static constexpr auto MANT_DIG = 24;
static constexpr auto TAG_POS = MANT_DIG;
static constexpr auto SGN_MASK = UINT8_C(0x80);
static constexpr auto EXP_MASK = UINT8_C(0x7F);
static constexpr auto EXP_BASE = INT8_C(0x40);
static constexpr auto SIG_MASK = (UINT32_C(1) << TAG_POS) - 1;
static constexpr auto MSD_POS = MANT_DIG - 4;

private:
// |sign| bexp(7) | frac(24) |
// sign: 1=negative
// bexp: biased radix 16 exponent, offset 0x40, 0=zero
// frac: fraction hexadecimal digits, 1/16 <= frac < 1
uint32_t _u32;
};

struct __ibm_float64 {
__ibm_float64(uint8_t tag = 0, uint64_t sig = 0) { set(tag, sig); }
__ibm_float64(const __ibm_float64 &f64) = default;
__ibm_float64 &operator=(const __ibm_float64 &f64) = default;

__ibm_float64 &set(uint8_t tag, uint64_t sig);
__ibm_float64 &set(uint64_t bits);

Error set(const float80_t &f80);
explicit operator float80_t() const;

uint64_t bits() const { return _u64; }
uint8_t tag() const { return _u64 >> TAG_POS; }
static uint64_t bits(bool sign, uint8_t exp, uint64_t sig);

const char *str() const;

static constexpr auto MANT_DIG = 56;
static constexpr auto TAG_POS = MANT_DIG;
static constexpr auto SGN_MASK = UINT8_C(0x80);
static constexpr auto EXP_MASK = UINT8_C(0x7F);
static constexpr auto EXP_BASE = INT8_C(0x40);
static constexpr auto SIG_MASK = (UINT64_C(1) << TAG_POS) - 1;
static constexpr auto MSD_POS = MANT_DIG - 4;

private:
// |sign| bexp(7) | frac(56) |
// sign: 1=negative
// bexp: biased radix 16 exponent, offset 0x40, 0=zero
// frac: fraction hexadecimal digits, 1/16 <= frac < 1
uint64_t _u64;
};

using ibm_float32_t = __ibm_float32;
using ibm_float64_t = __ibm_float64;

} // namespace libasm

#endif

// Local Variables:
// mode: c++
// c-basic-offset: 4
// tab-width: 4
// End:
// vim: set ft=cpp et ts=4 sw=4:
3 changes: 2 additions & 1 deletion src/ninja.rules
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ build float80_base.o: cxx ${root}/src/float80_base.cpp
build float80_hard.o: cxx ${root}/src/float80_hard.cpp
build float80_soft.o: cxx ${root}/src/float80_soft.cpp
build formatters.o: cxx ${root}/src/formatters.cpp
build ieee_float.o: cxx ${root}/src/ieee_float.cpp
build ibm_float.o: cxx ${root}/src/ibm_float.cpp
build ieee_float.o: cxx ${root}/src/ieee_float.cpp
build insn_base.o: cxx ${root}/src/insn_base.cpp
build operators.o: cxx ${root}/src/operators.cpp
build option_base.o: cxx ${root}/src/option_base.cpp
Expand Down
8 changes: 4 additions & 4 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,22 @@ OBJS_asm = test_asm_helper.o asm_base.o \
config_base.o insn_base.o operators.o parsers.o reg_base.o value.o \
value_parser.o text_common.o \
fixed64.o ieee_float.o float80_base.o float80_hard.o float80_soft.o \
dec_float.o
dec_float.o ibm_float.o
OBJS_dis = test_dis_helper.o dis_base.o \
config_base.o formatters.o insn_base.o reg_base.o value.o \
value_formatter.o text_common.o \
fixed64.o ieee_float.o float80_base.o float80_hard.o float80_soft.o \
dec_float.o
dec_float.o ibm_float.o
OBJS_expr = test_expr_helper.o \
config_base.o formatters.o insn_base.o operators.o parsers.o \
value.o value_formatter.o value_parser.o text_common.o \
fixed64.o ieee_float.o float80_base.o float80_hard.o float80_soft.o \
dec_float.o
dec_float.o ibm_float.o
OBJS_gen = gen_driver.o test_generator.o tokenized_text.o \
config_base.o dis_base.o dis_formatter.o formatters.o insn_base.o \
list_formatter.o reg_base.o value.o value_formatter.o text_common.o \
fixed64.o ieee_float.o float80_base.o float80_hard.o float80_soft.o \
dec_float.o
dec_float.o ibm_float.o

TEST_OBJS = $(ARCHS:%=test_asm_%.o) $(ARCHS:%=test_dis_%.o)
EXPR_OBJS = $(EXPRS:%=test_expr_%.o)
Expand Down
Loading

0 comments on commit f39bf6a

Please sign in to comment.