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

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

//
// BT454
//

// 仕様書には $c100_0000 と書いてあるが、PROM も NetBSD カーネルも
// $c110_0000 にアクセスしている。実際には 4バイトごとにミラーが見えて
// いるので問題はない。
// LUNA88K でも1バイトずつ連続配置されている(BusIO_B)、LUNA88K の他の多くの
// デバイスのような BusIO_BFFF 配置でないので注意。

#include "bt454.h"
#include "planevram.h"
#include "renderer.h"
#include "uimessage.h"

// 下位ニブルは 0x0f が読めるようだ
#define LOW_NIBBLE	(0x0f)

// グローバル参照用
BT454Device *gBT454;

// コンストラクタ
BT454Device::BT454Device()
	: inherited("BT454")
{
	devaddr = 0xc1000000;
}

// デストラクタ
BT454Device::~BT454Device()
{
	gBT454 = NULL;
}

bool
BT454Device::Init()
{
	nplane = gPlaneVRAM->GetPlaneCount();
	assert(nplane >= 0);
	return true;
}

// リセット
void
BT454Device::ResetHard(bool poweron)
{
	reg.idx = 0;

	// XXX BT454 のレジスタの初期値は不明なのでとりあえず全部黒にしておく
	memset(reg.color, 0, countof(reg.color));
	for (int i = 0; i < countof(reg.color); i++) {
		MakeHostColor(i);
	}
}

/* static */ const char
BT454Device::rgbstr[3] = { 'R', 'G', 'B' };

uint64
BT454Device::Read(uint32 offset)
{
	uint32 data;

	switch (offset) {
	 case 0:	// アドレスレジスタ
		// 今の(今からアクセスする)パレット番号を返す。
		data = reg.idx / 3;
		data = (data << 4) | LOW_NIBBLE;
		putlog(2, "Address Register -> $%02x", data);
		// アドレスレジスタアクセスで ab カウンタは 0 にリセットされる
		reg.idx = (reg.idx / 3) * 3;
		break;

	 case 1:	// カラーパレットレジスタ
		// reg.color[] は上位4ビットが有効なのでそのまま読み出せる。
		data = reg.color[reg.idx] | LOW_NIBBLE;
		putlog(2, "Color Palette $%x(%c) -> $%02x",
			reg.idx / 3, rgbstr[reg.idx % 3], data);
		// アクセスするたびにインクリメントする。
		reg.idx++;
		if (reg.idx >= countof(reg.color)) {
			reg.idx = 0;
		}
		break;

	 case 2:
		// ADDRa,b を 0 にする? D0-D3 は 0 になる??
		// データシートが雑でよく分からん…
		reg.idx = (reg.idx / 3) * 3;
		data = 0x00 | LOW_NIBBLE;
		putlog(2, "reset ab");
		break;

	 case 3:
		putlog(0, "Read Overlay Register (NOT IMPLEMENTED)");
		data = 0xff;
		break;

	 default:
		__unreachable();
	}

	return data;
}

uint64
BT454Device::Write(uint32 offset, uint32 data)
{
	// 書き込みデータのうち有効なのは上位ニブルだけ

	switch (offset) {
	 case 0:	// アドレスレジスタ
		// 今からアクセスするパレット番号。
		// アドレスレジスタアクセスで ab カウンタは 0 にリセットされる。
		// data はパレット番号だが reg.idx は配列のインデックスなので 3倍。
		putlog(2, "Address Register <- $%02x", data);
		reg.idx = (data >> 4) * 3;
		break;

	 case 1:	// カラーパレットレジスタ
		// reg.color[] は上位4ビットが有効なのでそのまま書き込む。
		// 下位4ビットはどうするか。
		reg.color[reg.idx] = (data & 0xf0);
		if (loglevel == 1) {
			// ログレベル1なら RGB が書き込まれた時点で表示。
			// 大体はこれくらいの表示で構わないはず。
			if (reg.idx % 3 == 2) {
				putlogn("Color Palette $%x = (%x,%x,%x)",
					reg.idx / 3,
					reg.color[reg.idx - 2] >> 4,
					reg.color[reg.idx - 1] >> 4,
					reg.color[reg.idx    ] >> 4);
			}
		} else if (loglevel >= 2) {
			putlogn("Color Palette $%x(%c) <- $%02x",
				reg.idx / 3, rgbstr[reg.idx % 3], data);
		}
		// ホストカラーを計算。
		MakeHostColor(reg.idx);

		// ホストカラー計算後にインクリメントする。
		reg.idx++;
		if (reg.idx >= countof(reg.color)) {
			reg.idx = 0;
		}
		break;

	 case 2:
		// ab カウンタを 0 にする? データは無視されるようだ
		reg.idx = (reg.idx / 3) * 3;
		putlog(2, "reset ab");
		break;

	 case 3:
		putlog(0, "Overlay Register <- $%02x (NOT IMPLEMENTED)", data);
		break;

	 default:
		__unreachable();
	}
	return 0;
}

uint64
BT454Device::Peek(uint32 offset)
{
	uint8 data;

	switch (offset) {
	 case 0:	// アドレスレジスタ
		data = (reg.idx / 3) << 4;
		break;

	 case 1:	// カラーパレットレジスタ
		// 今読み出そうとしたら読み出せるやつ
		data = reg.color[reg.idx];
		break;

	 case 2:
		data = 0;
		break;

	 case 3:
		// 未実装
		data = 0xff;
		break;

	 default:
		__unreachable();
	}

	return data | LOW_NIBBLE;
}

// idx 番目のレジスタ値からホストパレットを作成。
void
BT454Device::MakeHostColor(int idx)
{
	int col = idx / 3;
	int ab  = idx % 3;

	if (nplane == 1) {
		// 1bpp なら R,G,B のうち G の値だけを使用
		if (ab == 1) {
			reg.hostcolor[col].r = reg.color[col * 3 + 1];
			reg.hostcolor[col].g = reg.color[col * 3 + 1];
			reg.hostcolor[col].b = reg.color[col * 3 + 1];
		}
	} else {
		// 4bpp なら代入するだけ
		switch (ab) {
		 case 0:
			reg.hostcolor[col].r = reg.color[col * 3 + ab];
			break;
		 case 1:
			reg.hostcolor[col].g = reg.color[col * 3 + ab];
			break;
		 case 2:
			reg.hostcolor[col].b = reg.color[col * 3 + ab];
			break;
		 default:
			__unreachable();
		}
	}

	// パレット変更が起きたことをレンダラに通知
	gRenderer->Invalidate2();

	// UI にも通知
	UIMessage::Post(UIMessage::PALETTE);
}

unix.superglobalmegacorp.com

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