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

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

#include "mpu680x0.h"
#define M680X0_CYCLE_TABLE
#include "m680x0cycle.h"

class MPU680x0Test : public MPU680x0Device
{
 public:
	MPU680x0Test() {
		cycle_table = cycle_table_030cc;
	}
	~MPU680x0Test() override { }
	void test_ea_ix();
	void test_ea_ix2();

	uint32 fetch_2() override;
	uint32 fetch_4() override;
	uint32 read_data(busaddr addr) override;
	void write_data(busaddr addr, uint32 data) override;

	busaddr TranslatePeek(busaddr) override { return busaddr(0); }
	void CalcStat() override { }
	bool ops_movec_rc_rn_cpu(uint, uint) override { return true; }
	bool ops_movec_rn_rc_cpu(uint, uint) override { return true; }
	void ops_mmu30() override { }
	void ops_mmu40_pflush() override { }
	void ResetMMU() override { }
	void ResetCache() override { }
	void SetCACR(uint32) override { }
};

static uint16 g_fetch[5];
static int    g_fetch_ptr;

// ダミーのフェッチルーチン
// グローバル変数 g_fetch[] で指定された値を順に返す
uint32
MPU680x0Test::fetch_2()
{
	uint16 data;

	if (g_fetch_ptr >= countof(g_fetch)) {
		abort();
	}
	data = g_fetch[g_fetch_ptr++];
	return data;
}

uint32
MPU680x0Test::fetch_4()
{
	uint32 data;

	data = fetch_2() << 16;
	data |= fetch_2();
	return data;
}

// ダミーリード
// アドレスを2倍にして返す。
// メモリ間接の post index、pre index を演算だけで判別するため。
uint32
MPU680x0Test::read_data(busaddr laddr)
{
	if (laddr.GetSize() == 4) {
		return laddr.Addr() << 1;
	}
	return 0;
}

void
MPU680x0Test::write_data(busaddr laddr, uint32 data)
{
}

// リンクを通すためのダミー。
Object::Object(uint) { }
Object::~Object() { }
Device::Device(uint) : inherited(0) { }
Device::~Device() { }
MPUDevice::MPUDevice(uint) : inherited(0) { }
MPUDevice::~MPUDevice() { }
MainMPUDevice::MainMPUDevice() : inherited(0) { }
MainMPUDevice::~MainMPUDevice() { }
MPU680x0Device::MPU680x0Device() { }
MPU680x0Device::~MPU680x0Device() { }
BranchHistory::BranchHistory(uint) : inherited(0) { }
BranchHistory::~BranchHistory() { }
BranchHistory_m680x0::BranchHistory_m680x0(uint) : inherited(0) { }
BranchHistory_m680x0::~BranchHistory_m680x0() { }
void Object::SetLogLevel(int) { }
void Object::putlogn(const char *, ...) const { }
void Device::putlogn(const char *, ...) const { }
bool Device::Create() { return true; }
bool Device::Create2() { return true; }
bool Device::Init() { return true; }
void Device::ResetHard(bool) { }
void Device::PowerOff() { }
bool MPUDevice::Init() { return true; }
void MPUDevice::ResetHard(bool) { }
void MPUDevice::PowerOff() { }
bool MainMPUDevice::Init() { return true; }
bool MPU680x0Device::Init() { return true; }
void MPU680x0Device::ResetHard(bool) { }
void MPU680x0Device::Interrupt(int) { }
void MPU680x0Device::SetTrace(bool) { }
std::string BranchHistory::FormatHeader() const { return ""; }
std::string BranchHistory::FormatEntry(const BranchEntry&) { return ""; }
std::string BranchHistory_m680x0::FormatEntry(const BranchEntry&) { return ""; }

void
panic_func(const char *func, const char *fmt, ...)
{
	va_list ap;
	printf("panic: %s:", func);
	va_start(ap, fmt);
	vprintf(fmt, ap);
	va_end(ap);
	abort();
}

static MPU680x0Test *cpu;
static int tested;
static int failed;

