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