File:  [Isaki's NoNo m68k/m88k emulator] / nono / fpe / host.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:57 2026 UTC (3 months ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// XM6i
// Copyright (C) 2013 Tetsuya Isaki
//
// for host FPU mode
//

#include <float.h>
#include <stdio.h>
#include <string.h>

#include "cmake_config.h"
#include "fpu_emulate.h"

/*
 * M68881/2 の浮動小数点表現(IEEE754)をホストの浮動小数点表現に変換する。
 */

/* ホスト演算用のダミー fpemu */
static struct fpemu dummyfe;

float
fpu_to_host_float(const uint32_t *src)
{
	return *(const float *)src;
}

double
fpu_to_host_double(const uint32_t *src)
{
	double dst = 0;	/* shut up gcc */
	uint32_t *d = (uint32_t *)&dst;

	d[1] = src[0];
	d[0] = src[1];
	return dst;
}

#if defined(HAVE_LONG_DOUBLE)
long double
fpu_to_host_ldouble(const uint32_t *src)
{
	long double dst = 0;	/* shut up gcc */
	uint32_t *d = (uint32_t *)&dst;

#if LONG_DOUBLE == 16
	/* amd64 だと16バイト境界にしたいのでパディングがあるだけ */
	d[3] = 0;
#endif
	/* intel フォーマットは16bitパディングの位置が 68881 とは逆 */
	d[2] = src[0] >> 16;
	d[1] = src[1];
	d[0] = src[2];

	return dst;
}
#endif /* HAVE_LONG_DOUBLE */

void
host_float_to_fpu(uint32_t *dst, float src)
{
	// stub
}

void
host_double_to_fpu(uint32_t *dst, double src)
{
	uint32_t *s = (uint32_t *)&src;

	dst[1] = s[0];
	dst[0] = s[1];
}

void
host_ldouble_to_fpu(uint32_t *dst, long double src)
{
	// stub
}

/*
 * fpn 表現とホスト浮動小数点の変換
 */

/*
 * +-INF を作成して返す。
 * 符号部は fp の符号を使うが、指数部/仮数部はこちらで用意する。
 * 特に ISINF(fp) で判定した場合 fp の仮数部は不定なので流用してはいけない。
 */
static inline double
fp2dbl_inf(const struct fpn *fp)
{
	uint64_t v;

	if (fp->fp_sign) {
		// -INF
		v = 0xfff0000000000000ULL;
	} else {
		// +INF
		v = 0x7ff0000000000000ULL;
	}
	return *(double*)&v;
}

double
fp2dbl(const struct fpn *fp)
{
	int exp;
	uint64_t v;

	if (ISNAN(fp)) {
		exp = DBL_EXP_INFNAN;
	} else if (ISINF(fp)) {
		return fp2dbl_inf(fp);
	} else {
		exp = fp->fp_exp + DBL_EXP_BIAS;
		// exp <= 0 は X 精度を D 精度にするとアンダーフローするケース。
		if (ISZERO(fp) || exp <= 0) {
			if (fp->fp_sign) {
				return -0.0;
			} else {
				return 0.0;
			}
		} else if (exp >= DBL_EXP_INFNAN) {
			return fp2dbl_inf(fp);
		}
	}

	v = (fp->fp_sign);
	v <<= 11;
	v |= exp;
	v <<= FP_LG;
	// mant の有効な上位の 52 ビットを取り出す
	v |= fp->fp_mant[0] & (FP_1 - 1);
	v <<= 32;
	v |= fp->fp_mant[1];
	v <<= 2;
	v |= (fp->fp_mant[2] >> (32-2)) & 0x03;

	return *(double*)&v;
}

long double
fp2ldbl(const struct fpn *f)
{
	struct fpn fp;
	uint32_t a[3];

	CPYFPN(&fp, f);
	fpu_implode(&dummyfe, &fp, FTYPE_EXT, a);
	return fpu_to_host_ldouble(a);
}

void
dbl2fp(struct fpn *fp, double src)
{
	uint32_t a[2];

	host_double_to_fpu(a, src);
	fpu_explode(&dummyfe, fp, FTYPE_DBL, a);
	return;
}

void
ldbl2fp(struct fpn *fp, long double src)
{
	// stub
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.