|
|
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.7 root 20: : inherited("TVRAM", 1024, 1024)
1.1 root 21: {
22: devaddr = baseaddr;
23: devlen = 512 * 1024;
24:
1.1.1.7 root 25: // プレーン数は4枚固定
26: nplane = NPLANE;
1.1.1.4 root 27:
1.1.1.7 root 28: modify_mask = 0xff00;
29:
30: mem.reset(new uint8[devlen]);
1.1 root 31: }
32:
1.1.1.7 root 33: // デストラクタ
1.1 root 34: TVRAMDevice::~TVRAMDevice()
35: {
36: }
37:
1.1.1.7 root 38: bool
39: TVRAMDevice::Init()
40: {
41: // 加工済みパレットを取得
42: palette = gVideoCtlr->GetHostPalette();
43:
44: return true;
45: }
46:
47: // リセット
1.1 root 48: void
1.1.1.7 root 49: TVRAMDevice::ResetHard(bool poweron)
1.1 root 50: {
51: // XXX ここ?
52: Invalidate();
53: }
54:
1.1.1.2 root 55: inline uint64
56: TVRAMDevice::Decoder(uint32 addr) const
57: {
58: return addr - baseaddr;
59: }
60:
1.1 root 61: uint64
62: TVRAMDevice::Read8(uint32 addr)
63: {
1.1.1.5 root 64: gMPU->AddCycle(9); // Inside/Out p.135
1.1.1.2 root 65: uint32 offset = Decoder(addr);
1.1.1.7 root 66: return mem[HLB(offset)];
1.1 root 67: }
68:
69: uint64
70: TVRAMDevice::Read16(uint32 addr)
71: {
1.1.1.5 root 72: gMPU->AddCycle(9); // Inside/Out p.135
1.1.1.2 root 73: uint32 offset = Decoder(addr);
1.1.1.7 root 74: return *(uint16 *)&mem[HLW(offset)];
1.1 root 75: }
76:
77: uint64
78: TVRAMDevice::Write8(uint32 addr, uint32 data)
79: {
1.1.1.2 root 80: uint32 offset = Decoder(addr);
1.1.1.7 root 81: uint8 *ptr;
82: uint8 mask8;
1.1 root 83:
1.1.1.5 root 84: gMPU->AddCycle(9); // Inside/Out p.135
85:
1.1 root 86: // XXX とりあえずね
1.1.1.8 ! root 87: putlog(3, "Write $%06x.B <- $%02x", addr, data);
1.1 root 88:
1.1.1.7 root 89: if (tvram.men) {
90: if ((addr & 1) == 0) {
91: mask8 = tvram.mask >> 8;
92: } else {
93: mask8 = tvram.mask;
94: }
95: } else {
96: mask8 = 0;
97: }
98:
1.1 root 99: if (tvram.sa) {
100: // 同時アクセス
101: uint32 poffset = offset & 0x1ffff;
102: for (int plane = 0; plane < 4; plane++) {
103: if (tvram.ap[plane]) {
1.1.1.7 root 104: ptr = &mem[HLB(0x20000 * plane + poffset)];
105: *ptr = (data & ~mask8) | (*ptr & mask8);
1.1 root 106: }
107: }
108: } else {
109: // 通常アクセス
1.1.1.7 root 110: ptr = &mem[HLB(offset)];
111: *ptr = (data & ~mask8) | (*ptr & mask8);
1.1 root 112: }
1.1.1.7 root 113: SetDirty(offset);
1.1 root 114: return 0;
115: }
116:
117: uint64
118: TVRAMDevice::Write16(uint32 addr, uint32 data)
119: {
1.1.1.2 root 120: uint32 offset = Decoder(addr);
1.1.1.7 root 121: uint16 *ptr;
122: uint16 mask16;
1.1 root 123:
1.1.1.5 root 124: gMPU->AddCycle(9); // Inside/Out p.135
125:
1.1 root 126: // XXX とりあえずね
1.1.1.8 ! root 127: putlog(3, "Write $%06x.W <- $%04x", addr, data);
1.1 root 128:
1.1.1.7 root 129: if (tvram.men) {
130: mask16 = tvram.mask;
131: } else {
132: mask16 = 0;
133: }
134:
1.1 root 135: if (tvram.sa) {
136: // 同時アクセス
137: uint32 poffset = offset & 0x1ffff;
138: for (int plane = 0; plane < 4; plane++) {
139: if (tvram.ap[plane]) {
1.1.1.7 root 140: ptr = (uint16 *)&mem[HLW(0x20000 * plane + poffset)];
141: *ptr = (data & ~mask16) | (*ptr & mask16);
1.1 root 142: }
143: }
144: } else {
145: // 通常アクセス
1.1.1.7 root 146: ptr = (uint16 *)&mem[HLW(offset)];
147: *ptr = (data & ~mask16) | (*ptr & mask16);
1.1 root 148: }
1.1.1.7 root 149: SetDirty(offset);
1.1 root 150: return 0;
151: }
152:
153: uint64
154: TVRAMDevice::Peek8(uint32 addr)
155: {
1.1.1.2 root 156: uint32 offset = Decoder(addr);
1.1.1.7 root 157: return mem[HLB(offset)];
1.1 root 158: }
159:
1.1.1.7 root 160: // offset の位置に対応する更新フラグを立てる。
161: // offset は TVRAM 先頭からのバイトオフセット (プレーン先頭からではない)。
162: inline void
163: TVRAMDevice::SetDirty(uint32 offset)
164: {
165: // VRAM は横 1024 ドット(128バイト) x 縦 1024 ドットで、これを
166: // 横 128 ドット(16バイト) x 縦 16 ドットずつのブロックに分割する。
167: // ブロック数は横 8個 x 縦 64個。
168: //
169: // 1 0
170: // 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
171: // +-----------+-------+-----+-------+-----+
172: // VRAM | Y座標 (1024dot) | X (128byte) : 8bit|
173: // +-----------+-------+-----+-------+-----+
174: // : : : : :
175: // +-----------+-------+-----+-------------+
176: // Block | Y(64blks) | 16dot | X(8)| 128 dot | *: X は 8 blocks
177: // +-----------+-------+-----+-------------+
178: // \ \ | |
179: // \ \ | |
180: // \ \ | |
181: // +-----------+-----+
182: // Dirty | Y(64blks) | X(8)|
183: // +-----------+-----+
184: // 8 7 6 5 4 3 2 1 0
185:
186: // x 座標(バイト単位 7 bit)の上位 3 bit
187: int x = (offset >> 4) & 0x07;
188: // y 座標(10bit) の上位 6 bit
189: int y = (offset >> 8) & 0x1f8;
190:
191: // からインデックスを求める
192: int b = x + y;
193:
194: dirty[b] = 1;
195:
196: #if defined(PERF_HIT)
197: // どのロングワードが更新されたか
198: dirty_word[(offset & 0x1ffff) >> 2] = true;
199: #endif
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;
212: gRenderer->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
255: TVRAMDevice::RasterCopy(int src_ras, int dst_ras)
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 にする。
! 266: #if !defined(PERF_HIT)
! 267: // dirty は、1ブロックが縦 16dot 収容しているので、4の倍数から始まる
! 268: // 4ラインは必ず1ブロックに収まる。横方向は1ブロックにつき 128dot 収容して
! 269: // いるので全部で8ブロック。
! 270: // よって dirty を立てるだけなら 8回の呼び出しで済む。
! 271: for (int x = 0; x < 8; x++) {
! 272: SetDirty(dst_ras * 128 + (x << 4));
! 273: }
! 274: #else
! 275: // PERF_HIT の更新を行う場合は律儀に全プレーンの全ロングワード分ループする
! 276: for (int plane = 0; plane < 4; plane++) {
! 277: for (int i = 0; i < 4; i++) {
! 278: int y = dst_ras + i;
! 279: for (int x = 0; x < 128 / sizeof(uint32); x++) {
! 280: SetDirty(0x20000 * plane + y * 128 + x * sizeof(uint32));
! 281: }
1.1.1.7 root 282: }
283: }
1.1.1.8 ! root 284: #endif
1.1 root 285: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.