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