File:  [Isaki's NoNo m68k/m88k emulator] / nono / m680x0 / m680x0bitfield.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:40 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, v024, v023, HEAD
nono 1.3.0

//
// nono
// Copyright (C) 2022 nono project
// Licensed under nono-license.txt
//

#include "m680x0bitfield.h"
#include "bitops.h"

// コンストラクタ
// 呼び出し側でここまでに ir2 へのフェッチはしておくこと。
acc_bf::acc_bf(MPU680x0Device *cpu_)
{
	cpu = cpu_;

	//  F  E  D  C  B  A  9  8  7  6  5  4  3  2  1  0
	//  0  0  0  0 DO <-- offset --> DW <-- width --->

	offset = (cpu->GetIR2() >> 6) & 0x1f;
	if ((cpu->GetIR2() & 0x0800)) {
		offset = (int32)cpu->reg.D[offset & 7];
		local_offset = offset & 0x1f;
	} else {
		local_offset = offset;
	}

	width = cpu->GetIR2();
	if ((cpu->GetIR2() & 0x0020)) {
		width = cpu->reg.D[width & 7];
	}
	// モジュロ 32 を取り、0 なら 32 を表す
	width = ((width - 1) & 31) + 1;
	// mask は32ビットの上位から width ビット 1 が並んだもの
	mask = 0xffffffff << (32 - width);
}

// データレジスタから値を読み込む。n はデータレジスタの番号。
void
acc_bf::LoadReg(uint n)
{
	data = cpu->reg.D[n];
	data = ROL32(data, local_offset);
	data &= mask;
}

// メモリから値を読み込む。
// 命令サイクル数のため、4バイト以内なら true を返す。
bool
acc_bf::LoadMem(uint32 addr)
{
	// EA の計算
	ea = addr + offset / 8;
	local_offset = offset % 8;
	if (local_offset < 0) {
		local_offset += 8;
		ea--;
	}

	// アクセスするバイト数
	bytes = (local_offset + width + 7) / 8;

	// 40ビットバッファに読み込む
	if (bytes <= 4) {
		buf = ((uint64)cpu->read_n(ea, bytes)) << ((5 - bytes) * 8);
	} else {
		// 実際どういうアクセスになるのか分からないが。
		if ((ea & 1) == 0) {
			// 偶数アドレスから5バイト
			buf = ((uint64)cpu->read_4(ea)) << 8;
			buf |= ((uint64)cpu->read_1(ea + 4));
		} else {
			// 奇数アドレスから5バイト
			buf = ((uint64)cpu->read_1(ea)) << 32;
			buf |= ((uint64)cpu->read_4(ea + 1));
		}
	}

	// 32ビット左詰めにする
	data = (buf >> (8 - local_offset)) & mask;

	return (bytes <= 4);
}

// データレジスタに値を書き出す。
void
acc_bf::StoreReg(uint n)
{
	uint32 m = ROR32(mask, local_offset);
	uint32 d = ROR32(data, local_offset);

	cpu->reg.D[n] = (cpu->reg.D[n] & ~m) | (d & m);
}

// メモリに値を書き出す
void
acc_bf::StoreMem()
{
	// 32ビット左詰めデータを 40ビットバッファにマージ
	uint64 m = (uint64)mask << (8 - local_offset);
	uint64 d = (uint64)data << (8 - local_offset);
	buf = (buf & ~m) | (d & m);

	// 40ビットバッファを書き戻す
	if (bytes <= 4) {
		cpu->write_n(ea, bytes, buf >> ((5 - bytes) * 8));
	} else {
		// 実際どういうアクセスになるのか分からないが。
		if ((ea & 1) == 0) {
			// 偶数アドレスから5バイト
			cpu->write_4(ea, buf >> 8);
			cpu->write_1(ea + 4, buf & 0xff);
		} else {
			// 奇数アドレスから5バイト
			cpu->write_1(ea, buf >> 32);
			cpu->write_4(ea + 1, buf);
		}
	}
}

unix.superglobalmegacorp.com

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