// 拡張 EA の全組み合わせを試す網羅テスト
void
MPU680x0Test::test_ea_ix()
{
	uint32 ea;
	struct {
		uint16 ext;		// 拡張ワード
		int exp_pc;		// 何ワード読まれるべきかの期待値1(extを含む)
		uint32 exp_ea;	// 期待値
		const char *name;
	} table[] = {
#if 1
#include "testea.h"
#endif
	};

	uint32 An = 0x00010000;
	cpu->reg.D[1] = 0x00100010;

	for (int i = 0; i < countof(table); i++) {
		g_fetch_ptr = 0;
		g_fetch[g_fetch_ptr++] = table[i].ext;
		// bd
		switch ((table[i].ext >> 4) & 3) {
		 case 0:
		 case 1:
			break;
		 case 2:
			g_fetch[g_fetch_ptr++] = 0x0100;
			break;
		 case 3:
			g_fetch[g_fetch_ptr++] = 0x0100;
			g_fetch[g_fetch_ptr++] = 0x0200;
			break;
		}
		// od
		switch (table[i].ext & 3) {
		 case 0:
		 case 1:
			break;
		 case 2:
			g_fetch[g_fetch_ptr++] = 0x1000;
			break;
		 case 3:
			g_fetch[g_fetch_ptr++] = 0x1000;
			g_fetch[g_fetch_ptr++] = 0x2000;
			break;
		}
		g_fetch_ptr = 0;

		tested++;
		printf("test_ea_ix[0x%04x] %-20s ", table[i].ext, table[i].name);
		ea = internal_ea_ix(An);
		if (table[i].exp_pc != g_fetch_ptr) {
			printf("FAILED! pc expects %d but %d\n",
				table[i].exp_pc, g_fetch_ptr);
			failed++;
			continue;
		}
		if (table[i].exp_ea != ea) {
			printf("FAILED! ea expects %x but %x\n",
				table[i].exp_ea, ea);
			printf(" 0x%04x .. WL=%d SC=%d BS=%d IS=%d BDSZ=%d IIS=%d\n",
				table[i].ext,
				(table[i].ext >> 11) & 1,
				(table[i].ext >>  9) & 3,
				(table[i].ext >>  7) & 1,
				(table[i].ext >>  6) & 1,
				(table[i].ext >>  4) & 3,
				(table[i].ext      ) & 7);
			failed++;
			continue;
		}
		printf("ok\n");
	}
}

static const char *scalestr[] = {
	"", "*2", "*4", "*8"
};

// 拡張 EA Full format の指定パターンのテストを生成する。
static void
make_ea_ix_full(int wl, int scale, int bs, int is, int bdsz, int iis)
{
	uint32 data;
	uint32 an = 0x00010000;
	uint32 xn = 0;
	uint32 bd = 0;
	uint32 od = 0;
	int cnt = 1;

	if (bs) {
		an = 0;
	}

	if (!is) {
		xn = 0x00100010;
		if (wl == 0) xn &= 0xffff;
		xn <<= scale;
	}

	if (bdsz == 2) {
		bd = 0x00000100; cnt+=1;
	} else if (bdsz == 3) {
		bd = 0x01000200; cnt+=2;
	}

	switch (iis & 3) {
	 case 2:
		od = 0x00001000; cnt += 1;	break;
	 case 3:
		od = 0x10002000; cnt += 2;	break;
	}

	data = 0;
	if (is == 0) {
		switch (iis) {
		 case 0: data = an + bd + xn;	break;
		 case 1:
		 case 2:
		 case 3:
				data = ((an + bd + xn) << 1) + od;	break;
		 case 4:
			return;
		 case 5:
		 case 6:
		 case 7:
				data = ((an + bd) << 1) + xn + od;	break;
		}
	} else {
		switch (iis) {
		 case 0: data = an + bd;	break;
		 case 1:
		 case 2:
		 case 3:
				data = ((an + bd) << 1) + od;	break;
		 default:
			return;
		}
	}

	printf("\t\t{ 0x%04x, %d, 0x%08x, \"(",
		(0x1100 + (wl<<11) + (scale<<9) + (bs<<7) + (is << 6) + (bdsz<<4)+ iis),
		cnt,
		data);
	char anbuf[16];
	char xnbuf[16];
	char bdbuf[16];
	char odbuf[16];
	anbuf[0] = '\0';
	xnbuf[0] = '\0';
	bdbuf[0] = '\0';
	odbuf[0] = '\0';
	if (bdsz == 2)
		snprintf(bdbuf, sizeof(bdbuf), "bd.W");
	else if (bdsz == 3)
		snprintf(bdbuf, sizeof(bdbuf), "bd.L");
	if (bs == 0)
		snprintf(anbuf, sizeof(anbuf), "An");
	if (is == 0) {
		snprintf(xnbuf, sizeof(xnbuf),
			"Xn.%c%s", (wl?'L':'W'), scalestr[scale]);
	}
	if ((iis & 3) == 2)
		snprintf(odbuf, sizeof(odbuf), "od.W");
	else if ((iis & 3) == 3)
		snprintf(odbuf, sizeof(odbuf), "od.L");

	if (is == 0) {
		switch (iis) {
		 case 0: printf("%s,%s,%s", anbuf, bdbuf, xnbuf);	break;
		 case 1: printf("[%s,%s,%s]", anbuf, bdbuf, xnbuf);	break;
		 case 2: printf("[%s,%s,%s],od.W", anbuf, bdbuf, xnbuf);	break;
		 case 3: printf("[%s,%s,%s],od.L", anbuf, bdbuf, xnbuf);	break;
		 case 4: printf("reserved");	break;
		 case 5: printf("[%s,%s],%s", anbuf, bdbuf, xnbuf);	break;
		 case 6: printf("[%s,%s],%s,od.W", anbuf, bdbuf, xnbuf);	break;
		 case 7: printf("[%s,%s],%s,od.L", anbuf, bdbuf, xnbuf);	break;
		}
	} else {
		switch (iis) {
		 case 0: printf("%s,%s", anbuf, bdbuf);	break;
		 case 1: printf("[%s,%s]", anbuf, bdbuf);	break;
		 case 2: printf("[%s,%s],od.W", anbuf, bdbuf);	break;
		 case 3: printf("[%s,%s],od.L", anbuf, bdbuf);	break;
		 default: printf("reserved");	break;
		}
	}

	printf(")\" },\n");
}

