|
|
1.1 root 1: //
2: // nono
1.1.1.4 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "crtc.h"
8: #include "mfp.h"
9: #include "renderer.h"
10: #include "tvram.h"
11:
1.1.1.4 root 12: // e80000..e803ff 内は $40 バイトでミラー。
13: // e80400..e807ff 内は 256 バイトでミラーになっており、このうち
14: // +$00..+$7f はバスエラー、
15: // +$80..+$ff は何かが読める。
16: // 仕様は $e80480.w に1ポートあるので、これがワードで全域にミラーされている?
17: // 全体としては この $800 バイトずつが繰り返して見える。
18:
19: std::unique_ptr<CRTCDevice> gCRTC;
20:
1.1 root 21: CRTCDevice::CRTCDevice()
22: {
23: logname = "crtc";
24: devname = "CRTC";
25: devaddr = 0xe80000;
26: devlen = 0x2000;
27:
28: vdisp_event.dev = this;
29: vdisp_event.func = (DeviceCallback_t)&CRTCDevice::VDispCallback;
1.1.1.2 root 30: vdisp_event.SetName("CRTC V-DISP");
1.1 root 31: }
32:
33: CRTCDevice::~CRTCDevice()
34: {
35: }
36:
37: void
38: CRTCDevice::ResetHard()
39: {
40: // XXX 初期値適当
41: crtc.r[20] = 0x0016;
42:
43: // XXX 適当
44: // すぐに垂直帰線期間を開始する
45: vdisp_event.time = 0;
46: vdisp_event.code = 1;
1.1.1.3 root 47: vdisp_event.Start();
1.1 root 48: }
49:
50: uint64
1.1.1.6 ! root 51: CRTCDevice::Read(uint32 offset)
1.1 root 52: {
1.1.1.4 root 53: uint64 data;
1.1 root 54:
1.1.1.5 root 55: gMPU->AddCycle(9); // InsideOut p.135
56:
1.1.1.6 ! root 57: if (offset < 0x400 / 2) { // CRTC レジスタ
1.1.1.4 root 58: // 0x40 バイトでミラー
1.1.1.6 ! root 59: offset &= (0x40 / 2) - 1;
1.1.1.4 root 60: // R20, R21 のみ読み出し可能
1.1.1.6 ! root 61: switch (offset) {
1.1.1.4 root 62: case 20:
1.1.1.6 ! root 63: data = crtc.r[offset];
! 64: putlog(2, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4 root 65: break;
66: case 21:
67: // R21 へのアクセスは多いのでログレベルを上げておく
1.1.1.6 ! root 68: data = crtc.r[offset];
! 69: putlog(3, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4 root 70: break;
71: default:
72: // それ以外は読み出し不可 ($00 が読める)
73: data = 0;
1.1.1.6 ! root 74: if (offset < countof(crtc.r)) {
! 75: putlog(3, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4 root 76: } else {
77: putlog(3, "$%06x -> $%04x", gMPU->GetPaddr(), (uint32)data);
78: }
79: break;
1.1 root 80: }
81:
1.1.1.4 root 82: } else { // 動作ポート
1.1.1.6 ! root 83: if ((offset & (0x80 / 2)) == 0) { // +$00..+$7f
1.1.1.4 root 84: data = (uint64)-1;
1.1.1.6 ! root 85: } else { // +$80..+$ff
1.1.1.4 root 86: data = crtc.op;
1.1 root 87: }
88: }
89:
90: return data;
91: }
92:
93: uint64
1.1.1.6 ! root 94: CRTCDevice::Write(uint32 offset, uint32 data)
1.1 root 95: {
1.1.1.5 root 96: gMPU->AddCycle(9); // InsideOut p.135
97:
1.1.1.6 ! root 98: if (offset < 0x400 / 2) { // CRTC レジスタ
1.1.1.4 root 99: // 0x40 バイトでミラー
1.1.1.6 ! root 100: offset &= (0x40 / 2) - 1;
! 101: if (offset < countof(crtc.r)) {
! 102: SetReg(offset, data);
1.1 root 103: } else {
1.1.1.4 root 104: // ここ何がいるんだ?
105: putlog(2, "$%06x <- $%04x", gMPU->GetPaddr(), data);
1.1 root 106: }
107:
1.1.1.4 root 108: } else { // 動作ポート
1.1.1.6 ! root 109: if ((offset & (0x80 / 2)) == 0) { // +$00..+$7f
1.1.1.4 root 110: return (uint64)-1;
111: } else {
1.1 root 112: crtc.op = data & 0x0b;
1.1.1.4 root 113: putlog(2, "$E80480.W <- $%04x", crtc.op);
1.1 root 114: }
115: }
1.1.1.4 root 116:
1.1 root 117: return 0;
118: }
119:
120: uint64
1.1.1.6 ! root 121: CRTCDevice::Peek(uint32 offset)
1.1 root 122: {
1.1.1.4 root 123: uint64 data;
1.1 root 124:
1.1.1.6 ! root 125: if (offset < 0x400 / 2) { // CRTC レジスタ
1.1.1.4 root 126: // 0x40 バイトでミラー
1.1.1.6 ! root 127: offset &= (0x40 / 2) - 1;
! 128: if (offset == 20 || offset == 21) {
1.1.1.4 root 129: // R20, R21 のみ読み出し可能
1.1.1.6 ! root 130: data = crtc.r[offset];
1.1.1.4 root 131: } else {
132: data = 0;
133: }
1.1 root 134:
1.1.1.4 root 135: } else { // 動作ポート
1.1.1.6 ! root 136: if ((offset & (0x80 / 2)) == 0) {
1.1.1.4 root 137: data = (uint64)-1;
138: } else {
139: data = crtc.op;
140: }
1.1 root 141: }
1.1.1.4 root 142:
143: return data;
1.1 root 144: }
145:
1.1.1.4 root 146: // CRTC レジスタへの書き込み。
147: // reg は CRTC::R00 .. CRTC::R23
1.1 root 148: void
1.1.1.4 root 149: CRTCDevice::SetReg(uint32 reg, uint32 data)
1.1 root 150: {
151: crtc.r[reg] = data;
152:
153: switch (reg) {
1.1.1.4 root 154: case CRTC::R10:
155: putlog(2, "R%02d <- $%04x", reg, data);
156: gTVRAM->SetScrollX(crtc.r[10]);
157: break;
158: case CRTC::R11:
159: putlog(2, "R%02d <- $%04x", reg, data);
160: gTVRAM->SetScrollY(crtc.r[11]);
161: break;
1.1 root 162: case CRTC::R21:
1.1.1.4 root 163: // 頻度が高いのでログレベルを上げておく
164: putlog(3, "R%02d <- $%04x", reg, data);
1.1 root 165: gTVRAM->set_crtc_21(crtc.r[21]);
166: break;
167: default:
1.1.1.4 root 168: putlog(2, "R%02d <- $%04x (未実装)", reg, data);
169: break;
1.1 root 170: }
171: }
172:
173: // 垂直表示・帰線イベント
1.1.1.5 root 174: // ev.code が 1 なら表示期間開始(V-disp)、0 なら帰線期間開始(V-blank)。
1.1 root 175: void
1.1.1.5 root 176: CRTCDevice::VDispCallback(Event& ev)
1.1 root 177: {
1.1.1.5 root 178: int& vdisp = ev.code;
179:
1.1 root 180: // GPIP の状態を更新
1.1.1.5 root 181: gMFP->SetVDisp(vdisp);
1.1 root 182:
183: // 今はここで1画面まるごと作成
1.1.1.5 root 184: if (vdisp) {
1.1 root 185: // Render に作画指示
186: gRenderer->Render();
187: }
188:
189: // 次のタイミングを計算
190: // XXX まだ CRTC から計算していない
1.1.1.5 root 191: if (vdisp) {
1.1 root 192: // 垂直表示期間
1.1.1.5 root 193: ev.time = 16250_usec;
194: ev.code = 0;
1.1 root 195: } else {
196: // 垂直帰線期間
1.1.1.5 root 197: ev.time = 1778_usec;
198: ev.code = 1;
1.1 root 199: }
1.1.1.5 root 200: ev.Start();
1.1 root 201: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.