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