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