|
|
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.4 root 51: CRTCDevice::Read(uint32 addr)
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.4 root 57: if (addr < 0x400 / 2) { // CRTC レジスタ
58: // 0x40 バイトでミラー
59: addr &= (0x40 / 2) - 1;
60: // R20, R21 のみ読み出し可能
61: switch (addr) {
62: case 20:
63: data = crtc.r[addr];
64: putlog(2, "R%02d -> $%04x", addr, (uint32)data);
65: break;
66: case 21:
67: // R21 へのアクセスは多いのでログレベルを上げておく
68: data = crtc.r[addr];
69: putlog(3, "R%02d -> $%04x", addr, (uint32)data);
70: break;
71: default:
72: // それ以外は読み出し不可 ($00 が読める)
73: data = 0;
74: if (addr < countof(crtc.r)) {
75: putlog(3, "R%02d -> $%04x", addr, (uint32)data);
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 { // 動作ポート
83: if ((addr & (0x80 / 2)) == 0) { // +$00..+$7f
84: data = (uint64)-1;
85: } else { // +$80..+$ff
86: data = crtc.op;
1.1 root 87: }
88: }
89:
90: return data;
91: }
92:
93: uint64
1.1.1.4 root 94: CRTCDevice::Write(uint32 addr, uint32 data)
1.1 root 95: {
1.1.1.5 ! root 96: gMPU->AddCycle(9); // InsideOut p.135
! 97:
1.1.1.4 root 98: if (addr < 0x400 / 2) { // CRTC レジスタ
99: // 0x40 バイトでミラー
100: addr &= (0x40 / 2) - 1;
101: if (addr < countof(crtc.r)) {
102: SetReg(addr, 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 { // 動作ポート
109: if ((addr & (0x80 / 2)) == 0) { // +$00..+$7f
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.4 root 121: CRTCDevice::Peek(uint32 addr)
1.1 root 122: {
1.1.1.4 root 123: uint64 data;
1.1 root 124:
1.1.1.4 root 125: if (addr < 0x400 / 2) { // CRTC レジスタ
126: // 0x40 バイトでミラー
127: addr &= (0x40 / 2) - 1;
128: if (addr == 20 || addr == 21) {
129: // R20, R21 のみ読み出し可能
130: data = crtc.r[addr];
131: } else {
132: data = 0;
133: }
1.1 root 134:
1.1.1.4 root 135: } else { // 動作ポート
136: if ((addr & (0x80 / 2)) == 0) {
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.