--- nono/m680x0/m68030acc.cpp 2026/04/29 17:04:28 1.1.1.1 +++ nono/m680x0/m68030acc.cpp 2026/04/29 17:05:15 1.1.1.3 @@ -1,173 +1,897 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "header.h" -#include "m68030core.h" -#include "m68030bus.h" -#include "m68030ccr.h" +#include "mpu680x0.h" #include "m68030acc.h" -// インライン展開するにはでかいし使用頻度も少ない人たちはこっち。 -// インライン展開できそうな人たちは m68030acc.h のほうへ。 +/*static*/ inline uint32 +m68030acc::vflag_add_8(uint32 src, uint32 dst, uint32 res) +{ + return vflag_add_32(src, dst, res) << 24; +} + +/*static*/ inline uint32 +m68030acc::vflag_add_16(uint32 src, uint32 dst, uint32 res) +{ + return vflag_add_32(src, dst, res) << 16; +} + +/*static*/ inline uint32 +m68030acc::vflag_add_32(uint32 src, uint32 dst, uint32 res) +{ + return (src ^ res) & (dst ^ res); +} + +// src + dst を計算し、XNZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値の上位ビットはクリアされている。 +uint32 +m68030acc::add_8(uint32 src, uint32 dst) +{ + Z = dst + src; + C = Z >> 8; + X = C; + N = Z << 24; + Z &= 0xff; + V = vflag_add_8(src, dst, Z); + return Z; +} + +// src + dst を計算し、XNZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値の上位ビットはクリアされている。 +uint32 +m68030acc::add_16(uint32 src, uint32 dst) +{ + Z = dst + src; + C = Z >> 16; + X = C; + N = Z << 16; + Z &= 0xffff; + V = vflag_add_16(src, dst, Z); + return Z; +} + +// src + dst を計算し、XNZVC フラグをセットして結果を返す。 +uint32 +m68030acc::add_32(uint32 src, uint32 dst) +{ + CZ = (uint64)dst + (uint64)src; + X = C; + V = vflag_add_32(src, dst, Z); + N = Z; + return Z; +} + +// src + dst + X を計算し、XNZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値の上位ビットはクリアされている。 +uint32 +m68030acc::addx_8(uint32 src, uint32 dst) +{ + uint32 res = dst + src + (IsX() ? 1 : 0); + C = res >> 8; + X = C; + N = res << 24; + // 結果がゼロでなければ Z をクリア、結果がゼロなら Z は何もしない + if (N != 0) { + Z = N; + } + V = vflag_add_8(src, dst, res); + return res & 0xff; +} + +// src + dst + X を計算し、XNZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値の上位ビットはクリアされている。 +uint32 +m68030acc::addx_16(uint32 src, uint32 dst) +{ + uint32 res = dst + src + (IsX() ? 1 : 0); + C = res >> 16; + X = C; + N = res << 16; + // 結果がゼロでなければ Z をクリア、結果がゼロなら Z は何もしない + if (N != 0) { + Z = N; + } + V = vflag_add_16(src, dst, res); + return res & 0xffff; +} + +// src + dst + X を計算し、XNZVC フラグをセットして結果を返す。 +uint32 +m68030acc::addx_32(uint32 src, uint32 dst) +{ + uint64 res = (uint64)dst + (uint64)src + (IsX() ? 1 : 0); + C = res >> 32; + X = C; + N = res; + // 結果がゼロでなければ Z をクリア、結果がゼロなら Z は何もしない + if (N != 0) { + Z = N; + } + V = vflag_add_32(src, dst, res); + return res; +} + + +/*static*/ inline uint32 +m68030acc::vflag_sub_8(uint32 src, uint32 dst, uint32 res) +{ + return vflag_sub_32(src, dst, res) << 24; +} + +/*static*/ inline uint32 +m68030acc::vflag_sub_16(uint32 src, uint32 dst, uint32 res) +{ + return vflag_sub_32(src, dst, res) << 16; +} + +/*static*/ inline uint32 +m68030acc::vflag_sub_32(uint32 src, uint32 dst, uint32 res) +{ + return (src ^ dst) & (dst ^ res); +} + +// dst - src を計算し、NZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値の上位ビットはクリアされている。 +uint32 +m68030acc::cmp_8(uint32 src, uint32 dst) +{ + Z = dst - src; + C = Z >> 8; + N = Z << 24; + Z &= 0xff; + V = vflag_sub_8(src, dst, Z); + return Z; +} + +// dst - src を計算し、NZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値の上位ビットはクリアされている。 +uint32 +m68030acc::cmp_16(uint32 src, uint32 dst) +{ + Z = dst - src; + C = Z >> 16; + N = Z << 16; + Z &= 0xffff; + V = vflag_sub_16(src, dst, Z); + return Z; +} +// dst - src を計算し、NZVC フラグをセットして結果を返す。 +uint32 +m68030acc::cmp_32(uint32 src, uint32 dst) +{ + CZ = (uint64)dst - (uint64)src; + N = Z; + V = vflag_sub_32(src, dst, Z); + return Z; +} -// ビットフィールド命令 +// dst - src を計算し、XNZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値の上位ビットはクリアされている。 +uint32 +m68030acc::sub_8(uint32 src, uint32 dst) +{ + uint32 res = cmp_8(src, dst); + X = C; + return res; +} -// コンストラクタ -// 呼び出し側でここまでに RegIR2 へのフェッチはしておくこと。 -acc_bf::acc_bf(m68kcpu *arg) +// dst - src を計算し、XNZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値の上位ビットはクリアされている。 +uint32 +m68030acc::sub_16(uint32 src, uint32 dst) { - cpu = arg; + uint32 res = cmp_16(src, dst); + X = C; + return res; +} - // F E D C B A 9 8 7 6 5 4 3 2 1 0 - // 0 0 0 0 DO <-- offset --> DW <-- width ---> +// dst - src を計算し、XNZVC フラグをセットして結果を返す。 +uint32 +m68030acc::sub_32(uint32 src, uint32 dst) +{ + uint32 res = cmp_32(src, dst); + X = C; + return res; +} - offset = (RegIR2 >> 6) & 0x1f; - if ((RegIR2 & 0x0800)) { - offset = (int32)RegD(offset & 7); - local_offset = offset & 0x1f; +// src - dst - X を計算し、XNZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値 res の上位ビットはクリアされている。 +uint32 +m68030acc::subx_8(uint32 src, uint32 dst) +{ + uint32 res = dst - src - (IsX() ? 1 : 0); + C = res >> 8; + X = C; + N = res << 24; + // 結果がゼロでなければ Z をクリア、結果がゼロなら Z は何もしない + if (N != 0) { + Z = N; + } + V = vflag_sub_8(src, dst, res); + return res & 0xff; +} + +// src - dst - X を計算し、XNZVC フラグをセットして結果を返す。 +// src, dst の上位ビットはクリアしておくこと。 +// 戻り値 res の上位ビットはクリアされている。 +uint32 +m68030acc::subx_16(uint32 src, uint32 dst) +{ + uint32 res = dst - src - (IsX() ? 1 : 0); + C = res >> 16; + X = C; + N = res << 16; + // 結果がゼロでなければ Z をクリア、結果がゼロなら Z は何もしない + if (N != 0) { + Z = N; + } + V = vflag_sub_16(src, dst, res); + return res & 0xffff; +} + +// src - dst - X を計算し、XNZVC フラグをセットして結果を返す。 +uint32 +m68030acc::subx_32(uint32 src, uint32 dst) +{ + uint64 res = (uint64)dst - (uint64)src - (IsX() ? 1 : 0); + C = res >> 32; + X = C; + N = res; + // 結果がゼロでなければ Z をクリア、結果がゼロなら Z は何もしない + if (N != 0) { + Z = N; + } + V = vflag_sub_32(src, dst, res); + return res; +} + +// src(u16) * dst(u16) を計算し、NZVC フラグをセットして結果(u32)を返す。 +// src, dst の上位ビットはクリアしておくこと。 +uint32 +m68030acc::mulu_16(uint32 src, uint32 dst) +{ + uint32 res = src * dst; + // 16x16->32 ではオーバーフローは起きないので move でよい + move_32(res); + return res; +} + +// src(s16) * dst(s16) を計算し、NZVC フラグをセットして結果(u32)を返す。 +// src, dst の上位ビットはクリアしておくこと。 +uint32 +m68030acc::muls_16(uint32 src, uint32 dst) +{ + int32 res = (int32)(int16)src * (int32)(int16)dst; + // 16x16->32 ではオーバーフローは起きないので move でよい + move_32(res); + return res; +} + +// src(u32) * dst(u32) を計算し、NZVC フラグをセットして結果(32bit)を返す。 +uint32 +m68030acc::mulu_32(uint32 src, uint32 dst) +{ + uint64 res = (uint64)src * (uint64)dst; + Z = res; + N = res; + C = 0; + if (res > 0xffffffffUL) { + V = V_BIT; } else { - local_offset = offset; + V = 0; } + return (uint32)res; +} - width = RegIR2; - if ((RegIR2 & 0x0020)) { - width = RegD(width & 7); +// src(s32) * dst(s32) を計算し、NZVC フラグをセットして結果(32bit)を返す。 +uint32 +m68030acc::muls_32(uint32 src, uint32 dst) +{ + int64 res = (int64)(int32)src * (int64)(int32)dst; + Z = res; + N = res; + C = 0; + // V フラグは64ビット演算結果の上位32ビットが + // 下位32ビットの符号拡張になっていなかった場合に立つ。 + // つまり符号付き整数で 32bit 表現と 64bit 表現が一致していなければ立つ。 + int32 tmp = res; + if (res != tmp) { + V = V_BIT; + } else { + V = 0; } - // モジュロ 32 を取り、0 なら 32 を表す - width = ((width - 1) & 31) + 1; - // mask は32ビットの上位から width ビット 1 が並んだもの - mask = 0xffffffff << (32 - width); + return (uint32)res; } -// データレジスタから値を読み込む。n はデータレジスタの番号。 -void -acc_bf::LoadReg(uint n) +// src(u32) * dst(u32) を計算し、NZVC フラグをセットして結果(64bit)を返す。 +uint64 +m68030acc::mulu_64(uint32 src, uint32 dst) { - data = RegD(n); - data = ROL32(data, local_offset); - data &= mask; + uint64 res = (uint64)src * (uint64)dst; + N = res >> 32; + Z = N | res; + V = 0; + C = 0; + return res; +} + +// src(s32) * dst(s32) を計算し、NZVC フラグをセットして結果(64bit)を返す。 +uint64 +m68030acc::muls_64(uint32 src, uint32 dst) +{ + int64 res = (int64)(int32)src * (int64)(int32)dst; + N = res >> 32; + Z = N | res; + V = 0; + C = 0; + return res; } -// メモリから値を読み込む。 void -acc_bf::LoadMem(uint32 addr) +m68030acc::btst(uint32 data, int n) { - // EA の計算 - ea = addr + offset / 8; - local_offset = offset % 8; - if (local_offset < 0) { - local_offset += 8; - ea--; - } - - // アクセスするバイト数 - bytes = (local_offset + width + 7) / 8; - - // 40ビットバッファに読み込む - // m68030_read_NN() はミスアラインドでもアクセスできる - switch (bytes) { - case 1: - buf = ((uint64)m68030_read_8(cpu, ea)) << 32; - break; - case 2: - buf = ((uint64)m68030_read_16(cpu, ea)) << 24; - break; - case 3: - if ((ea & 1) == 0) { - // 偶数アドレスから3バイト - buf = ((uint64)m68030_read_16(cpu, ea)) << 24; - buf |= ((uint64)m68030_read_8(cpu, ea + 2)) << 16; - } else { - // 奇数アドレスから3バイト - buf = ((uint64)m68030_read_8(cpu, ea)) << 32; - buf |= (uint64)m68030_read_16(cpu, ea + 1) << 16; - } - break; - case 4: - buf = ((uint64)m68030_read_32(cpu, ea)) << 8; - break; - case 5: - if ((ea & 1) == 0) { - // 偶数アドレスから5バイト - buf = ((uint64)m68030_read_32(cpu, ea)) << 8; - buf |= ((uint64)m68030_read_8(cpu, ea + 4)); - } else { - // 奇数アドレスから5バイト - buf = ((uint64)m68030_read_8(cpu, ea)) << 32; - buf |= ((uint64)m68030_read_32(cpu, ea + 1)); - } - break; - default: - __unreachable(); + Z = data & (1 << n); +} + +uint32 +m68030acc::bchg(uint32 data, int n) +{ + Z = data & (1 << n); + data ^= (1 << n); + return data; +} + +uint32 +m68030acc::bclr(uint32 data, int n) +{ + Z = data & (1 << n); + data &= ~(1 << n); + return data; +} + +uint32 +m68030acc::bset(uint32 data, int n) +{ + Z = data & (1 << n); + data |= (1 << n); + return data; +} + + +// data を count ビット算術左シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..63。data の上位はクリアしておくこと。 +uint32 +m68030acc::asl_8(uint32 data, int count) +{ + if (count == 0) { + move_8(data); + return data; + } + int64 tmps = (int64)(int8)data; + if (count > 8) count = 9; + uint64 tmp = (uint64)tmps << count; + X = C = tmp >> 8; + N = tmp << 24; + Z = N; + // 送り出された全てのビットが元の MSB と一致すれば V=0 + SetV(((int64)tmp >> 7) != (tmps >> 8)); + return tmp & 0xff; +} + +// data を count ビット算術左シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..63。data の上位はクリアしておくこと。 +uint32 +m68030acc::asl_16(uint32 data, int count) +{ + if (count == 0) { + move_16(data); + return data; + } + int64 tmps = (int64)(int16)data; + if (count > 16) count = 17; + uint64 tmp = (uint64)tmps << count; + X = C = tmp >> 16; + N = tmp << 16; + Z = N; + // 送り出された全てのビットが元の MSB と一致すれば V=0 + SetV(((int64)tmp >> 15) != (tmps >> 16)); + return tmp & 0xffff; +} + +// data を count ビット算術左シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::asl_32(uint32 data, int count) +{ + if (count == 0) { + move_32(data); + return data; + } + int64 tmps = (int64)(int32)data; + if (count > 32) count = 33; + uint64 tmp = (uint64)tmps << count; + X = C = tmp >> 32; + N = Z = tmp; + // 送り出された全てのビットが元の MSB と一致すれば V=0 + SetV(((int64)tmp >> 31) != (tmps >> 32)); + return tmp; +} + +// data を count ビット左シフトし、NZVC フラグを反映して結果を返す。 +// count は 0..63。data の上位はクリアしておくこと。 +uint32 +m68030acc::lsl_8(uint32 data, int count) +{ + if (count == 0) { + move_8(data); + return data; + } + uint64 tmp = (uint64)data << count; + X = C = tmp >> 8; + N = tmp << 24; + Z = tmp & 0xff; + V = 0; + return Z; +} + +// data を count ビット左シフトし、NZVC フラグを反映して結果を返す。 +// count は 0..63。data の上位はクリアしておくこと。 +uint32 +m68030acc::lsl_16(uint32 data, int count) +{ + if (count == 0) { + move_16(data); + return data; + } + uint64 tmp = (uint64)data << count; + X = C = tmp >> 16; + N = tmp << 16; + Z = tmp & 0xffff; + V = 0; + return Z; +} + +// data を count ビット左シフトし、NZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::lsl_32(uint32 data, int count) +{ + if (count == 0) { + move_32(data); + return data; + } + uint64 tmp = (uint64)data << count; + X = C = tmp >> 32; + N = tmp; + Z = tmp; + V = 0; + return Z; +} + +// data:X を count ビット左ローテートし、XNZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::roxl_8(uint32 data, int count) +{ + count %= 9; + if (count == 0) { + Z = data; + N = data << 24; + V = 0; + C = X; + return Z; + } + uint32 xbit = X & 1; + Z = (data << count) | (data >> (9 - count)) | (xbit << (count - 1)); + C = X = Z >> 8; + Z &= 0xff; + N = Z << 24; + V = 0; + return Z; +} + +// data:X を count ビット左ローテートし、XNZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::roxl_16(uint32 data, int count) +{ + count %= 17; + if (count == 0) { + Z = data; + N = data << 16; + V = 0; + C = X; + return Z; + } + uint32 xbit = X & 1; + Z = (data << count) | (data >> (17 - count)) | (xbit << (count - 1)); + C = X = Z >> 16; + Z &= 0xffff; + N = Z << 16; + V = 0; + return Z; +} + +// data:X を count ビット左ローテートし、XNZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::roxl_32(uint32 data, int count) +{ + count %= 33; + if (count == 0) { + Z = data; + N = data; + V = 0; + C = X; + return Z; + } + // 32bit値の 32ビットシフトは未定義動作なので 64bit値を使用 + uint64 data64 = data; + uint32 xbit = X & 1; + Z = (data64 << count) | (data64 >> (33 - count)) | (xbit << (count - 1)); + C = X = data64 >> (32 - count); + N = Z; + V = 0; + return Z; +} + +// data を count ビット左ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63。data の上位はクリアしておくこと +uint32 +m68030acc::rol_8(uint32 data, int count) +{ + if (count == 0) { + move_8(data); + return data; } - // 32ビット左詰めにする - data = (buf >> (8 - local_offset)) & mask; + count %= 8; + int count2 = (8 - count) % 8; + uint8 tmp = (data << count) | (data >> count2); + Z = tmp; + N = (uint32)tmp << 24; + C = data >> count2; + V = 0; + return Z; } -// データレジスタに値を書き出す。 -void -acc_bf::StoreReg(uint n) +// data を count ビット左ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63。data の上位はクリアしておくこと +uint32 +m68030acc::rol_16(uint32 data, int count) { - uint32 m = ROR32(mask, local_offset); - uint32 d = ROR32(data, local_offset); + if (count == 0) { + move_16(data); + return data; + } - RegD(n) = (RegD(n) & ~m) | (d & m); + count %= 16; + int count2 = (16 - count) % 16; + uint16 tmp = (data << count) | (data >> count2); + Z = tmp; + N = (uint32)tmp << 16; + C = data >> count2; + V = 0; + return Z; } -// メモリに値を書き出す -void -acc_bf::StoreMem() +// data を count ビット左ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::rol_32(uint32 data, int count) +{ + if (count == 0) { + move_32(data); + return data; + } + + count %= 32; + int count2 = (32 - count) % 32; + uint64 data64 = (uint64)data; + uint64 tmp = (data << count) | (data >> count2); + Z = tmp; + N = Z; + C = data64 >> count2; + V = 0; + return Z; +} + +// data を count ビット算術右シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..64。data の上位はクリアしておくこと。 +uint32 +m68030acc::asr_8(uint32 data, int count) { - // 32ビット左詰めデータを 40ビットバッファにマージ - uint64 m = (uint64)mask << (8 - local_offset); - uint64 d = (uint64)data << (8 - local_offset); - buf = (buf & ~m) | (d & m); - - // 40ビットバッファを書き戻す - // m68030_write_NN() はミスアラインドでもアクセスできる - switch (bytes) { - case 1: - m68030_write_8(cpu, ea, buf >> 32); - break; - case 2: - m68030_write_16(cpu, ea, buf >> 24); - break; - case 3: - if ((ea & 1) == 0) { - // 偶数アドレスから3バイト - m68030_write_16(cpu, ea, buf >> 24); - m68030_write_8(cpu, ea + 2, buf >> 16); + if (count == 0) { + move_8(data); + return data; + } + if (count > 8) { + if ((int8)data < 0) { + data = 0xff; } else { - // 奇数アドレスから3バイト - m68030_write_8(cpu, ea, buf >> 32); - m68030_write_16(cpu, ea + 1, buf >> 16); + data = 0; } - break; - case 4: - m68030_write_32(cpu, ea, buf >> 8); - break; - case 5: - if ((ea & 1) == 0) { - // 偶数アドレスから5バイト - m68030_write_32(cpu, ea, buf >> 8); - m68030_write_8(cpu, ea + 4, buf); + X = C = Z = data; + N = data << 24; + V = 0; + return data; + } + // data >>> count の結果が tmp の上位32ビット中の下位8ビットに入る + uint64 tmp = (uint64)(int64)(int8)data << (32 - count); + X = C = tmp >> 31; + N = tmp >> 8; + Z = (tmp >> 32) & 0xff; + V = 0; + return Z; +} + +// data を count ビット算術右シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..64。data の上位はクリアしておくこと。 +uint32 +m68030acc::asr_16(uint32 data, int count) +{ + if (count == 0) { + move_16(data); + return data; + } + if (count > 16) { + if ((int16)data < 0) { + data = 0xffff; } else { - // 奇数アドレスから5バイト - m68030_write_8(cpu, ea, buf >> 32); - m68030_write_32(cpu, ea + 1, buf); + data = 0; } - break; - default: - __unreachable(); + X = C = Z = data; + N = data << 16; + V = 0; + return data; + } + // data >>> count の結果が tmp の上位32ビット中の下位16ビットに入る + uint64 tmp = (uint64)(int64)(int16)data << (32 - count); + X = C = tmp >> 31; + N = tmp >> 16; + Z = (tmp >> 32) & 0xffff; + V = 0; + return Z; +} + +// data を count ビット算術右シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..64 +uint32 +m68030acc::asr_32(uint32 data, int count) +{ + if (count == 0) { + move_32(data); + return data; + } + if (count > 32) { + if ((int32)data < 0) { + data = 0xffffffff; + } else { + data = 0; + } + X = C = Z = data; + N = data; + V = 0; + return data; + } + // data >>> count の結果が tmp の上位32ビットに入る + uint64 tmp = (uint64)(int64)(int32)data << (32 - count); + X = C = tmp >> 31; + Z = N = tmp >> 32; + V = 0; + return Z; +} + +// data を count ビット論理右シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::lsr_8(uint32 data, int count) +{ + if (count == 0) { + move_8(data); + return data; + } + if (count > 8) { + X = C = 0; + move_8(0); + return 0; + } + // data >> count の結果が tmp の上位32ビットに入る + uint64 tmp = (uint64)data << (32 - count); + X = C = tmp >> 31; + N = tmp >> 8; + Z = (tmp >> 32) & 0xff; + V = 0; + return Z; +} + +// data を count ビット論理右シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::lsr_16(uint32 data, int count) +{ + if (count == 0) { + move_16(data); + return data; + } + if (count > 16) { + X = C = 0; + move_16(0); + return 0; + } + // data >> count の結果が tmp の上位32ビットに入る + uint64 tmp = (uint64)data << (32 - count); + X = C = tmp >> 31; + N = tmp >> 16; + Z = (tmp >> 32) & 0xffff; + V = 0; + return Z; +} + +// data を count ビット論理右シフトし、XNZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::lsr_32(uint32 data, int count) +{ + if (count == 0) { + move_32(data); + return data; + } + if (count > 32) { + X = C = 0; + move_32(0); + return 0; + } + // data >> count の結果が tmp の上位32ビットに入る + uint64 tmp = (uint64)data << (32 - count); + X = C = tmp >> 31; + Z = N = tmp >> 32; + V = 0; + return Z; +} + +// data:C を count ビット右ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::roxr_8(uint32 data, int count) +{ + count %= 9; + if (count == 0) { + Z = data; + N = data << 24; + V = 0; + C = X; + return Z; + } + uint32 rot = data & ((1 << (count - 1)) - 1); + uint32 xbit = X & 1; + Z = (data >> count) | (rot << (9 - count)) | (xbit << (8 - count)); + C = X = data >> (count - 1); + N = Z << 24; + V = 0; + return Z; +} + +// data:C を count ビット右ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::roxr_16(uint32 data, int count) +{ + count %= 17; + if (count == 0) { + Z = data; + N = data << 16; + V = 0; + C = X; + return Z; + } + uint32 rot = data & ((1 << (count - 1)) - 1); + uint32 xbit = X & 1; + Z = (data >> count) | (rot << (17 - count)) | (xbit << (16 - count)); + C = X = data >> (count - 1); + N = Z << 16; + V = 0; + return Z; +} + +// data:C を count ビット右ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::roxr_32(uint32 data, int count) +{ + count %= 33; + if (count == 0) { + Z = data; + N = data; + V = 0; + C = X; + return Z; + } + // 32bit値の 32ビットシフトは未定義動作なので 64bit値を使用 + uint64 data64 = data; + uint64 rot = data64 & ((1 << (count - 1)) - 1); + uint32 xbit = X & 1; + Z = (data64 >> count) | (rot << (33 - count)) | (xbit << (32 - count)); + C = X = data64 >> (count - 1); + N = Z; + V = 0; + return Z; +} + +// data を count ビット右ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::ror_8(uint32 data, int count) +{ + if (count == 0) { + move_8(data); + return data; } + + count %= 8; + uint8 tmp = (data >> count) | (data << (8 - count)); + Z = tmp; + N = (uint32)tmp << 24; + // 7 0 1 2 3 4 5 6 + C = data >> ((count + 7) % 8); + V = 0; + return tmp; +} + +// data を count ビット右ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::ror_16(uint32 data, int count) +{ + if (count == 0) { + move_16(data); + return data; + } + + count %= 16; + uint16 tmp = (data >> count) | (data << (16 - count)); + Z = tmp; + N = (uint32)tmp << 16; + C = data >> ((count + 15) % 16); + V = 0; + return tmp; +} + +// data を count ビット右ローテートし、NZVC フラグを反映して結果を返す。 +// count は 0..63 +uint32 +m68030acc::ror_32(uint32 data, int count) +{ + if (count == 0) { + move_32(data); + return data; + } + + count %= 32; + uint64 data64 = (uint64)data; + uint64 tmp = (data >> count) | (data << (32 - count)); + Z = tmp; + N = tmp; + C = data64 >> ((count + 31) % 32); + V = 0; + return tmp; } void -acc_chk2cmp2_32(m68kcpu *cpu, uint32 compare, uint32 lower, uint32 upper) +m68030acc::chk2cmp2_32(uint32 compare, uint32 lower, uint32 upper) { // 実機の実行結果をじっと睨んだ結果、このロジックで // cmp2 は実行していると考えられる。 @@ -177,305 +901,68 @@ acc_chk2cmp2_32(m68kcpu *cpu, uint32 com // この cmp は通常の if で代替できるけど、 // あえて MPU 内部の動作をエミュレート。 - acc_cmp_32(cpu, lower, upper); + cmp_32(lower, upper); - if (RegCondCS) { - acc_cmp_32(cpu, compare, upper); - if (RegCondEQ) { + if (CondCS()) { + cmp_32(compare, upper); + if (CondEQ()) { // break - } else if (RegCondCS) { - acc_cmp_32(cpu, lower, compare); + } else if (CondCS()) { + cmp_32(lower, compare); } else { - acc_cmp_32(cpu, compare, lower); + cmp_32(compare, lower); } } else { - acc_cmp_32(cpu, lower, compare); - if (RegCondEQ) { + cmp_32(lower, compare); + if (CondEQ()) { // break - } else if (RegCondCS) { + } else if (CondCS()) { // break } else { - acc_cmp_32(cpu, compare, upper); + cmp_32(compare, upper); } } } -// dst(u32) / src(u16) を計算して、NZVC フラグをセットする。 -// src の上位ビットはクリアしておくこと。 -// true なら rem(16) と quo(16) が有効で、 -// rem, quo の上位ビットはクリアされている。 -// false なら結果を書き戻さずに終了する。 -bool -acc_divu_32_16(m68kcpu *cpu, uint32 src, uint32 dst, uint32 *quo, uint32 *rem) -{ - if (src == 0) { - // ゼロ除算の場合、 - // X は変化しない - // C は常にクリア - // N,Z,V は未定義 - CCR.c = 0; - m68030_exception(cpu, M68K_EXCEP_ZERODIV); - return false; - } - *quo = dst / src; - *rem = dst % src; - if (*quo > 0xffff) { - // オーバーフローの場合、 - // X は変化しない - // N,Z は未定義 - // V はセット - // C は常にクリア - CCR.v = m68030ccr::V_BIT; - CCR.c = 0; - return false; - } - // 正常の場合、 - // X は変化しない - // V, C はクリア - // N, Z は quo の結果。 - *rem &= 0xffff; - acc_move_16(cpu, *quo); - return true; -} - -// dst(u32) / src(u32) を計算して、NZVC フラグをセットする。 -// true なら rem(32), quo(32) が有効、 -// false なら結果を書き戻さずに終了する。 -bool -acc_divu_32_32(m68kcpu *cpu, uint32 src, uint32 dst, uint32 *quo, uint32 *rem) -{ - if (src == 0) { - // ゼロ除算の場合、 - // X は変化しない - // C は常にクリア - // N,Z,V は未定義 - CCR.c = 0; - m68030_exception(cpu, M68K_EXCEP_ZERODIV); - return false; - } - *quo = dst / src; - *rem = dst % src; - // このケースでオーバーフローは起きないはず - - // 正常の場合、 - // X は変化しない - // V, C はクリア - // N, Z は quo の結果。 - acc_move_32(cpu, *quo); - return true; -} - -// dst(u64) / src(u32) を計算して、NZVC フラグをセットする。 -// true なら rem(32), quo(32) が有効、 -// false なら結果を書き戻さずに終了する。 -bool -acc_divu_64_32(m68kcpu *cpu, uint32 src, uint64 dst, uint32 *quo, uint32 *rem) -{ - if (src == 0) { - // ゼロ除算の場合、 - // X は変化しない - // C は常にクリア - // N,Z,V は未定義 - CCR.c = 0; - m68030_exception(cpu, M68K_EXCEP_ZERODIV); - return false; - } - uint64 q64 = dst / src; - *rem = dst % src; - if (q64 > 0xffffffffUL) { - // オーバーフローの場合、 - // X は変化しない - // N,Z は未定義 - // V はセット - // C は常にクリア - CCR.v = m68030ccr::V_BIT; - CCR.c = 0; - return false; - } - - *quo = q64; - - // 正常の場合、 - // X は変化しない - // V, C はクリア - // N, Z は quo の結果。 - acc_move_32(cpu, *quo); - return true; -} - -// dst(s32) / src(s16) を計算して、NZVC フラグをセットする。 -// src の上位ビットはクリアしておくこと。 -// true なら rem(16) と quo(16) が有効で、 -// rem, quo の上位ビットはクリアされている。 -// false なら結果を書き戻さずに終了する。 -bool -acc_divs_32_16(m68kcpu *cpu, uint32 src, uint32 dst, uint32 *quo, uint32 *rem) -{ - if (src == 0) { - // ゼロ除算の場合、 - // X は変化しない - // C は常にクリア - // N,Z,V は未定義 - CCR.c = 0; - m68030_exception(cpu, M68K_EXCEP_ZERODIV); - return false; - } - - // ホストでオーバーフローが起きるのはこのケースのみ - if (dst == 0x80000000 && src == 0xffff) { - // オーバーフローの場合、 - // X は変化しない - // N,Z は未定義 - // V はセット - // C は常にクリア - CCR.v = m68030ccr::V_BIT; - CCR.c = 0; - return false; - } - - int32 squo = (int32)dst / (int32)(int16)src; - int32 srem = (int32)dst % (int32)(int16)src; - if ((int16)squo != squo) { - // オーバーフローの場合 - CCR.v = m68030ccr::V_BIT; - CCR.c = 0; - return false; - } - // 正常の場合、 - // X は変化しない - // V, C はクリア - // N, Z は quo の結果。 - *quo = (uint32)squo & 0xffff; - *rem = (uint32)srem & 0xffff; - acc_move_16(cpu, *quo); - return true; -} - -// dst(s32) / src(s32) を計算して、NZVC フラグをセットする。 -// true なら rem(32), quo(32) が有効、 -// false なら結果を書き戻さずに終了する。 -bool -acc_divs_32_32(m68kcpu *cpu, uint32 src, uint32 dst, uint32 *quo, uint32 *rem) -{ - if (src == 0) { - // ゼロ除算の場合、 - // X は変化しない - // C は常にクリア - // N,Z,V は未定義 - CCR.c = 0; - m68030_exception(cpu, M68K_EXCEP_ZERODIV); - return false; - } - - // ホストでオーバーフローが起きるのはこのケースのみ - if (dst == INT32_MIN && src == -1) { - // オーバーフローの場合、 - // X は変化しない - // N,Z は未定義 - // V はセット - // C は常にクリア - CCR.v = m68030ccr::V_BIT; - CCR.c = 0; - return false; - } - - *quo = (int32)dst / (int32)src; - *rem = (int32)dst % (int32)src; - // ここでオーバーフローは起きない - - // 正常の場合、 - // X は変化しない - // V, C はクリア - // N, Z は quo の結果。 - acc_move_32(cpu, *quo); - return true; -} - -// dst(s64) / src(s32) を計算して、NZVC フラグをセットする。 -// true なら rem(32), quo(32) が有効、 -// false なら結果を書き戻さずに終了する。 -bool -acc_divs_64_32(m68kcpu *cpu, uint32 src, uint64 dst, uint32 *quo, uint32 *rem) -{ - if (src == 0) { - // ゼロ除算の場合、 - // X は変化しない - // C は常にクリア - // N,Z,V は未定義 - CCR.c = 0; - m68030_exception(cpu, M68K_EXCEP_ZERODIV); - return false; - } - - // ホストでオーバーフローが起きるのはこのケースのみ - if (dst == INT64_MIN && src == -1) { - // オーバーフローの場合、 - // X は変化しない - // N,Z は未定義 - // V はセット - // C は常にクリア - CCR.v = m68030ccr::V_BIT; - CCR.c = 0; - return false; - } - - int64 sq64 = (int64)dst / (int32)src; - *rem = (int64)dst % (int32)src; - if ((int32)sq64 != sq64) { - // オーバーフロー - CCR.v = m68030ccr::V_BIT; - CCR.c = 0; - return false; - } - - // 正常の場合、 - // X は変化しない - // V, C はクリア - // N, Z は quo の結果。 - *quo = (uint32)sq64; - acc_move_32(cpu, *quo); - return true; -} - // src_10 + dst_10 + X を計算し、XNZVC フラグをセットして結果を返す。 // src, dst の上位ビットはクリアしておくこと。 // 戻り値の上位ビットはクリアされている。 uint32 -acc_abcd_8(m68kcpu *cpu, uint32 src, uint32 dst) +m68030acc::abcd_8(uint32 src, uint32 dst) { uint32 res; uint32 tmp; uint32 adj; uint32 low; - uint32 c; + uint32 cbit; adj = 0; - c = 0; + cbit = 0; // X フラグは LSB なので直接足してよい - tmp = src + dst + (CCR.x & m68030ccr::X_BIT); + tmp = src + dst + (X & X_BIT); - low = (src & 0x0f) + (dst & 0x0f) + (CCR.x & m68030ccr::X_BIT); + low = (src & 0x0f) + (dst & 0x0f) + (X & X_BIT); if (low > 0x09) { adj = 0x06; } if (tmp > 0x99) { adj += 0x60; - c = m68030ccr::C_BIT; + cbit = C_BIT; } res = tmp + adj; - c |= res >> 8; - CCR.x = CCR.c = c; + cbit |= res >> 8; + X = C = cbit; res &= 0xff; - CCR.z |= res; + Z |= res; // V フラグは不定だが 68030 では常にクリア - CCR.v = 0; + V = 0; // N フラグは不定だが 68030 実機合わせ - CCR.n = res << 24; + N = res << 24; return res; } @@ -484,41 +971,41 @@ acc_abcd_8(m68kcpu *cpu, uint32 src, uin // src, dst の上位ビットはクリアしておくこと。 // 戻り値の上位ビットはクリアされている。 uint32 -acc_sbcd_8(m68kcpu *cpu, uint32 src, uint32 dst) +m68030acc::sbcd_8(uint32 src, uint32 dst) { uint32 res; int32 tmp; int32 adj; int32 low; - uint32 c; + uint32 cbit; adj = 0; - c = 0; + cbit = 0; // X フラグは LSB なので直接引いてよい - tmp = dst - src - (CCR.x & m68030ccr::X_BIT); + tmp = dst - src - (X & X_BIT); - low = (dst & 0x0f) - (src & 0x0f) - (CCR.x & m68030ccr::X_BIT); + low = (dst & 0x0f) - (src & 0x0f) - (X & X_BIT); if (low < 0) { adj = 0x06; } if (tmp < 0) { adj += 0x60; - c = m68030ccr::C_BIT; + cbit = C_BIT; } res = tmp - adj; - c |= res >> 8; - CCR.x = CCR.c = c; + cbit |= res >> 8; + X = C = cbit; res &= 0xff; - CCR.z |= res; + Z |= res; // V フラグは不定だが 68030 では常にクリア - CCR.v = 0; + V = 0; // N フラグは不定だが 68030 実機合わせ - CCR.n = res << 24; + N = res << 24; return res; }