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