|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: //
8: // GVRAM
9: //
1.1.1.6 root 10:
1.1 root 11: // GVRAM はワード単位でホストバイトオーダ配置なので、
12: // バイトアクセス時は HB() マクロを使用のこと。
13:
1.1.1.6 root 14: #include "gvram.h"
1.1.1.11! root 15: #include "event.h"
! 16: #include "textscreen.h"
1.1.1.6 root 17: #include "videoctlr.h"
18:
1.1.1.8 root 19: // InsideOut p.135
1.1.1.11! root 20: /*static*/ const busdata
! 21: GVRAMDevice::wait = busdata::Wait(9 * 40_nsec);
1.1.1.8 root 22:
1.1.1.6 root 23: // コンストラクタ
1.1 root 24: GVRAMDevice::GVRAMDevice()
1.1.1.7 root 25: : inherited(OBJ_GVRAM)
1.1 root 26: {
1.1.1.11! root 27: composite.Create(1024, 1024);
1.1 root 28: }
29:
1.1.1.6 root 30: // デストラクタ
1.1 root 31: GVRAMDevice::~GVRAMDevice()
32: {
33: }
34:
1.1.1.10 root 35: // 初期化
36: bool
37: GVRAMDevice::Init()
38: {
39: uint devlen = 0x20'0000; // XXX とりあえず
40: mem.reset(new(std::nothrow) uint8[devlen]);
41: if ((bool)mem == false) {
42: warnx("Cannot allocate %u bytes at %s", devlen, __method__);
43: return false;
44: }
45:
1.1.1.11! root 46: videoctlr = GetVideoCtlrDevice();
! 47:
! 48: // 加工済みグラフィックパレットを取得。
! 49: palette = &(videoctlr->GetHostPalette())[0];
! 50:
1.1.1.10 root 51: return true;
52: }
53:
1.1.1.11! root 54: void
! 55: GVRAMDevice::ResetHard(bool poweron)
! 56: {
! 57: // XXX ここ?
! 58: Invalidate();
! 59: }
! 60:
! 61: // 全画面の更新フラグを立てる。
! 62: void
! 63: GVRAMDevice::Invalidate()
! 64: {
! 65: dirty.line.set();
! 66: }
! 67:
1.1.1.9 root 68: inline uint32
69: GVRAMDevice::Decoder(uint32 addr) const
1.1 root 70: {
1.1.1.9 root 71: return addr - baseaddr;
1.1 root 72: }
73:
1.1.1.8 root 74: busdata
1.1.1.9 root 75: GVRAMDevice::Read(busaddr addr)
1.1 root 76: {
1.1.1.9 root 77: uint32 offset = Decoder(addr.Addr());
1.1.1.8 root 78: busdata data;
1.1.1.9 root 79:
80: data = *(uint16 *)&mem[offset & ~1U];
1.1.1.8 root 81: data |= wait;
1.1.1.9 root 82: data |= BusData::Size2;
1.1.1.8 root 83: return data;
1.1 root 84: }
85:
1.1.1.8 root 86: busdata
1.1.1.9 root 87: GVRAMDevice::Write(busaddr addr, uint32 data)
1.1 root 88: {
1.1.1.9 root 89: uint32 offset = Decoder(addr.Addr());
90: uint32 reqsize = addr.GetSize();
91: uint32 datasize = std::min(2 - (offset & 1U), reqsize);
92: data >>= (reqsize - datasize) * 8;
93:
1.1.1.11! root 94: // 現状 1024x1024 (4bit) しか対応していない。
! 95: if (__predict_false(datasize == 1)) {
! 96: if ((offset & 1) != 0) {
! 97: mem[HB(offset)] = data & 0x0f;
! 98: }
1.1.1.9 root 99: } else {
1.1.1.11! root 100: *(uint16 *)&mem[offset] = data & 0x0f;
1.1.1.9 root 101: }
1.1.1.11! root 102: SetDirty(offset);
1.1.1.9 root 103:
104: busdata r = wait;
105: r |= busdata::Size(datasize);
106: return r;
1.1 root 107: }
108:
1.1.1.8 root 109: busdata
1.1.1.9 root 110: GVRAMDevice::Peek1(uint32 addr)
1.1 root 111: {
1.1.1.9 root 112: uint32 offset = Decoder(addr);
113: return mem[HB(offset)];
1.1 root 114: }
1.1.1.11! root 115:
! 116: bool
! 117: GVRAMDevice::Poke1(uint32 addr, uint32 data)
! 118: {
! 119: if ((int32)data >= 0) {
! 120: uint32 offset = Decoder(addr);
! 121: // 現状 1024x1024 モードしか対応していないため
! 122: // 有効なのはワード中下位4ビット。
! 123: if ((offset & 1) != 0) {
! 124: mem[HB(offset)] = data & 0x0f;
! 125: // この場合も画面を更新する。
! 126: SetDirty(offset);
! 127: }
! 128: }
! 129: return true;
! 130: }
! 131:
! 132: // offset の位置に対応する更新フラグを立てる。
! 133: // offset はページ先頭からのバイトオフセット。
! 134: inline void
! 135: GVRAMDevice::SetDirty(uint32 offset)
! 136: {
! 137: // GVRAM (1024x1024 モード) は
! 138: // 横 1024 ドット(2048バイト) x 縦 1024 ドット。
! 139: //
! 140: // 1 0
! 141: // 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
! 142: // +-------------------+---------------------+
! 143: // GVRAM | Y座標 (1024dot) | X座標 (1024word) |
! 144: // +-------------------+---------------------+
! 145: // : :
! 146: // +-------------------+
! 147: // | |
! 148: // +-------------------+
! 149: // 9 8 7 6 5 4 3 2 1 0
! 150:
! 151: // 更新フラグはラスタ単位
! 152: uint y = offset >> 11;
! 153: dirty.line.set(y);
! 154: }
! 155:
! 156: // 画面更新する必要があるか。
! 157: // VM スレッドで呼ばれる。
! 158: bool
! 159: GVRAMDevice::Snap()
! 160: {
! 161: bool update_needed;
! 162:
! 163: // 更新 (dirty) があれば pending に重ねる。
! 164: {
! 165: std::lock_guard<std::mutex> lock(mtx);
! 166: pending.line |= dirty.line;
! 167: dirty.line.reset();
! 168:
! 169: if (__predict_false(dirty.invalidate2)) {
! 170: pending.invalidate2 = true;
! 171: dirty.invalidate2 = false;
! 172: }
! 173:
! 174: update_needed = pending.line.any() || pending.invalidate2;
! 175: }
! 176:
! 177: return update_needed;
! 178: }
! 179:
! 180: // 画面合成。
! 181: // レンダラスレッドで VideoCtlr から呼ばれる。
! 182: // dst を更新すれば true を返す。
! 183: bool
! 184: GVRAMDevice::Render(BitmapRGBX& dst)
! 185: {
! 186: bool updated = false;
! 187:
! 188: // ローカルにコピー。
! 189: ModifyInfo modified;
! 190: {
! 191: std::lock_guard<std::mutex> lock(mtx);
! 192: modified.line = pending.line;
! 193: modified.invalidate2 = pending.invalidate2;
! 194: pending.line.reset();
! 195: pending.invalidate2 = false;
! 196: }
! 197:
! 198: // GVRAM に更新があれば composite を更新。
! 199: if (modified.line.any()) {
! 200: Render1024ToComposite(modified.line);
! 201: updated = true;
! 202: }
! 203:
! 204: // composite に更新があるか(updated)、
! 205: // 無条件に更新するか(modified.invalidate2) なら dst を更新。
! 206: if (updated || modified.invalidate2) {
! 207: RenderCompositeToRGBX(dst, modified);
! 208: updated = true;
! 209: }
! 210:
! 211: return updated;
! 212: }
! 213:
! 214: // GVRAM (1024x1024、16色モード) から composite 画面を合成する。
! 215: // レンダラスレッドから呼ばれる。
! 216: void
! 217: GVRAMDevice::Render1024ToComposite(const bitset1024& modified)
! 218: {
! 219: constexpr uint xend = 1024;
! 220: constexpr uint yend = 1024;
! 221: for (uint y = 0; y < yend; y++) {
! 222: if (__predict_true(modified.test(y) == false)) {
! 223: continue;
! 224: }
! 225:
! 226: const uint16 *src = (const uint16 *)&mem[0];
! 227: src += y * 1024;
! 228: uint8 *dst = (uint8 *)composite.GetRowPtr(y);
! 229: for (uint x = 0; x < xend; x++) {
! 230: *dst++ = *src++;
! 231: }
! 232: }
! 233: }
! 234:
! 235: void
! 236: GVRAMDevice::RenderCompositeToRGBX(BitmapRGBX& dst,
! 237: const ModifyInfo& modified)
! 238: {
! 239: dst.DrawBitmapI8(0, 0, composite, palette);
! 240: }
! 241:
! 242: // (x, y) 位置のピクセル情報を screen に出力。(ビットマップモニタの情報欄)
! 243: void
! 244: GVRAMDevice::UpdateInfo(TextScreen& screen, int x, int y) const
! 245: {
! 246: screen.Clear();
! 247:
! 248: // 0 1 2 3 4 5 6
! 249: // 012345678901234567890123456789012345678901234567890123456789012345
! 250: // X=1023 Y=1023: ColorCode=$d
! 251:
! 252: screen.Puts(0, 0, "X= Y=");
! 253: if (x >= 0) {
! 254: const uint16 *mem16 = (const uint16 *)&mem[0];
! 255: uint16 cc = mem16[y * 1024 + x];
! 256: screen.Print(2, 0, "%4d Y=%4d Colorcode=$%x", x, y, cc);
! 257: }
! 258: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.