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