|
|
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 とりあえずね
87: putlog(3, "Write $%06x <- $%02x", addr, data);
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 とりあえずね
127: putlog(3, "Write $%06x <- $%04x", addr, data);
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: // XXX 今の所コピー中という期間は存在せず一瞬で終わる
! 254: // src_ras, dst_ras はライン番号 (レジスタ設定値を4倍したもの)。
! 255: void
! 256: TVRAMDevice::RasterCopy(int src_ras, int dst_ras)
! 257: {
! 258: for (int plane = 0; plane < 4; plane++) {
! 259: if (tvram.cp[plane]) {
! 260: uint8 *src = &mem[HLW(0x20000 * plane + src_ras * 128)];
! 261: uint8 *dst = &mem[HLW(0x20000 * plane + dst_ras * 128)];
! 262: memcpy(dst, src, 128 * 4);
1.1 root 263: }
264: }
265:
1.1.1.7 ! root 266: // dst からの4ラインを全部 dirty にする
! 267: for (int i = 0; i < 4; i++) {
! 268: int y = dst_ras + i;
! 269: // PERF_HIT の更新もあるので律儀に全ロングバイト分ループする
! 270: for (int x = 0; x < 128 / sizeof(uint32); x++) {
! 271: SetDirty(y * 128 + x * 4);
! 272: }
! 273: }
1.1 root 274: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.