--- nono/vm/tvram.cpp 2026/04/29 17:05:14 1.1.1.8 +++ nono/vm/tvram.cpp 2026/04/29 17:05:18 1.1.1.9 @@ -17,16 +17,17 @@ // コンストラクタ TVRAMDevice::TVRAMDevice() - : inherited("TVRAM", 1024, 1024) + : inherited(1024, 1024) { - devaddr = baseaddr; - devlen = 512 * 1024; + SetName("TVRAM"); + ClearAlias(); + AddAlias("TVRAM"); + + uint devlen = 512 * 1024; // プレーン数は4枚固定 nplane = NPLANE; - modify_mask = 0xff00; - mem.reset(new uint8[devlen]); } @@ -35,11 +36,19 @@ TVRAMDevice::~TVRAMDevice() { } +// 初期化 bool TVRAMDevice::Init() { + if (inherited::Init() == false) { + return false; + } + + renderer = GetRenderer(); + auto videoctlr = GetVideoCtlrDevice(); + // 加工済みパレットを取得 - palette = gVideoCtlr->GetHostPalette(); + palette = &(videoctlr->GetHostPalette())[0]; return true; } @@ -61,7 +70,7 @@ TVRAMDevice::Decoder(uint32 addr) const uint64 TVRAMDevice::Read8(uint32 addr) { - gMPU->AddCycle(9); // Inside/Out p.135 + mpu->AddCycle(9); // Inside/Out p.135 uint32 offset = Decoder(addr); return mem[HLB(offset)]; } @@ -69,7 +78,7 @@ TVRAMDevice::Read8(uint32 addr) uint64 TVRAMDevice::Read16(uint32 addr) { - gMPU->AddCycle(9); // Inside/Out p.135 + mpu->AddCycle(9); // Inside/Out p.135 uint32 offset = Decoder(addr); return *(uint16 *)&mem[HLW(offset)]; } @@ -81,7 +90,7 @@ TVRAMDevice::Write8(uint32 addr, uint32 uint8 *ptr; uint8 mask8; - gMPU->AddCycle(9); // Inside/Out p.135 + mpu->AddCycle(9); // Inside/Out p.135 // XXX とりあえずね putlog(3, "Write $%06x.B <- $%02x", addr, data); @@ -96,9 +105,9 @@ TVRAMDevice::Write8(uint32 addr, uint32 mask8 = 0; } + uint32 poffset = offset & 0x1ffff; if (tvram.sa) { // 同時アクセス - uint32 poffset = offset & 0x1ffff; for (int plane = 0; plane < 4; plane++) { if (tvram.ap[plane]) { ptr = &mem[HLB(0x20000 * plane + poffset)]; @@ -110,7 +119,7 @@ TVRAMDevice::Write8(uint32 addr, uint32 ptr = &mem[HLB(offset)]; *ptr = (data & ~mask8) | (*ptr & mask8); } - SetDirty(offset); + SetDirty(poffset); return 0; } @@ -121,7 +130,7 @@ TVRAMDevice::Write16(uint32 addr, uint32 uint16 *ptr; uint16 mask16; - gMPU->AddCycle(9); // Inside/Out p.135 + mpu->AddCycle(9); // Inside/Out p.135 // XXX とりあえずね putlog(3, "Write $%06x.W <- $%04x", addr, data); @@ -132,9 +141,9 @@ TVRAMDevice::Write16(uint32 addr, uint32 mask16 = 0; } + uint32 poffset = offset & 0x1ffff; if (tvram.sa) { // 同時アクセス - uint32 poffset = offset & 0x1ffff; for (int plane = 0; plane < 4; plane++) { if (tvram.ap[plane]) { ptr = (uint16 *)&mem[HLW(0x20000 * plane + poffset)]; @@ -146,7 +155,7 @@ TVRAMDevice::Write16(uint32 addr, uint32 ptr = (uint16 *)&mem[HLW(offset)]; *ptr = (data & ~mask16) | (*ptr & mask16); } - SetDirty(offset); + SetDirty(poffset); return 0; } @@ -157,46 +166,50 @@ TVRAMDevice::Peek8(uint32 addr) return mem[HLB(offset)]; } +uint64 +TVRAMDevice::Poke8(uint32 addr, uint32 data) +{ + if ((int32)data >= 0) { + uint32 offset = Decoder(addr); + uint32 poffset = offset & 0x1ffff; + mem[HLB(offset)] = data; + // この場合も画面を更新する + SetDirty(poffset); + } + return 0; +} + // offset の位置に対応する更新フラグを立てる。 -// offset は TVRAM 先頭からのバイトオフセット (プレーン先頭からではない)。 +// offset はプレーン先頭からのバイトオフセット。 inline void TVRAMDevice::SetDirty(uint32 offset) { - // VRAM は横 1024 ドット(128バイト) x 縦 1024 ドットで、これを - // 横 128 ドット(16バイト) x 縦 16 ドットずつのブロックに分割する。 - // ブロック数は横 8個 x 縦 64個。 + // VRAM は横 1024 ドット(128バイト) x 縦 1024 ドット。 // // 1 0 // 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0 // +-----------+-------+-----+-------+-----+ // VRAM | Y座標 (1024dot) | X (128byte) : 8bit| // +-----------+-------+-----+-------+-----+ - // : : : : : - // +-----------+-------+-----+-------------+ - // Block | Y(64blks) | 16dot | X(8)| 128 dot | *: X は 8 blocks - // +-----------+-------+-----+-------------+ - // \ \ | | - // \ \ | | - // \ \ | | - // +-----------+-----+ - // Dirty | Y(64blks) | X(8)| - // +-----------+-----+ - // 8 7 6 5 4 3 2 1 0 - - // x 座標(バイト単位 7 bit)の上位 3 bit - int x = (offset >> 4) & 0x07; - // y 座標(10bit) の上位 6 bit - int y = (offset >> 8) & 0x1f8; - - // からインデックスを求める - int b = x + y; - - dirty[b] = 1; - -#if defined(PERF_HIT) - // どのロングワードが更新されたか - dirty_word[(offset & 0x1ffff) >> 2] = true; -#endif + // : : + // +-------------------+ + // Dirty | | + // +-------------------+ + // 9 8 7 6 5 4 3 2 1 0 + + // 更新フラグはラスタ単位 + int y = offset >> 7; + dirty[y] = 1; +} + +// X 方向にはみ出したときに対応する仮想画面の Y 座標を返す。 +int +TVRAMDevice::GetWrapY(int y) const +{ + // はみ出すと次のラスタの先頭から表示するが、 + // TVRAM は 4 ラスタがひとかたまりで構成されていて、 + // 末尾 2bit が 3 のラスタの次は、末尾だけ 0 のラスタに戻る。ようだ。 + return (y & ~3) + ((y + 1) & 3); } void @@ -209,7 +222,7 @@ void TVRAMDevice::SetScrollY(int y) { yscroll = y; - gRenderer->Invalidate2(); + renderer->Invalidate2(); } // CRTC R21 での同時アクセス設定を反映する。 @@ -263,23 +276,60 @@ TVRAMDevice::RasterCopy(int src_ras, int } // dst からの4ラインを全部 dirty にする。 -#if !defined(PERF_HIT) - // dirty は、1ブロックが縦 16dot 収容しているので、4の倍数から始まる - // 4ラインは必ず1ブロックに収まる。横方向は1ブロックにつき 128dot 収容して - // いるので全部で8ブロック。 - // よって dirty を立てるだけなら 8回の呼び出しで済む。 - for (int x = 0; x < 8; x++) { - SetDirty(dst_ras * 128 + (x << 4)); + for (int y = 0; y < 4; y++) { + SetDirty((dst_ras + y) * 128); } -#else - // PERF_HIT の更新を行う場合は律儀に全プレーンの全ロングワード分ループする - for (int plane = 0; plane < 4; plane++) { - for (int i = 0; i < 4; i++) { - int y = dst_ras + i; - for (int x = 0; x < 128 / sizeof(uint32); x++) { - SetDirty(0x20000 * plane + y * 128 + x * sizeof(uint32)); - } +} + +// (x, y) 位置のピクセル情報を screen に描画。(ビットマップモニタの情報欄) +void +TVRAMDevice::UpdateInfo(TextScreen& screen, int x, int y) const +{ + screen.Clear(); + + //0 1 2 3 4 5 6 + //012345678901234567890123456789012345678901234567890123456789012345 + //X=1024 Y=2024: (P0) $e01234: $00 (%00000000) ColorCode=$d + + screen.Puts(0, 0, "X= Y="); + for (int i = 0; i < nplane; i++) { + screen.Print(15, i, "(P%d)", i); + } + + // カーソルが範囲外ならここまで。 + if (x < 0) { + return; + } + + screen.Print(2, 0, "%4d Y=%4d", x, y); + + // 1プレーン内のバイトオフセット + uint32 planeoffset = ((uint)y * 128) + ((uint)x / 8); + + uint cc = 0; + for (int i = 0; i < nplane; i++) { + // プレーン0先頭からのバイトオフセット + uint32 totaloffset = 0x20000 * i + planeoffset; + + uint8 data = mem[HLB(totaloffset)]; + screen.Print(15, i, "(P%d) $%06x: $%02x (%%", + i, baseaddr + totaloffset, data); + + // ビットパターン + for (int m = 0x80; m != 0; m >>= 1) { + screen.Putc((data & m) ? '1' : '0'); + } + screen.Putc(')'); + + // カーソル位置をハイライト + screen.Locate(35 + (x % 8), i); + screen.SetAttr(TA::Em); + + // カラーコードを計算 + if ((data & (0x80U >> (x % 8))) != 0) { + cc |= (1U << i); } } -#endif + + screen.Print(45, 0, "ColorCode=$%x", cc); }