|
|
1.1 root 1: //
2: // nono
1.1.1.3 ! root 3: // Copyright (C) 2020 nono project
! 4: // Licensed under nono-license.txt
! 5: //
! 6:
1.1 root 7: //
8: // TVRAM
9: //
10:
11: #include "tvram.h"
1.1.1.3 ! root 12: #include "crtc.h"
! 13: #include "renderer.h"
! 14: #include "videoctlr.h"
1.1 root 15:
16: //
17: // TVRAM はワード単位でホストバイトオーダ配置なので、
18: // バイトアクセス時は HB() マクロを使用のこと。
19: //
20:
1.1.1.2 root 21: std::unique_ptr<TVRAMDevice> gTVRAM;
1.1 root 22:
23: TVRAMDevice::TVRAMDevice()
24: {
25: logname = "tvram";
26: devname = "TVRAM";
27: devaddr = baseaddr;
28: devlen = 512 * 1024;
29:
1.1.1.2 root 30: mem.reset(new uint8[devlen]);
1.1 root 31: }
32:
33: TVRAMDevice::~TVRAMDevice()
34: {
35: }
36:
37: void
38: TVRAMDevice::ResetHard()
39: {
40: // XXX ここ?
41: Invalidate();
42: }
43:
1.1.1.2 root 44: inline uint64
45: TVRAMDevice::Decoder(uint32 addr) const
46: {
47: return addr - baseaddr;
48: }
49:
1.1 root 50: uint64
51: TVRAMDevice::Read8(uint32 addr)
52: {
1.1.1.2 root 53: uint32 offset = Decoder(addr);
1.1 root 54: return mem[HB(offset)];
55: }
56:
57: uint64
58: TVRAMDevice::Read16(uint32 addr)
59: {
1.1.1.2 root 60: uint32 offset = Decoder(addr);
1.1 root 61: return *(uint16 *)&mem[offset];
62: }
63:
64: uint64
65: TVRAMDevice::Write8(uint32 addr, uint32 data)
66: {
1.1.1.2 root 67: uint32 offset = Decoder(addr);
1.1 root 68:
69: // XXX とりあえずね
70: putlog(3, "Write $%06x <- $%02x", addr, data);
71:
72: if (tvram.sa) {
73: // 同時アクセス
74: uint32 poffset = offset & 0x1ffff;
75: for (int plane = 0; plane < 4; plane++) {
76: if (tvram.ap[plane]) {
77: mem[HB(0x20000 * plane + poffset)] = data;
78: }
79: }
80: } else {
81: // 通常アクセス
82: mem[HB(offset)] = data;
83: }
84: atomic_dirty[(offset % 0x20000) / 128] = 1;
85: return 0;
86: }
87:
88: uint64
89: TVRAMDevice::Write16(uint32 addr, uint32 data)
90: {
1.1.1.2 root 91: uint32 offset = Decoder(addr);
1.1 root 92:
93: // XXX とりあえずね
94: putlog(3, "Write $%06x <- $%04x", addr, data);
95:
96: if (tvram.sa) {
97: // 同時アクセス
98: uint32 poffset = offset & 0x1ffff;
99: for (int plane = 0; plane < 4; plane++) {
100: if (tvram.ap[plane]) {
101: *(uint16 *)&mem[0x20000 * plane + poffset] = data;
102: }
103: }
104: } else {
105: // 通常アクセス
106: *(uint16 *)&mem[offset] = data;
107: }
108: atomic_dirty[(offset % 0x20000) / 128] = 1;
109: return 0;
110: }
111:
112: uint64
113: TVRAMDevice::Peek8(uint32 addr)
114: {
1.1.1.2 root 115: uint32 offset = Decoder(addr);
116: return mem[HB(offset)];
1.1 root 117: }
118:
119: // 全画面の更新フラグを立てる
120: void
121: TVRAMDevice::Invalidate()
122: {
123: for (int i = 0; i < 1024; i++) {
124: atomic_dirty[i] = 1;
125: }
126: }
127:
1.1.1.3 ! root 128: void
! 129: TVRAMDevice::SetScrollX(int x)
! 130: {
! 131: tvram.xscroll = x;
! 132: }
! 133:
! 134: void
! 135: TVRAMDevice::SetScrollY(int y)
! 136: {
! 137: tvram.yscroll = y;
! 138: // 全ラインを無効にする XXX とりあえずね
! 139: Invalidate();
! 140: }
! 141:
1.1 root 142: // CRTC R21 での同時アクセス設定を反映する
143: // CRTC から呼ばれる
144: void
145: TVRAMDevice::set_crtc_21(uint16 data)
146: {
147: tvram.sa = (data & 0x100);
148: tvram.ap[0] = (data & 0x10);
149: tvram.ap[1] = (data & 0x20);
150: tvram.ap[2] = (data & 0x40);
151: tvram.ap[3] = (data & 0x80);
152:
153: if (0) {
154: if (tvram.sa) {
155: putlog(2, "テキスト画面同時アクセス有効 %c%c%c%c",
156: tvram.ap[0] ? '0' : '-',
157: tvram.ap[1] ? '1' : '-',
158: tvram.ap[2] ? '2' : '-',
159: tvram.ap[3] ? '3' : '-');
160: } else {
161: putlog(2, "テキスト画面同時アクセス無効");
162: }
163: }
164: }
165:
166: // テキスト画面合成
167: bool
168: TVRAMDevice::Render(uint8 *imagebuf)
169: {
170: const uint16 *palette_w;
171: uint8 pal[16][3];
172: const uint16 *plane0;
173: const uint16 *plane1;
174: const uint16 *plane2;
175: const uint16 *plane3;
176: uint8 *dst0;
177: bool updated;
178:
179: dst0 = imagebuf;
180:
181: // パレット取得
1.1.1.3 ! root 182: palette_w = gVideoCtlr->GetPalette();
1.1 root 183: // パレット前半 256 ワードはグラフィックパレット、
184: // テキストパレットは後半。
185: palette_w += 0x100;
186:
187: // パレット情報から RGB24 色データを作成
188: // XXX ちょっと輝度は置いとく
189: for (int i = 0; i < 16; i++) {
190: pal[i][0] = ((palette_w[i] >> 6) & 0x1f) << 3; // R
191: pal[i][1] = ((palette_w[i] >> 11)) << 3; // G
192: pal[i][2] = ((palette_w[i] >> 1) & 0x1f) << 3; // B
193: }
194:
195: updated = false;
196:
197: // dirty は VRAM への書き込みがあれば常に 1 にする。
198: // レンダリング時に dirty が 1 なら 2 にしてレンダリング。
199: // レンダリング終了時に dirty が 2 なら 0 に戻す。
200: // これによりレンダリング中に VRAM への書き込みがあれば次回描画される。
201:
202: // sy はメモリ上の Y 座標
203: // dy はレンダラ画面の Y 座標 (CRTC のXXX を考慮)
204: // XXX スクロールは未実装
205:
206: // テキスト画面
1.1.1.2 root 207: plane0 = (uint16 *)&mem[0x00000];
208: plane1 = (uint16 *)&mem[0x20000];
209: plane2 = (uint16 *)&mem[0x40000];
210: plane3 = (uint16 *)&mem[0x60000];
1.1.1.3 ! root 211: int sy = tvram.yscroll;
1.1 root 212: for (int dy = 0; dy < 512; dst0 += 768 * Renderer::BPP, dy++, sy++) {
213: sy &= 0x3ff;
214:
215: if (atomic_cas_8(&atomic_dirty[sy], 1, 2) == 1) {
216: uint8 *dst = dst0;
217: // sx はメモリ上の X オフセット (ワード単位)
218: // dx はレンダラ画面の X オフセット (ワード単位)
219:
220: int sx = sy * 1024 / 16;
221: for (int dx = 0; dx < 768 / 16; dx++, sx++) {
222: uint16 t0 = plane0[sx];
223: uint16 t1 = plane1[sx];
224: uint16 t2 = plane2[sx];
225: uint16 t3 = plane3[sx];
226:
227: // 1ワードの 16bit が横 16dot に相当
228: for (int j = 0; j < 16; j++) {
229: uint c = 0;
230: // カラーコード(パレット番号)を作成
231: if ((t0 & 0x8000)) c |= 1;
232: if ((t1 & 0x8000)) c |= 2;
233: if ((t2 & 0x8000)) c |= 4;
234: if ((t3 & 0x8000)) c |= 8;
235: t0 <<= 1;
236: t1 <<= 1;
237: t2 <<= 1;
238: t3 <<= 1;
239:
240: *dst++ = pal[c][0];
241: *dst++ = pal[c][1];
242: *dst++ = pal[c][2];
243: }
244: }
245:
246: // 2の時だけ0に戻す
247: atomic_cas_8(&atomic_dirty[sy], 2, 0);
248: updated = true;
249: }
250: }
251:
252: return updated;
253: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.