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