|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// OPM (YM2151)
//
#include "opm.h"
#include "adpcm.h"
#include "event.h"
#include "fdc.h"
#include "mainbus.h"
#include "mpu.h"
#include "scheduler.h"
// コンストラクタ
OPMDevice::OPMDevice()
: inherited(OBJ_OPM)
{
}
// デストラクタ
OPMDevice::~OPMDevice()
{
}
// 初期化
bool
OPMDevice::Init()
{
adpcm = GetADPCMDevice();
fdc = GetFDCDevice();
return true;
}
// リセット
void
OPMDevice::ResetHard(bool poweron)
{
busy_origin = 0;
busy_start = 0;
busy_end = 0;
fdc->SetForceReady(false);
}
busdata
OPMDevice::ReadPort(uint32 offset)
{
busdata data;
switch (offset) {
case 0:
putlog(0, "Read $%06x (NOT IMPLEMENTED)",
GetMainbusDevice()->GetPaddr());
data = 0;
break;
case 1:
// OPM ステータスレジスタ
data = 0;
if (IsBusy()) {
data |= 0x80;
}
// タイマ関係の bit1, bit0 は未実装
putlog(1, "STAT -> $%02x", data.Data());
break;
default:
VMPANIC("corrupted offset=%u", offset);
data = 0xff;
break;
}
// InsideOut p.135
const busdata read_wait = busdata::Wait(19 * 40_nsec);
data |= read_wait;
data |= BusData::Size1;
return data;
}
busdata
OPMDevice::WritePort(uint32 offset, uint32 data)
{
uint64 now = scheduler->GetVirtTime();
switch (offset) {
case 0:
putlog(1, "REG <- $%02x", data);
// アドレス選択が反映されるまで 8 クロックかかるらしい
// が、顕在化しないと思うので実装していない
reg = data;
break;
case 1:
putlog(1, "DATA <- $%02x", data);
// CPU が命令中のどのタイミングでライトするかを用意していないので
// 実際に OPM にライトされるタイミングは正確にはわからない。
// なので正確な時刻の起点は不明。
//
// BUSY がアサートされるまで OPM クロックで 8 から 12 クロックかかる
// らしい。
//
// BUSY のアサート期間は 68 クロックらしい。
// YM2151 アプリケーションマニュアル(英語版) 2.1.1
// BUSY フラグのみならず、書き込み処理期間中のときは保証されていない。
// とりあえず無視する。
if (busy_origin <= now && now < busy_end) {
putlog(0, "Write on Busy");
break;
}
// 時刻の起点は CPU 側の命令によって異なるはずだが
// わからないので命令のぶんは無視しておく。
// 53 クロックのウェイトのほうは足す。
busy_origin = now + 53 * mpu->GetClock_tsec();
// busy_start のほうはとりあえず 10 クロックにしておく。
busy_start = busy_origin + 10 * clk;
busy_end = busy_origin + 68 * clk;
switch (reg) {
case 0x1b:
adpcm->SetClock(data & 0x80);
fdc->SetForceReady(data & 0x40);
// 他のビットは未対応
break;
default:
putlog(0, "Write $%06x <- $%02x (NOT IMPLEMENTED)",
GetMainbusDevice()->GetPaddr(), data);
break;
}
break;
default:
VMPANIC("corrupted offset=%u", offset);
break;
}
// InsideOut p.135
const busdata write_wait = busdata::Wait(53 * 40_nsec);
busdata r = write_wait;
r |= BusData::Size1;
return r;
}
busdata
OPMDevice::PeekPort(uint32 offset)
{
// XXX 未実装
return 0xff;
}
bool
OPMDevice::PokePort(uint32 offset, uint32 data)
{
return false;
}
// OPM ステータスレジスタの B (BUSY) ビット
bool
OPMDevice::IsBusy() const
{
uint64 now = scheduler->GetVirtTime();
return (busy_start <= now && now < busy_end);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.