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