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