|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
1.1.1.4 root 7: //
8: // OPM (YM2151)
9: //
10:
1.1 root 11: #include "opm.h"
1.1.1.5 root 12: #include "adpcm.h"
1.1.1.10! root 13: #include "event.h"
1.1.1.4 root 14: #include "fdc.h"
1.1.1.5 root 15: #include "mpu.h"
16: #include "scheduler.h"
1.1 root 17:
1.1.1.4 root 18: // コンストラクタ
1.1 root 19: OPMDevice::OPMDevice()
1.1.1.6 root 20: : inherited(OBJ_OPM)
1.1 root 21: {
22: }
23:
1.1.1.4 root 24: // デストラクタ
1.1 root 25: OPMDevice::~OPMDevice()
26: {
1.1.1.6 root 27: }
28:
29: // 初期化
30: bool
31: OPMDevice::Init()
32: {
33: adpcm = GetADPCMDevice();
34: fdc = GetFDCDevice();
35:
36: return true;
1.1 root 37: }
38:
1.1.1.5 root 39: // リセット
40: void
41: OPMDevice::ResetHard(bool poweron)
42: {
43: busy_origin = 0;
44: busy_start = 0;
45: busy_end = 0;
46:
1.1.1.6 root 47: fdc->SetForceReady(false);
1.1.1.5 root 48: }
49:
1.1.1.7 root 50: busdata
1.1.1.8 root 51: OPMDevice::ReadPort(uint32 offset)
1.1 root 52: {
1.1.1.7 root 53: busdata data;
1.1.1.5 root 54:
1.1.1.4 root 55: switch (offset) {
56: case 0:
1.1.1.6 root 57: putlog(0, "Read $%06x (NOT IMPLEMENTED)", mpu->GetPaddr());
1.1.1.7 root 58: data = 0;
59: break;
1.1.1.4 root 60: case 1:
61: // OPM ステータスレジスタ
1.1.1.5 root 62: data = 0;
63: if (IsBusy()) {
64: data |= 0x80;
65: }
66: // タイマ関係の bit1, bit0 は未実装
67:
1.1.1.7 root 68: putlog(1, "STAT -> $%02x", data.Data());
69: break;
1.1.1.4 root 70: default:
1.1.1.8 root 71: VMPANIC("corrupted offset=%u", offset);
1.1.1.7 root 72: data = 0xff;
73: break;
1.1.1.4 root 74: }
1.1.1.7 root 75:
76: // InsideOut p.135
1.1.1.8 root 77: const busdata read_wait = busdata::Wait(19 * 40_nsec);
1.1.1.7 root 78: data |= read_wait;
79:
1.1.1.8 root 80: data |= BusData::Size1;
1.1.1.7 root 81: return data;
1.1 root 82: }
83:
1.1.1.7 root 84: busdata
1.1.1.8 root 85: OPMDevice::WritePort(uint32 offset, uint32 data)
1.1 root 86: {
1.1.1.6 root 87: uint64 now = scheduler->GetVirtTime();
1.1.1.5 root 88:
1.1.1.4 root 89: switch (offset) {
90: case 0:
91: putlog(1, "REG <- $%02x", data);
1.1.1.5 root 92: // アドレス選択が反映されるまで 8 クロックかかるらしい
93: // が、顕在化しないと思うので実装していない
1.1.1.4 root 94: reg = data;
95: break;
96: case 1:
97: putlog(1, "DATA <- $%02x", data);
1.1.1.5 root 98: // CPU が命令中のどのタイミングでライトするかを用意していないので
99: // 実際に OPM にライトされるタイミングは正確にはわからない。
100: // なので正確な時刻の起点は不明。
101: //
102: // BUSY がアサートされるまで OPM クロックで 8 から 12 クロックかかる
103: // らしい。
104: //
105: // BUSY のアサート期間は 68 クロックらしい。
106: // YM2151 アプリケーションマニュアル(英語版) 2.1.1
107:
108: // BUSY フラグのみならず、書き込み処理期間中のときは保証されていない。
109: // とりあえず無視する。
110: if (busy_origin <= now && now < busy_end) {
111: putlog(0, "Write on Busy");
112: break;
113: }
114:
115: // 時刻の起点は CPU 側の命令によって異なるはずだが
116: // わからないので命令のぶんは無視しておく。
117: // 53 クロックのウェイトのほうは足す。
1.1.1.6 root 118: busy_origin = now + 53 * mpu->GetClock_nsec();
1.1.1.5 root 119:
120: // busy_start のほうはとりあえず 10 クロックにしておく。
121: busy_start = busy_origin + 10 * clk;
122: busy_end = busy_origin + 68 * clk;
123:
1.1.1.4 root 124: switch (reg) {
125: case 0x1b:
1.1.1.6 root 126: adpcm->SetClock(data & 0x80);
127: fdc->SetForceReady(data & 0x40);
1.1.1.4 root 128: // 他のビットは未対応
129: break;
130: default:
1.1.1.5 root 131: putlog(0, "Write $%06x <- $%02x (NOT IMPLEMENTED)",
1.1.1.6 root 132: mpu->GetPaddr(), data);
1.1.1.4 root 133: break;
134: }
135: break;
136: default:
1.1.1.8 root 137: VMPANIC("corrupted offset=%u", offset);
1.1.1.6 root 138: break;
1.1.1.4 root 139: }
140:
1.1.1.7 root 141: // InsideOut p.135
142: const busdata write_wait = busdata::Wait(53 * 40_nsec);
143:
1.1.1.8 root 144: busdata r = write_wait;
145: r |= BusData::Size1;
146: return r;
1.1 root 147: }
148:
1.1.1.7 root 149: busdata
1.1.1.8 root 150: OPMDevice::PeekPort(uint32 offset)
1.1 root 151: {
152: // XXX 未実装
153: return 0xff;
154: }
1.1.1.5 root 155:
1.1.1.8 root 156: bool
157: OPMDevice::PokePort(uint32 offset, uint32 data)
158: {
159: return false;
160: }
161:
1.1.1.5 root 162: // OPM ステータスレジスタの B (BUSY) ビット
163: bool
164: OPMDevice::IsBusy() const
165: {
1.1.1.6 root 166: uint64 now = scheduler->GetVirtTime();
1.1.1.5 root 167:
168: return (busy_start <= now && now < busy_end);
169: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.