--- nono/vm/videoctlr.cpp 2026/04/29 17:04:36 1.1 +++ nono/vm/videoctlr.cpp 2026/04/29 17:05:14 1.1.1.7 @@ -4,7 +4,9 @@ // Licensed under nono-license.txt // -#include "videoctlr.h" +// +// ビデオコントローラ +// // e82000..e823ff パレット // e82400..e824ff R0(e82400.w) のミラー @@ -13,40 +15,57 @@ // e82700..e82fff $00 が読めるようだ // 以上の 4KB をミラー。 -std::unique_ptr gVideoCtlr; +#include "videoctlr.h" +#include "mpu.h" +#include "renderer.h" +#include "uimessage.h" + +// グローバル参照用 +VideoCtlrDevice *gVideoCtlr; +// コンストラクタ VideoCtlrDevice::VideoCtlrDevice() + : inherited("VideoCtlr") { - logname = "videoctlr"; - devname = "VideoCtlr"; devaddr = baseaddr; devlen = 0x2000; } +// デストラクタ VideoCtlrDevice::~VideoCtlrDevice() { + gVideoCtlr = NULL; } -// addr は何ワード目のポートかという意味になるので -// $E82002 が addr=1 (番目のワード)。 +// リセット +void +VideoCtlrDevice::ResetHard(bool poweron) +{ + // XXX not yet +} + +// offset は何ワード目のポートかという意味になるので +// $E82002 が offset=1 (番目のワード)。 uint64 -VideoCtlrDevice::Read(uint32 addr) +VideoCtlrDevice::Read(uint32 offset) { uint32 data; - if (addr < 0x400 / 2) { // パレット - data = palette.w[addr]; + gMPU->AddCycle(9); // InsideOut p.135 + + if (offset < 0x400 / 2) { // パレット + data = palette.w[offset]; - } else if (addr < 0x500 / 2) { // $E82400 (R0) + } else if (offset < 0x500 / 2) { // $E82400 (R0) data = videoctlr.r0; - } else if (addr < 0x600 / 2) { // $E82500 (R1) + } else if (offset < 0x600 / 2) { // $E82500 (R1) data = videoctlr.r1; - } else if (addr < 0x700 / 2) { // $E82600 (R2) + } else if (offset < 0x700 / 2) { // $E82600 (R2) data = videoctlr.r2; - } else { // それ以降は $00 が読めるようだ + } else { // それ以降は $00 が読めるようだ data = 0; } @@ -54,45 +73,48 @@ VideoCtlrDevice::Read(uint32 addr) } uint64 -VideoCtlrDevice::Write(uint32 addr, uint32 data) +VideoCtlrDevice::Write(uint32 offset, uint32 data) { - if (addr < 0x400 / 2) { // パレット - putlog(3, "パレット $%06x.W <- $%04x", baseaddr + addr * 2, data); - palette.w[addr] = data; + gMPU->AddCycle(11); // InsideOut p.135 - } else if (addr < 0x500 / 2) { // $E82400 (R0) + if (offset < 0x400 / 2) { // パレット + putlog(3, "Palette $%06x.W <- $%04x", baseaddr + offset * 2, data); + palette.w[offset] = data; + MakePalette(); + + } else if (offset < 0x500 / 2) { // $E82400 (R0) SetR0(data); - } else if (addr < 0x600 / 2) { // $E82500 (R1) + } else if (offset < 0x600 / 2) { // $E82500 (R1) SetR1(data); - } else if (addr < 0x700 / 2) { // $E82600 (R2) + } else if (offset < 0x700 / 2) { // $E82600 (R2) SetR2(data); - } else { // それ以降はたぶん何も起きない? + } else { // それ以降はたぶん何も起きない? } return 0; } uint64 -VideoCtlrDevice::Peek(uint32 addr) +VideoCtlrDevice::Peek(uint32 offset) { uint32 data; - if (addr < 0x400 / 2) { // パレット - data = palette.w[addr]; + if (offset < 0x400 / 2) { // パレット + data = palette.w[offset]; - } else if (addr < 0x500 / 2) { // $E82400 (R0) + } else if (offset < 0x500 / 2) { // $E82400 (R0) data = videoctlr.r0; - } else if (addr < 0x600 / 2) { // $E82500 (R1) + } else if (offset < 0x600 / 2) { // $E82500 (R1) data = videoctlr.r1; - } else if (addr < 0x700 / 2) { // $E82600 (R2) + } else if (offset < 0x700 / 2) { // $E82600 (R2) data = videoctlr.r2; - } else { // それ以降は $00 が読めるようだ + } else { // それ以降は $00 が読めるようだ data = 0; } @@ -103,7 +125,7 @@ VideoCtlrDevice::Peek(uint32 addr) void VideoCtlrDevice::SetR0(uint32 data) { - putlog(0, "R0 <- $%04x 未実装書き込み", data); + putlog(0, "R0 <- $%04x (NOT IMPLEMENTED)", data); videoctlr.r0 = data & 3; } @@ -111,7 +133,7 @@ VideoCtlrDevice::SetR0(uint32 data) void VideoCtlrDevice::SetR1(uint32 data) { - putlog(0, "R1 <- $%04x 未実装書き込み", data); + putlog(0, "R1 <- $%04x (NOT IMPLEMENTED)", data); videoctlr.r1 = data & 0x3fff; } @@ -119,6 +141,35 @@ VideoCtlrDevice::SetR1(uint32 data) void VideoCtlrDevice::SetR2(uint32 data) { - putlog(0, "R2 <- $%04x 未実装書き込み", data); + putlog(0, "R2 <- $%04x (NOT IMPLEMENTED)", data); videoctlr.r2 = (data & 0xff7f); } + +// +void +VideoCtlrDevice::MakePalette() +{ + const uint16 *p; + + // パレット前半 256 ワードはグラフィックパレット、 + // テキストパレットは後半。 + p = &palette.w[256]; + + // パレット情報から Color 形式の色データを作成 + // X680x0 のパレットは %GGGGG'RRRRR'BBBBB'I で並んでいる。 + for (int i = 0; i < 16; i++) { + int I = (p[i] & 1) << 2; // 輝度ビット + int R = (((p[i] >> 6) & 0x1f) << 3) + I; + int G = (((p[i] >> 11)) << 3) + I; + int B = (((p[i] >> 1) & 0x1f) << 3) + I; + cooked_palette[i].r = R; + cooked_palette[i].g = G; + cooked_palette[i].b = B; + } + + // パレット変更が起きたことをレンダラに通知 + gRenderer->Invalidate2(); + + // UI にも通知 + UIMessage::Post(UIMessage::PALETTE); +}