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