// 拡張 EA 全パターンのテストを生成する。
static void
make_ea_ix()
{
	// Brief format
	for (int wl = 0; wl <= 1; wl++) {
		for (int scale=0; scale <= 3; scale++) {
			uint32 an = 0x00010000;
			uint32 d8 = 1;
			uint32 data;
			uint32 xn;
			xn = 0x00100010;
			if (wl == 0) xn &= 0xffff;
			xn <<= scale;
			data = an + xn + d8;

			printf("\t\t{ 0x%04x, 1, 0x%08x, \"d8(An,D1.%c%s)\" },\n",
				0x1000 + (wl << 11) + (scale << 9) + d8,
				data,
				wl ? 'L' : 'W',
				scalestr[scale]);
		}
	}

	// Full format
	for (int wl=0; wl<= 1; wl++) {
		for (int scale=0; scale<=3; scale++) {
			for (int bs = 0; bs <= 1; bs++) {
				for (int is = 0; is <= 1; is++) {
					for (int bdsz = 1; bdsz <= 3; bdsz++) {
						for (int iis = 0; iis < 8; iis++) {
							make_ea_ix_full(wl, scale, bs, is, bdsz, iis);
						}
					}
				}
			}
		}
	}
}

// 符号拡張のテスト。
// 符号拡張が起きるのは xn.W, bd.W, od.W の3か所。
void
MPU680x0Test::test_ea_ix2()
{
	struct {
		uint16 ext;			// 拡張ワード
		uint32 exp_ea;		// 期待値
		const char *name;
	} table[] = {
		{ 0x1122,	0x00020000, "([An,bd.W,Xn.W],od.W)" },
		{ 0x1126,	0x00020010, "([An,bd.W],Xn.W,od.W)" },
		{ 0x1162,	0x00020020, "([An,bd.W],od.W)" },
	};

	uint32 An = 0x00011110;
	cpu->reg.D[1] = 0x0000fff0;	// -0x0010.W
	for (int i = 0; i < countof(table); i++) {
		g_fetch[0] = table[i].ext;
		g_fetch[1] = 0xff00;	// -0x0100.W
		g_fetch[2] = 0xe000;	// -0x2000.W
		g_fetch_ptr = 0;

		tested++;
		printf("test_ea_ix2[0x%04x] %-20s ", table[i].ext, table[i].name);
		uint32 ea = internal_ea_ix(An);
		if (table[i].exp_ea != ea) {
			printf("FAILED! ea expects %08x but %08x\n",
				table[i].exp_ea, ea);
			printf(" 0x%04x .. WL=%d SC=%d BS=%d IS=%d BDSZ=%d IIS=%d\n",
				table[i].ext,
				(table[i].ext >> 11) & 1,
				(table[i].ext >>  9) & 3,
				(table[i].ext >>  7) & 1,
				(table[i].ext >>  6) & 1,
				(table[i].ext >>  4) & 3,
				(table[i].ext      ) & 7);
			failed++;
			continue;
		}
		printf("ok\n");
	}
}

int
main(int ac, char *av[])
{
	cpu = new MPU680x0Test();

	// 引数が何かあればテストパターン生成、なければテスト。
	// XXX そのうち整備する。
	if (ac > 1) {
		make_ea_ix();
	} else {
		tested = 0;
		failed = 0;

		cpu->test_ea_ix();
		cpu->test_ea_ix2();

		printf("RESULT: %d tested, %d success", tested, tested - failed);
		if (failed > 0)
			printf(", %d failed", failed);
		printf("\n");
	}

	return 0;
}

unix.superglobalmegacorp.com

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