|
|
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:
1.1.1.7 root 11: // TVRAM (PlaneVRAM) はロングワード単位でホストバイトオーダ配置なので、
12: // バイトアクセス時は HLB()、ワードアクセス時は HLW() マクロを使用のこと。
13:
1.1 root 14: #include "tvram.h"
1.1.1.7 root 15: #include "mpu.h"
1.1.1.3 root 16: #include "videoctlr.h"
1.1 root 17:
1.1.1.10! root 18: // InsideOut p.135
! 19: static const busdata wait = busdata::Wait(9 * 40_nsec);
! 20:
1.1.1.7 root 21: // コンストラクタ
1.1 root 22: TVRAMDevice::TVRAMDevice()
1.1.1.9 root 23: : inherited(1024, 1024)
1.1 root 24: {
1.1.1.9 root 25: SetName("TVRAM");
26: ClearAlias();
27: AddAlias("TVRAM");
28:
29: uint devlen = 512 * 1024;
1.1 root 30:
1.1.1.7 root 31: // プレーン数は4枚固定
32: nplane = NPLANE;
1.1.1.4 root 33:
1.1.1.7 root 34: mem.reset(new uint8[devlen]);
1.1 root 35: }
36:
1.1.1.7 root 37: // デストラクタ
1.1 root 38: TVRAMDevice::~TVRAMDevice()
39: {
40: }
41:
1.1.1.9 root 42: // 初期化
1.1.1.7 root 43: bool
44: TVRAMDevice::Init()
45: {
1.1.1.9 root 46: if (inherited::Init() == false) {
47: return false;
48: }
49:
50: renderer = GetRenderer();
51: auto videoctlr = GetVideoCtlrDevice();
52:
1.1.1.7 root 53: // 加工済みパレットを取得
1.1.1.9 root 54: palette = &(videoctlr->GetHostPalette())[0];
1.1.1.7 root 55:
56: return true;
57: }
58:
1.1.1.10! root 59: inline uint32
1.1.1.2 root 60: TVRAMDevice::Decoder(uint32 addr) const
61: {
62: return addr - baseaddr;
63: }
64:
1.1.1.10! root 65: busdata
1.1 root 66: TVRAMDevice::Read8(uint32 addr)
67: {
1.1.1.10! root 68: busdata data;
1.1.1.2 root 69: uint32 offset = Decoder(addr);
1.1.1.10! root 70: data = mem[HLB(offset)];
! 71: data |= wait;
! 72: return data;
1.1 root 73: }
74:
1.1.1.10! root 75: busdata
1.1 root 76: TVRAMDevice::Read16(uint32 addr)
77: {
1.1.1.10! root 78: busdata data;
1.1.1.2 root 79: uint32 offset = Decoder(addr);
1.1.1.10! root 80: data = *(uint16 *)&mem[HLW(offset)];
! 81: data |= wait;
! 82: return data;
1.1 root 83: }
84:
1.1.1.10! root 85: busdata
1.1 root 86: TVRAMDevice::Write8(uint32 addr, uint32 data)
87: {
1.1.1.2 root 88: uint32 offset = Decoder(addr);
1.1.1.7 root 89: uint8 *ptr;
90: uint8 mask8;
1.1 root 91:
92: // XXX とりあえずね
1.1.1.8 root 93: putlog(3, "Write $%06x.B <- $%02x", addr, data);
1.1 root 94:
1.1.1.7 root 95: if (tvram.men) {
96: if ((addr & 1) == 0) {
97: mask8 = tvram.mask >> 8;
98: } else {
99: mask8 = tvram.mask;
100: }
101: } else {
102: mask8 = 0;
103: }
104:
1.1.1.9 root 105: uint32 poffset = offset & 0x1ffff;
1.1 root 106: if (tvram.sa) {
107: // 同時アクセス
108: for (int plane = 0; plane < 4; plane++) {
109: if (tvram.ap[plane]) {
1.1.1.7 root 110: ptr = &mem[HLB(0x20000 * plane + poffset)];
111: *ptr = (data & ~mask8) | (*ptr & mask8);
1.1 root 112: }
113: }
114: } else {
115: // 通常アクセス
1.1.1.7 root 116: ptr = &mem[HLB(offset)];
117: *ptr = (data & ~mask8) | (*ptr & mask8);
1.1 root 118: }
1.1.1.9 root 119: SetDirty(poffset);
1.1.1.10! root 120: return wait;
1.1 root 121: }
122:
1.1.1.10! root 123: busdata
1.1 root 124: TVRAMDevice::Write16(uint32 addr, uint32 data)
125: {
1.1.1.2 root 126: uint32 offset = Decoder(addr);
1.1.1.7 root 127: uint16 *ptr;
128: uint16 mask16;
1.1 root 129:
130: // XXX とりあえずね
1.1.1.8 root 131: putlog(3, "Write $%06x.W <- $%04x", addr, data);
1.1 root 132:
1.1.1.7 root 133: if (tvram.men) {
134: mask16 = tvram.mask;
135: } else {
136: mask16 = 0;
137: }
138:
1.1.1.9 root 139: uint32 poffset = offset & 0x1ffff;
1.1 root 140: if (tvram.sa) {
141: // 同時アクセス
142: for (int plane = 0; plane < 4; plane++) {
143: if (tvram.ap[plane]) {
1.1.1.7 root 144: ptr = (uint16 *)&mem[HLW(0x20000 * plane + poffset)];
145: *ptr = (data & ~mask16) | (*ptr & mask16);
1.1 root 146: }
147: }
148: } else {
149: // 通常アクセス
1.1.1.7 root 150: ptr = (uint16 *)&mem[HLW(offset)];
151: *ptr = (data & ~mask16) | (*ptr & mask16);
1.1 root 152: }
1.1.1.9 root 153: SetDirty(poffset);
1.1.1.10! root 154: return wait;
1.1 root 155: }
156:
1.1.1.10! root 157: busdata
1.1 root 158: TVRAMDevice::Peek8(uint32 addr)
159: {
1.1.1.2 root 160: uint32 offset = Decoder(addr);
1.1.1.7 root 161: return mem[HLB(offset)];
1.1 root 162: }
163:
1.1.1.10! root 164: bool
1.1.1.9 root 165: TVRAMDevice::Poke8(uint32 addr, uint32 data)
166: {
167: if ((int32)data >= 0) {
168: uint32 offset = Decoder(addr);
169: uint32 poffset = offset & 0x1ffff;
170: mem[HLB(offset)] = data;
171: // この場合も画面を更新する
172: SetDirty(poffset);
173: }
1.1.1.10! root 174: return true;
1.1.1.9 root 175: }
176:
1.1.1.7 root 177: // offset の位置に対応する更新フラグを立てる。
1.1.1.9 root 178: // offset はプレーン先頭からのバイトオフセット。
1.1.1.7 root 179: inline void
180: TVRAMDevice::SetDirty(uint32 offset)
181: {
1.1.1.9 root 182: // VRAM は横 1024 ドット(128バイト) x 縦 1024 ドット。
1.1.1.7 root 183: //
184: // 1 0
185: // 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
186: // +-----------+-------+-----+-------+-----+
187: // VRAM | Y座標 (1024dot) | X (128byte) : 8bit|
188: // +-----------+-------+-----+-------+-----+
1.1.1.9 root 189: // : :
190: // +-------------------+
191: // Dirty | |
192: // +-------------------+
193: // 9 8 7 6 5 4 3 2 1 0
194:
195: // 更新フラグはラスタ単位
196: int y = offset >> 7;
197: dirty[y] = 1;
198: }
199:
200: // X 方向にはみ出したときに対応する仮想画面の Y 座標を返す。
201: int
202: TVRAMDevice::GetWrapY(int y) const
203: {
204: // はみ出すと次のラスタの先頭から表示するが、
205: // TVRAM は 4 ラスタがひとかたまりで構成されていて、
206: // 末尾 2bit が 3 のラスタの次は、末尾だけ 0 のラスタに戻る。ようだ。
207: return (y & ~3) + ((y + 1) & 3);
1.1 root 208: }
209:
1.1.1.3 root 210: void
211: TVRAMDevice::SetScrollX(int x)
212: {
1.1.1.7 root 213: xscroll = x;
1.1.1.3 root 214: }
215:
216: void
217: TVRAMDevice::SetScrollY(int y)
218: {
1.1.1.7 root 219: yscroll = y;
1.1.1.9 root 220: renderer->Invalidate2();
1.1.1.3 root 221: }
222:
1.1.1.7 root 223: // CRTC R21 での同時アクセス設定を反映する。
224: // CRTC から呼ばれる。
1.1 root 225: void
1.1.1.7 root 226: TVRAMDevice::SetAccessPlane(uint16 data)
1.1 root 227: {
1.1.1.7 root 228: tvram.cp[0] = (data & 0x01);
229: tvram.cp[1] = (data & 0x02);
230: tvram.cp[2] = (data & 0x04);
231: tvram.cp[3] = (data & 0x08);
1.1 root 232: tvram.ap[0] = (data & 0x10);
233: tvram.ap[1] = (data & 0x20);
234: tvram.ap[2] = (data & 0x40);
235: tvram.ap[3] = (data & 0x80);
1.1.1.7 root 236: tvram.sa = (data & 0x100);
237: tvram.men = (data & 0x200);
1.1 root 238:
239: if (0) {
240: if (tvram.sa) {
241: putlog(2, "テキスト画面同時アクセス有効 %c%c%c%c",
242: tvram.ap[0] ? '0' : '-',
243: tvram.ap[1] ? '1' : '-',
244: tvram.ap[2] ? '2' : '-',
245: tvram.ap[3] ? '3' : '-');
246: } else {
247: putlog(2, "テキスト画面同時アクセス無効");
248: }
249: }
250: }
251:
1.1.1.7 root 252: // CRTC R23 でのアクセスマスク設定を反映する。
253: // CRTC から呼ばれる。
254: void
255: TVRAMDevice::SetAccessMask(uint16 data)
1.1 root 256: {
1.1.1.7 root 257: tvram.mask = data;
258: }
1.1.1.4 root 259:
1.1.1.7 root 260: // ラスターコピーを開始する。
261: // src_ras, dst_ras はライン番号 (レジスタ設定値を4倍したもの)。
262: void
263: TVRAMDevice::RasterCopy(int src_ras, int dst_ras)
264: {
265: for (int plane = 0; plane < 4; plane++) {
266: if (tvram.cp[plane]) {
1.1.1.8 root 267: uint8 *src = &mem[0x20000 * plane + src_ras * 128];
268: uint8 *dst = &mem[0x20000 * plane + dst_ras * 128];
1.1.1.7 root 269: memcpy(dst, src, 128 * 4);
1.1 root 270: }
271: }
272:
1.1.1.8 root 273: // dst からの4ラインを全部 dirty にする。
1.1.1.9 root 274: for (int y = 0; y < 4; y++) {
275: SetDirty((dst_ras + y) * 128);
1.1.1.8 root 276: }
1.1.1.9 root 277: }
278:
279: // (x, y) 位置のピクセル情報を screen に描画。(ビットマップモニタの情報欄)
280: void
281: TVRAMDevice::UpdateInfo(TextScreen& screen, int x, int y) const
282: {
283: screen.Clear();
284:
285: //0 1 2 3 4 5 6
286: //012345678901234567890123456789012345678901234567890123456789012345
287: //X=1024 Y=2024: (P0) $e01234: $00 (%00000000) ColorCode=$d
288:
289: screen.Puts(0, 0, "X= Y=");
290: for (int i = 0; i < nplane; i++) {
291: screen.Print(15, i, "(P%d)", i);
292: }
293:
294: // カーソルが範囲外ならここまで。
295: if (x < 0) {
296: return;
297: }
298:
299: screen.Print(2, 0, "%4d Y=%4d", x, y);
300:
301: // 1プレーン内のバイトオフセット
302: uint32 planeoffset = ((uint)y * 128) + ((uint)x / 8);
303:
304: uint cc = 0;
305: for (int i = 0; i < nplane; i++) {
306: // プレーン0先頭からのバイトオフセット
307: uint32 totaloffset = 0x20000 * i + planeoffset;
308:
309: uint8 data = mem[HLB(totaloffset)];
310: screen.Print(15, i, "(P%d) $%06x: $%02x (%%",
311: i, baseaddr + totaloffset, data);
312:
313: // ビットパターン
314: for (int m = 0x80; m != 0; m >>= 1) {
315: screen.Putc((data & m) ? '1' : '0');
316: }
317: screen.Putc(')');
318:
319: // カーソル位置をハイライト
320: screen.Locate(35 + (x % 8), i);
321: screen.SetAttr(TA::Em);
322:
323: // カラーコードを計算
324: if ((data & (0x80U >> (x % 8))) != 0) {
325: cc |= (1U << i);
1.1.1.7 root 326: }
327: }
1.1.1.9 root 328:
329: screen.Print(45, 0, "ColorCode=$%x", cc);
1.1 root 330: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.