--- nono/vm/bt454.cpp 2026/04/29 17:04:35 1.1.1.3 +++ nono/vm/bt454.cpp 2026/04/29 17:05:10 1.1.1.7 @@ -4,75 +4,101 @@ // Licensed under nono-license.txt // -#include "bt454.h" -#include "bitmap.h" -#include "mpu.h" +// +// 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) -std::unique_ptr gBT454; +// グローバル参照用 +BT454Device *gBT454; +// コンストラクタ BT454Device::BT454Device() + : inherited("BT454") { - logname = "bt454"; - devname = "BT454"; devaddr = 0xc1000000; } +// デストラクタ BT454Device::~BT454Device() { + gBT454 = NULL; } bool BT454Device::Init() { - nplane = gBitmap->GetPlaneCount(); + nplane = gPlaneVRAM->GetPlaneCount(); + assert(nplane >= 0); return true; } +// リセット void -BT454Device::ResetHard() +BT454Device::ResetHard(bool poweron) { - reg.addr = 0; + 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 addr) +BT454Device::Read(uint32 offset) { uint32 data; - switch (addr) { + switch (offset) { case 0: // アドレスレジスタ - // 今の(今からアクセスする)パレット番号 - data = reg.addr / 3; + // 今の(今からアクセスする)パレット番号を返す。 + data = reg.idx / 3; data = (data << 4) | LOW_NIBBLE; - putlog(2, "アドレスレジスタ -> $%02x", data); + putlog(2, "Address Register -> $%02x", data); + // アドレスレジスタアクセスで ab カウンタは 0 にリセットされる + reg.idx = (reg.idx / 3) * 3; break; - case 1: // カラーマップレジスタ + case 1: // カラーパレットレジスタ // reg.color[] は上位4ビットが有効なのでそのまま読み出せる。 - data = reg.color[reg.addr]; - data |= LOW_NIBBLE; - putlog(2, "カラーマップ $%x(%c) -> $%02x", - reg.addr / 3, rgbstr[reg.addr % 3], data); + data = reg.color[reg.idx] | LOW_NIBBLE; + putlog(2, "Color Palette $%x(%c) -> $%02x", + reg.idx / 3, rgbstr[reg.idx % 3], data); // アクセスするたびにインクリメントする。 - reg.addr++; - if (reg.addr >= countof(reg.color)) { - reg.addr = 0; + 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, "未実装バイト読み込み $%08x", gMPU->GetPaddr()); + putlog(0, "未実装 overlay レジスタ読み込み"); data = 0xff; break; @@ -84,49 +110,55 @@ BT454Device::Read(uint32 addr) } uint64 -BT454Device::Write(uint32 addr, uint32 data) +BT454Device::Write(uint32 offset, uint32 data) { // 書き込みデータのうち有効なのは上位ニブルだけ - switch (addr) { + switch (offset) { case 0: // アドレスレジスタ - // 今からアクセスするパレット番号 - // data はパレット番号だが reg.addr は配列のインデックスなので 3倍。 - putlog(2, "アドレスレジスタ <- $%02x", data); - reg.addr = (data >> 4) * 3; + // 今からアクセスするパレット番号。 + // アドレスレジスタアクセスで ab カウンタは 0 にリセットされる。 + // data はパレット番号だが reg.idx は配列のインデックスなので 3倍。 + putlog(2, "Address Register <- $%02x", data); + reg.idx = (data >> 4) * 3; break; - case 1: // カラーマップレジスタ + case 1: // カラーパレットレジスタ // reg.color[] は上位4ビットが有効なのでそのまま書き込む。 // 下位4ビットはどうするか。 - reg.color[reg.addr] = (data & 0xf0); + reg.color[reg.idx] = (data & 0xf0); if (loglevel == 1) { // ログレベル1なら RGB が書き込まれた時点で表示。 // 大体はこれくらいの表示で構わないはず。 - if (reg.addr % 3 == 2) { - putlog("カラーマップ $%x = (%x,%x,%x)", - reg.addr / 3, - reg.color[reg.addr - 2] >> 4, - reg.color[reg.addr - 1] >> 4, - reg.color[reg.addr ] >> 4); + 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) { - putlog("カラーマップ $%x(%c) <- $%02x", - reg.addr / 3, rgbstr[reg.addr % 3], data); + putlogn("Color Palette $%x(%c) <- $%02x", + reg.idx / 3, rgbstr[reg.idx % 3], data); } // ホストカラーを計算。 - MakeHostColor(reg.addr); + MakeHostColor(reg.idx); // ホストカラー計算後にインクリメントする。 - reg.addr++; - if (reg.addr >= countof(reg.color)) { - reg.addr = 0; + 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, "未実装バイト書き込み $%08x <- %02x", gMPU->GetPaddr(), data); + putlog(0, "未実装 overlay レジスタ書き込み <- $%02x", data); break; default: @@ -136,43 +168,70 @@ BT454Device::Write(uint32 addr, uint32 d } uint64 -BT454Device::Peek(uint32 addr) +BT454Device::Peek(uint32 offset) { - switch (addr) { + uint8 data; + + switch (offset) { case 0: // アドレスレジスタ - // XXX 下位ニブルは? - return ((reg.addr / 3) << 4) | LOW_NIBBLE; + data = (reg.idx / 3) << 4; + break; - case 1: // カラーマップレジスタ + case 1: // カラーパレットレジスタ // 今読み出そうとしたら読み出せるやつ - return reg.color[reg.addr] | LOW_NIBBLE; + data = reg.color[reg.idx]; + break; case 2: + data = 0; + break; + case 3: // 未実装 - return 0xff; + data = 0xff; + break; default: __unreachable(); } + + return data | LOW_NIBBLE; } -// addr 番目のレジスタ値からホストパレットを作成。 +// idx 番目のレジスタ値からホストパレットを作成。 void -BT454Device::MakeHostColor(int addr) +BT454Device::MakeHostColor(int idx) { - int col = addr / 3; - int idx = addr % 3; + int col = idx / 3; + int ab = idx % 3; if (nplane == 1) { // 1bpp なら R,G,B のうち G の値だけを使用 - if (idx == 1) { - reg.hostcolor[col * 4 + 0] = reg.color[col * 3 + 1]; - reg.hostcolor[col * 4 + 1] = reg.color[col * 3 + 1]; - reg.hostcolor[col * 4 + 2] = reg.color[col * 3 + 1]; + 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 なら代入するだけ - reg.hostcolor[col * 4 + idx] = reg.color[col * 3 + idx]; + 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); }