File:  [Isaki's NoNo m68k/m88k emulator] / nono / hd64180 / hd647180io.cpp
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:01 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2022 nono project
// Licensed under nono-license.txt
//

//
// HD647180 I/O アクセス
//

#include "mpu64180.h"
#include "hd647180.h"
#include "hd647180asci.h"
#include "pio.h"
#include "scheduler.h"
#include "ssg.h"
#include "xpbus.h"

//#define ENABLE_SERIAL_LOG

uint32
MPU64180Device::ReadIO(uint32 addr)
{
	CYCLE(iowait);

	// 内蔵 I/O
	if (io_address <= addr && addr < io_address + 0x80) {
		return ReadInternalIO(addr - io_address);
	}

	return ReadExternalIO(addr);
}

uint32
MPU64180Device::ReadInternalIO(uint32 offset)
{
	uint32 data = -1;

	switch (offset) {
	 case 0x00:					// IO_CNTLA0
		data = asci->ReadCNTLA(0);
		break;
	 case 0x01:					// IO_CNTLA1
		data = asci->ReadCNTLA(1);
		break;
	 case 0x02:					// IO_CNTLB0
		data = asci->ReadCNTLB(0);
		break;
	 case 0x03:					// IO_CNTLB1
		data = asci->ReadCNTLB(1);
		break;
	 case 0x04:					// IO_STAT0
		data = asci->ReadSTAT(0);
		break;
	 case 0x05:					// IO_STAT1
		data = asci->ReadSTAT(1);
		break;
	 case 0x06:					// IO_TDR0
		data = asci->ReadTDR(0);
		break;
	 case 0x07:					// IO_TDR1
		data = asci->ReadTDR(1);
		break;
	 case 0x08:					// IO_RDR0
		data = asci->ReadRDR(0);
		break;
	 case 0x09:					// IO_RDR1
		data = asci->ReadRDR(1);
		break;

	 case 0x0a:					// IO_CNTR
	 case 0x0b:					// IO_TRDR
		break;

	 case 0x0c:					// IO_TMDR0L
		data = ReadTMDRL(0);
		break;
	 case 0x0d:					// IO_TMDR0H
		data = ReadTMDRH(0);
		break;
	 case 0x0e:					// IO_RLDR0L
		data = PeekRLDRL(0);
		break;
	 case 0x0f:					// IO_RLDR0H
		data = PeekRLDRH(0);
		break;
	 case 0x10:					// IO_TCR
		data = ReadTCR();
		break;
	 case 0x14:					// IO_TMDR1L
		data = ReadTMDRL(1);
		break;
	 case 0x15:					// IO_TMDR1H
		data = ReadTMDRH(1);
		break;
	 case 0x16:					// IO_RLDR1L
		data = PeekRLDRH(0);
		break;
	 case 0x17:					// IO_RLDR1H
		data = PeekRLDRH(1);
		break;
	 case 0x18:					// IO_FRC
		data = PeekFRC();
		break;

	 case 0x20:					// IO_SAR0L
	 case 0x21:					// IO_SAR0H
	 case 0x22:					// IO_SAR0B
	 case 0x23:					// IO_DAR0L
	 case 0x24:					// IO_DAR0H
	 case 0x25:					// IO_DAR0B
	 case 0x26:					// IO_BCR0L
	 case 0x27:					// IO_BCR0H
	 case 0x28:					// IO_MAR1L
	 case 0x29:					// IO_MAR1H
	 case 0x2a:					// IO_MAR1B
	 case 0x2b:					// IO_IAR1L
	 case 0x2c:					// IO_IAR1H
	 case 0x2e:					// IO_BCR1L
	 case 0x2f:					// IO_BCR1H
	 case 0x30:					// IO_DSTAT
	 case 0x31:					// IO_DMODE
		break;
	 case 0x32:					// IO_DCNTL
		data = PeekDCNTL();
		break;

	 case 0x33:					// IO_IL
		data = PeekIL();
		break;
	 case 0x34:					// IO_ITC
		data = PeekITC();
		break;
	 case 0x36:					// IO_RCR
		data = PeekRCR();
		break;

	 case 0x38:					// IO_CBR
		data = PeekCBR();
		break;

	 case 0x39:					// IO_BBR
		data = PeekBBR();
		break;

	 case 0x3a:					// IO_CBAR
		data = PeekCBAR();
		break;

	 case 0x3e:					// IO_OMCR
		break;
	 case 0x3f:					// IO_ICR
		data = PeekICR();
		break;

	 case 0x40:					// IO_T2FRCL
	 case 0x41:					// IO_T2FRCH
	 case 0x42:					// IO_T2OCR1L
	 case 0x43:					// IO_T2OCR1H
	 case 0x44:					// IO_T2OCR2L
	 case 0x45:					// IO_T2OCR2H
	 case 0x46:					// IO_T2ICRL
	 case 0x47:					// IO_T2ICRH
	 case 0x48:					// IO_T2CSR1
	 case 0x49:					// IO_T2CSR2
		break;

	 case 0x50:					// IO_CCSR
		break;
	 case 0x51:					// IO_RMCR
		data = PeekRMCR();
		break;

	 case 0x53:					// IO_DERA
		break;
	 case 0x60:					// IO_IODRA
		data = 0xff;
#if defined(ENABLE_SERIAL_LOG)
		putlog(0, "%s -> $%02x (NOT IMPLEMENTED)",
			IOName(offset).c_str(), data);
#endif
		return data;
	 case 0x61:					// IO_IODRB
	 case 0x62:					// IO_IODRC
	 case 0x63:					// IO_IODRD
	 case 0x64:					// IO_IODRE
	 case 0x65:					// IO_IODRF
	 case 0x66:					// IO_IDRG
	 case 0x70:					// IO_DDRA
	 case 0x71:					// IO_DDRB
	 case 0x72:					// IO_DDRC
	 case 0x73:					// IO_DDRD
	 case 0x74:					// IO_DDRE
	 case 0x75:					// IO_DDRF
		break;

	 default:
		break;
	}

	// 表示して値を返す部分はだいたいほぼ共通なので。
	if ((int32)data < 0) {
		// data が (32bitで) 負なら未実装ポート。
		data = 0xff;
		putlog(0, "ReadInternalIO %s -> $%02x (NOT IMPLEMENTED)",
			IOName(offset).c_str(), data);
	} else {
		putlog(2, "%s -> $%02x", IOName(offset).c_str(), data);
	}
	return data;
}

uint32
MPU64180Device::ReadExternalIO(uint32 addr)
{
	uint32 data = -1;

	// LUNA の外部 I/O はアドレスの上位バイト不問
	switch (addr & 0xff) {
	 case 0x82:					// SSG
	 case 0x83:					// SSG
		if (ssg) {
			data = ssg->Read1(addr);
		} else {
			data = 0xff;	// ?
		}
		break;

	 case 0x90:					// INT0 ネゲート
		// 読み込みでも (というかアクセスがあっただけで) ネゲート。
		putlog(1, "%s Negate INT0", IOName(addr).c_str());
		NegateINT0();
		// 実際何が読めるかは不明だが。
		return 0xff;

	 case 0xa0:					// レベル5 割り込み要求
	 case 0xb0:					// レベル1 割り込み要求
		// 読み込みでも割り込み上げそうだがとりあえず未実装へ回しておく。
		break;

	 default:
		break;
	}

	// 表示して値を返す部分はだいたいほぼ共通なので。
	if ((int32)data < 0) {
		// data が (32bitで) 負なら未実装ポート。
		data = 0xff;
		putlog(0, "ReadExternalIO %s -> $%02x (NOT IMPLEMENTED)",
			IOName(addr).c_str(), data);
	} else {
		putlog(2, "%s -> $%02x", IOName(addr).c_str(), data);
	}
	return data;
}

uint32
MPU64180Device::ReadTMDRL(int ch)
{
	auto& t = timer[ch];

	// TDR 読み出しで割り込みフラグクリアの実績を解除
	t.tif &= ~0x02;
	ChangeTimerInterrupt();

	// L の読み出しで count を tmp にラッチ
	t.tmpcount = t.count;

	// でラッチした L を読み出す
	return t.tmpcount & 0xff;
}

uint32
MPU64180Device::ReadTMDRH(int ch)
{
	auto& t = timer[ch];

	// TDR 読み出しで割り込みフラグクリアの実績を解除
	t.tif &= ~0x02;
	ChangeTimerInterrupt();

	// L 読み出し時にラッチしたやつを読み出す。
	return t.tmpcount >> 8;
}

uint32
MPU64180Device::ReadTCR()
{
	// TCR 読み出しで割り込みフラグクリアの実績を解除
	timer[0].tif &= ~0x01;
	timer[1].tif &= ~0x01;
	ChangeTimerInterrupt();

	return PeekTCR();
}

uint32
MPU64180Device::WriteIO(uint32 addr, uint32 data)
{
	CYCLE(iowait);

	// 内蔵 I/O
	if (io_address <= addr && addr < io_address + 0x80) {
		return WriteInternalIO(addr - io_address, data);
	}

	return WriteExternalIO(addr, data);
}

uint32
MPU64180Device::WriteInternalIO(uint32 offset, uint32 data)
{
	switch (offset) {
	 case 0x00:					// IO_CNTLA0
		return asci->WriteCNTLA(0, data);
	 case 0x01:					// IO_CNTLA1
		return asci->WriteCNTLA(1, data);
	 case 0x02:					// IO_CNTLB0
		return asci->WriteCNTLB(0, data);
	 case 0x03:					// IO_CNTLB1
		return asci->WriteCNTLB(1, data);
	 case 0x04:					// IO_STAT0
		return asci->WriteSTAT(0, data);
	 case 0x05:					// IO_STAT1
		return asci->WriteSTAT(1, data);
	 case 0x06:					// IO_TDR0
		return asci->WriteTDR(0, data);
	 case 0x07:					// IO_TDR1
		return asci->WriteTDR(1, data);
	 case 0x08:					// IO_RDR0
		return asci->WriteRDR(0, data);
	 case 0x09:					// IO_RDR1
		return asci->WriteRDR(1, data);

	 case 0x0a:					// IO_CNTR
	 case 0x0b:					// IO_TRDR
		break;

	 case 0x0c:					// IO_TMDR0L
		return WriteTMDRL(0, data);
	 case 0x0d:					// IO_TMDR0H
		return WriteTMDRH(0, data);
	 case 0x0e:					// IO_RLDR0L
		return WriteRLDRL(0, data);
	 case 0x0f:					// IO_RLDR0H
		return WriteRLDRH(0, data);
	 case 0x10:					// IO_TCR
		return WriteTCR(data);
	 case 0x14:					// IO_TMDR1L
		return WriteTMDRL(1, data);
	 case 0x15:					// IO_TMDR1H
		return WriteTMDRH(1, data);
	 case 0x16:					// IO_RLDR1L
		return WriteRLDRL(1, data);
	 case 0x17:					// IO_RLDR1H
		return WriteRLDRH(1, data);
	 case 0x18:					// IO_FRC
		// 書き込みは出来るけど、してはいけないっぽい。
		// たぶん現在値が変わるだけだと思うけど未対応。
		break;

	 case 0x20:					// IO_SAR0L
	 case 0x21:					// IO_SAR0H
	 case 0x22:					// IO_SAR0B
	 case 0x23:					// IO_DAR0L
	 case 0x24:					// IO_DAR0H
	 case 0x25:					// IO_DAR0B
	 case 0x26:					// IO_BCR0L
	 case 0x27:					// IO_BCR0H
	 case 0x28:					// IO_MAR1L
	 case 0x29:					// IO_MAR1H
	 case 0x2a:					// IO_MAR1B
	 case 0x2b:					// IO_IAR1L
	 case 0x2c:					// IO_IAR1H
	 case 0x2e:					// IO_BCR1L
	 case 0x2f:					// IO_BCR1H
	 case 0x30:					// IO_DSTAT
	 case 0x31:					// IO_DMODE
		break;
	 case 0x32:					// IO_DCNTL
		return WriteDCNTL(data);

	 case 0x33:					// IO_IL
		return WriteIL(data);
	 case 0x34:					// IO_ITC
		return WriteITC(data);
	 case 0x36:					// IO_RCR
		return WriteRCR(data);

	 case 0x38:					// IO_CBR
		return WriteCBR(data);
	 case 0x39:					// IO_BBR
		return WriteBBR(data);
	 case 0x3a:					// IO_CBAR
		return WriteCBAR(data);

	 case 0x3e:					// IO_OMCR
		break;
	 case 0x3f:					// IO_ICR
		return WriteICR(data);

	 case 0x40:					// IO_T2FRCL
	 case 0x41:					// IO_T2FRCH
	 case 0x42:					// IO_T2OCR1L
	 case 0x43:					// IO_T2OCR1H
	 case 0x44:					// IO_T2OCR2L
	 case 0x45:					// IO_T2OCR2H
	 case 0x46:					// IO_T2ICRL
	 case 0x47:					// IO_T2ICRH
	 case 0x48:					// IO_T2CSR1
	 case 0x49:					// IO_T2CSR2
		break;

	 case 0x50:					// IO_CCSR
		break;
	 case 0x51:					// IO_RMCR
		return WriteRMCR(data);

	 case 0x53:					// IO_DERA
	 case 0x60:					// IO_IODRA
	 case 0x61:					// IO_IODRB
	 case 0x62:					// IO_IODRC
	 case 0x63:					// IO_IODRD
	 case 0x64:					// IO_IODRE
	 case 0x65:					// IO_IODRF
	 case 0x66:					// IO_IDRG
	 case 0x70:					// IO_DDRA
	 case 0x71:					// IO_DDRB
	 case 0x72:					// IO_DDRC
	 case 0x73:					// IO_DDRD
	 case 0x74:					// IO_DDRE
	 case 0x75:					// IO_DDRF
		break;

	 default:
		break;
	}

	putlog(0, "WriteInternalIO %s <- $%02x (NOT IMPLEMENTED)",
		IOName(offset).c_str(), data);
	return 0;
}

uint32
MPU64180Device::WriteExternalIO(uint32 addr, uint32 data)
{
	// LUNA の外部 I/O はアドレスの上位バイト不問
	switch (addr & 0xff) {
	 case 0x82:					// SSG
	 case 0x83:					// SSG
		if (ssg) {
			ssg->Write1(addr, data);
		}
		return 0;

	 case 0x90:					// INT0 ネゲート
		putlog(1, "%s Negate INT0", IOName(addr).c_str());
		NegateINT0();
		return 0;

	 case 0xa0:					// レベル5 割り込み要求
		putlog(1, "%s Interrupt High", IOName(addr).c_str());
		pio0->InterruptXPHigh();
		return 0;

	 case 0xb0:					// レベル1 割り込み要求
		putlog(1, "%s Interrupt Low", IOName(addr).c_str());
		pio0->InterruptXPLow();
		return 0;

	 default:
		break;
	}

	putlog(0, "WriteExternalIO %s <- $%02x (NOT IMPLEMENTED)",
		IOName(addr).c_str(), data);
	return 0;
}

uint32
MPU64180Device::WriteTMDRL(int ch, uint32 data)
{
	auto& t = timer[ch];
	if (t.running) {
		// タイマー動作中の更新は inhibited と書いてあるけど、実際どうなる?
		putlog(0, "Writing %s <- $%02x while timer is running! (ignored)",
			IOName(HD647180::IO_TMDRL(ch)).c_str(), data);
	} else {
		t.count = (t.count & 0xff00) | data;
		putlog(1, "%s <- $%02x (TMDR%u = $%04x)",
			IOName(HD647180::IO_TMDRL(ch)).c_str(), data, ch, t.count);
	}
	return 0;
}

uint32
MPU64180Device::WriteTMDRH(int ch, uint32 data)
{
	auto& t = timer[ch];
	if (t.running) {
		// タイマー動作中の更新は inhibited と書いてあるけど、実際どうなる?
		putlog(0, "Writing %s <- $%02x while timer is running! (ignored)",
			IOName(HD647180::IO_TMDRH(ch)).c_str(), data);
	} else {
		t.count = (data << 8) | (t.count & 0x00ff);
		putlog(1, "%s <- $%02x (TMDR%u = $%04x)",
			IOName(HD647180::IO_TMDRH(ch)).c_str(), data, ch, t.count);
	}
	return 0;
}

uint32
MPU64180Device::WriteRLDRL(int ch, uint32 data)
{
	// 動作中にも変更可能
	auto& t = timer[ch];
	t.reload = (t.reload & 0xff00) | data;
	putlog(1, "%s <- $%02x (RLDR%u = $%04x)",
		IOName(HD647180::IO_RLDRL(ch)).c_str(), data, ch, t.reload);
	return 0;
}

uint32
MPU64180Device::WriteRLDRH(int ch, uint32 data)
{
	// 動作中にも変更可能
	auto& t = timer[ch];
	t.reload = (data << 8) | (t.reload & 0x00ff);
	putlog(1, "%s <- $%02x (RLDR%u = $%04x)",
		IOName(HD647180::IO_RLDRH(ch)).c_str(), data, ch, t.reload);
	return 0;
}

uint32
MPU64180Device::WriteTCR(uint32 data)
{
	std::array<bool, 2> new_tde;
	std::string msg;

	timer[1].intr_enable = (data & 0x20);
	timer[0].intr_enable = (data & 0x10);
	// intr_enable を変更したので ChangeTimerInterrupt() を呼ぶのは
	// 最後に行っている。

	timer_toc = (data >> 2) & 3;

	new_tde[1] = (data & 0x02);
	new_tde[0] = (data & 0x01);
	msg = string_format("TIE1=%u TIE0=%u TOC=$%x",
		(timer[1].intr_enable ? 1 : 0),
		(timer[0].intr_enable ? 1 : 0),
		timer_toc);

	for (int ch = 0; ch < timer.size(); ch++) {
		auto& t = timer[ch];
		if (t.running == false && new_tde[ch] == true) {
			// カウントダウン開始
			t.count = t.reload;
			t.running = true;
			MakeActiveTimer();
			msg += string_format(" Timer%u=Start", ch);
			EnableTimer();
		} else if (t.running == true && new_tde[ch] == false) {
			// カウントダウン停止

			// ここではタイマーの状態を停止にするだけでよい。
			// タイマーイベントの中で running が落ちてたら停止してくれる。
			t.running = false;
			MakeActiveTimer();
			msg += string_format(" Timer%u=Stop", ch);
		} else {
			// 変化なし
		}
	}

	putlog(1, "%s <- $%02x: %s",
		IOName(HD647180::IO_TCR).c_str(), data, msg.c_str());

	// ログの順序的に書き込みログの後で変更する
	ChangeTimerInterrupt();

	return 0;
}

uint32
MPU64180Device::WriteDCNTL(uint32 data)
{
	// メモリウェイト 0,1,2,3
	memwait = (data >> 6) & 3;

	// I/O ウェイトは 0,2,3,4
	iowait = (data >> 4) & 3;
	if (iowait != 0)
		iowait++;

	// 下位4ビット分は未実装
	dcntl = data & 0x0f;
	return 0;
}

uint32
MPU64180Device::WriteIL(uint32 data)
{
	// 書き込み時にマスクする
	intvec_low = data & 0xe0;
	return 0;
}

uint32
MPU64180Device::WriteITC(uint32 data)
{
	itc_trap = (data & 0x80);
	// UFO は ReadOnly
	itc_ite2 = (data & 0x04);
	itc_ite1 = (data & 0x02);
	itc_ite0 = (data & 0x01);

	// XXX 割り込み変わったら何かする?

	return 0;
}

uint32
MPU64180Device::WriteRCR(uint32 data)
{
	// 未実装
	rcr = data | 0x3c;

	if ((rcr & 0x80)) {
		// Refresh Enable は未実装。無効にするなら表示不要。
		putlog(0, "%s <- $%02x: Refresh Enable (NOT IMPLEMENTED)",
			IOName(HD647180::IO_RCR).c_str(), data);
	} else {
		// ログレベル 1 なら全部表示
		putlog(1, "%s <- $%02x (NOT IMPLEMENTED)",
			IOName(HD647180::IO_RCR).c_str(), data);
	}
	return 0;
}

uint32
MPU64180Device::WriteCBR(uint32 data)
{
	int lv;
	uint32 new_base = data << 12;
	if (commbase != new_base) {
		lv = 1;
		commbase = new_base;
	} else {
		lv = 2;
	}
	putlog(lv, "%s <- $%02x: Common Base Addr=$%05x",
		IOName(HD647180::IO_CBR).c_str(), data, commbase);
	return 0;
}

uint32
MPU64180Device::WriteBBR(uint32 data)
{
	int lv;
	uint32 new_base = data << 12;
	if (bankbase != new_base) {
		lv = 1;
		bankbase = new_base;
	} else {
		lv = 2;
	}
	putlog(lv, "%s <- $%02x: Bank Base Addr=$%05x",
		IOName(HD647180::IO_BBR).c_str(), data, bankbase);
	return 0;
}

uint32
MPU64180Device::WriteCBAR(uint32 data)
{
	int lv;
	uint32 new_comm = (data & 0xf0) << 8;
	uint32 new_bank = (data & 0x0f) << 12;
	if (commarea != new_comm || bankarea != new_bank) {
		lv = 1;
		commarea = new_comm;
		bankarea = new_bank;
	} else {
		lv = 2;
	}
	putlog(lv, "%s <- $%02x: CommArea=$%04x BankArea=$%04x",
		IOName(HD647180::IO_CBAR).c_str(), data, commarea, bankarea);
	return 0;
}

uint32
MPU64180Device::WriteICR(uint32 data)
{
	io_address = data & 0x80;
	putlog(1, "%s <- $%02x: I/O Address=$%02x",
		IOName(HD647180::IO_ICR).c_str(), data, io_address);

	// IOSTP は未実装
	if ((data & 0x20) != 0) {
		putlog(0, "%s IOSTP (NOT IMPLEMENTED)");
	}
	return 0;
}

uint32
MPU64180Device::WriteRMCR(uint32 data)
{
	xpbus->SetRMCR(data);
	putlog(1, "%s <- $%02x: RAM address=$%05x",
		IOName(HD647180::IO_RMCR).c_str(), data, xpbus->GetXPRAMAddr());
	return 0;
}

uint32
MPU64180Device::PeekIO(uint32 addr)
{
	// 内蔵 I/O
	if (io_address <= addr && addr < io_address + 0x80) {
		return PeekInternalIO(addr - io_address);
	}

	return PeekExternalIO(addr);
}

uint32
MPU64180Device::PeekInternalIO(uint32 offset)
{
	switch (offset) {
	 case 0x00:					// IO_CNTLA0
		return asci->PeekCNTLA(0);
	 case 0x01:					// IO_CNTLA1
		return asci->PeekCNTLA(1);
	 case 0x02:					// IO_CNTLB0
		return asci->PeekCNTLB(0);
	 case 0x03:					// IO_CNTLB1
		return asci->PeekCNTLB(1);
	 case 0x04:					// IO_STAT0
		return asci->PeekSTAT(0);
	 case 0x05:					// IO_STAT1
		return asci->PeekSTAT(1);
	 case 0x06:					// IO_TDR0
		return asci->PeekTDR(0);
	 case 0x07:					// IO_TDR1
		return asci->PeekTDR(1);
	 case 0x08:					// IO_RDR0
		return asci->PeekRDR(0);
	 case 0x09:					// IO_RDR1
		return asci->PeekRDR(1);

	 case 0x0a:					// IO_CNTR
	 case 0x0b:					// IO_TRDR
		break;

	 case 0x0c:					// IO_TMDR0L
		return PeekTMDRL(0);
	 case 0x0d:					// IO_TMDR0H
		return PeekTMDRH(0);
	 case 0x0e:					// IO_RLDR0L
		return PeekRLDRL(0);
	 case 0x0f:					// IO_RLDR0H
		return PeekRLDRH(0);
	 case 0x10:					// IO_TCR
		return PeekTCR();
	 case 0x14:					// IO_TMDR1L
		return PeekTMDRL(1);
	 case 0x15:					// IO_TMDR1H
		return PeekTMDRH(1);
	 case 0x16:					// IO_RLDR1L
		return PeekRLDRL(1);
	 case 0x17:					// IO_RLDR1H
		return PeekRLDRH(1);
	 case 0x18:					// IO_FRC
		return PeekFRC();

	 case 0x20:					// IO_SAR0L
	 case 0x21:					// IO_SAR0H
	 case 0x22:					// IO_SAR0B
	 case 0x23:					// IO_DAR0L
	 case 0x24:					// IO_DAR0H
	 case 0x25:					// IO_DAR0B
	 case 0x26:					// IO_BCR0L
	 case 0x27:					// IO_BCR0H
	 case 0x28:					// IO_MAR1L
	 case 0x29:					// IO_MAR1H
	 case 0x2a:					// IO_MAR1B
	 case 0x2b:					// IO_IAR1L
	 case 0x2c:					// IO_IAR1H
	 case 0x2e:					// IO_BCR1L
	 case 0x2f:					// IO_BCR1H
	 case 0x30:					// IO_DSTAT
	 case 0x31:					// IO_DMODE
		break;
	 case 0x32:					// IO_DCNTL
		return PeekDCNTL();

	 case 0x33:					// IO_IL
		return PeekIL();
	 case 0x34:					// IO_ITC
		return PeekITC();
	 case 0x36:					// IO_RCR
		return PeekRCR();

	 case 0x38:					// IO_CBR
		return PeekCBR();
	 case 0x39:					// IO_BBR
		return PeekBBR();
	 case 0x3a:					// IO_CBAR
		return PeekCBAR();

	 case 0x3e:					// IO_OMCR
		break;
	 case 0x3f:					// IO_ICR
		return PeekICR();

	 case 0x40:					// IO_T2FRCL
	 case 0x41:					// IO_T2FRCH
	 case 0x42:					// IO_T2OCR1L
	 case 0x43:					// IO_T2OCR1H
	 case 0x44:					// IO_T2OCR2L
	 case 0x45:					// IO_T2OCR2H
	 case 0x46:					// IO_T2ICRL
	 case 0x47:					// IO_T2ICRH
	 case 0x48:					// IO_T2CSR1
	 case 0x49:					// IO_T2CSR2
		break;

	 case 0x50:					// IO_CCSR
		break;
	 case 0x51:					// IO_RMCR
		return xpbus->GetRMCR();

	 case 0x53:					// IO_DERA
	 case 0x60:					// IO_IODRA
	 case 0x61:					// IO_IODRB
	 case 0x62:					// IO_IODRC
	 case 0x63:					// IO_IODRD
	 case 0x64:					// IO_IODRE
	 case 0x65:					// IO_IODRF
	 case 0x66:					// IO_IDRG
	 case 0x70:					// IO_DDRA
	 case 0x71:					// IO_DDRB
	 case 0x72:					// IO_DDRC
	 case 0x73:					// IO_DDRD
	 case 0x74:					// IO_DDRE
	 case 0x75:					// IO_DDRF
		break;

	 default:
		break;
	}
	return 0xff;
}

uint32
MPU64180Device::PeekExternalIO(uint32 addr)
{
	// LUNA の外部 I/O はアドレスの上位バイト不問
	switch (addr & 0xff) {
	 case 0x82:					// SSG
	 case 0x83:					// SSG
		if (ssg) {
			return ssg->Peek1(addr);
		}
		break;

	 case 0x90:					// INT0 ネゲート
		break;

	 case 0xa0:					// レベル5 割り込み要求
	 case 0xb0:					// レベル1 割り込み要求
		break;

	 default:
		break;
	}
	return 0xff;
}

uint32
MPU64180Device::PeekTMDRL(int ch) const
{
	return timer[ch].count & 0xff;
}

uint32
MPU64180Device::PeekTMDRH(int ch) const
{
	return timer[ch].count >> 8;
}

uint32
MPU64180Device::PeekRLDRL(int ch) const
{
	return timer[ch].reload & 0xff;
}

uint32
MPU64180Device::PeekRLDRH(int ch) const
{
	return timer[ch].reload >> 8;
}

uint32
MPU64180Device::PeekTCR() const
{
	uint32 data = (timer_toc << 2);

	if (timer[1].tif != 0)
		data |= 0x80;
	if (timer[0].tif != 0)
		data |= 0x40;
	if (timer[1].intr_enable)
		data |= 0x20;
	if (timer[0].intr_enable)
		data |= 0x10;
	if (timer[1].running)
		data |= 0x02;
	if (timer[0].running)
		data |= 0x01;

	return data;
}

uint32
MPU64180Device::PeekFRC() const
{
	if (opmode == OpMode::Reset) {
		return 0xff;
	} else {
		// Free Running Counter はリセット時に 0FFH で、
		// そこから 10φ ごとに1ずつ減っていく。
		// そのため、リセット時の時刻を覚えておき、経過時間から計算する。
		uint64 time = scheduler->GetVirtTime() - timer_epoch;
		return 0xff - (uint8)(time / (clock_tsec * 10));
	}
}

uint32
MPU64180Device::PeekDCNTL() const
{
	uint32 data;

	data = (memwait << 6);
	if (iowait != 0) {
		data |= (iowait - 1) << 4;
	}
	data |= dcntl;

	return data;
}

uint32
MPU64180Device::PeekIL() const
{
	return intvec_low;
}

uint32
MPU64180Device::PeekITC() const
{
	uint32 data = 0x38;
	if (itc_trap)
		data |= 0x80;
	if (itc_ufo)
		data |= 0x40;
	if (itc_ite2)
		data |= 0x04;
	if (itc_ite1)
		data |= 0x02;
	if (itc_ite0)
		data |= 0x01;
	return data;
}

uint32
MPU64180Device::PeekRCR() const
{
	return rcr;
}

uint32
MPU64180Device::PeekCBR() const
{
	return (commbase >> 12) & 0xff;
}

uint32
MPU64180Device::PeekBBR() const
{
	return (bankbase >> 12) & 0xff;
}

uint32
MPU64180Device::PeekCBAR() const
{
	uint32 data;

	data  = (commarea >>  8) & 0xf0;
	data |= (bankarea >> 12) & 0x0f;

	return data;
}

uint32
MPU64180Device::PeekICR() const
{
	// IOSTP は未実装
	return io_address | 0x5f;
}

uint32
MPU64180Device::PeekRMCR() const
{
	return xpbus->GetRMCR();
}

// アドレス (とあれば名前) を返す。
/*static*/ std::string
MPU64180Device::IOName(uint32 addr)
{
	std::string buf;

	if (addr < 0x100) {
		buf = string_format("%02XH", addr);
	} else {
		buf = string_format("%04XH", addr);
	}

	if (addr < ionames.size() && ionames[addr] != NULL) {
		buf += '(';
		buf += ionames[addr];
		buf += ')';
	}
	return buf;
}

/*static*/ std::vector<const char *>
MPU64180Device::ionames = {
	"CNTLA0",	// 00
	"CNTLA1",	// 01
	"CNTLB0",	// 02
	"CNTLB1",	// 03
	"STAT0",	// 04
	"STAT1",	// 05
	"TDR0",		// 06
	"TDR1",		// 07
	"RDR0",		// 08
	"RDR1",		// 09
	"CNTR",		// 0a
	"TRDR",		// 0b
	"TMDR0L",	// 0c
	"TMDR0H",	// 0d
	"RLDR0L",	// 0e
	"RLDR0H",	// 0f

	"TCR",		// 10
	NULL,		// 11
	NULL,		// 12
	NULL,		// 13
	"TMDR1L",	// 14
	"TMDR1H",	// 15
	"RLDR1L",	// 16
	"RLDR1H",	// 17
	"FRFC",		// 18
	NULL,		// 19
	NULL,		// 1a
	NULL,		// 1b
	NULL,		// 1c
	NULL,		// 1d
	NULL,		// 1e
	NULL,		// 1f

	"SAR0L",	// 20
	"SAR0H",	// 21
	"SAR0B",	// 22
	"DAR0L",	// 23
	"DAR0H",	// 24
	"DAR0B",	// 25
	"BCR0L",	// 26
	"BCR0H",	// 27
	"MAR1L",	// 28
	"MAR1H",	// 29
	"MAR1B",	// 2a
	"IAR1L",	// 2b
	"IAR1H",	// 2c
	NULL,		// 2d
	"BCR1L",	// 2e
	"BCR1H",	// 2f

	"DSTAT",	// 30
	"DMODE",	// 31
	"DCNTL",	// 32
	"IL",		// 33
	"ITC",		// 34
	NULL,		// 35
	"RCR",		// 36
	NULL,		// 37
	"CBR",		// 38
	"BBR",		// 39
	"CBAR",		// 3a
	NULL,		// 3b
	NULL,		// 3c
	NULL,		// 3d
	"OMCR",		// 3e
	"ICR",		// 3f

	"T2FRCL",	// 40
	"T2FRCH",	// 41
	"T2OCR1L",	// 42
	"T2OCR1H",	// 43
	"T2OCR2L",	// 44
	"T2OCR2H",	// 45
	"T2ICRL",	// 46
	"T2ICRH",	// 47
	"T2CSR1",	// 48
	"T2CSR2",	// 49
	NULL,		// 4a
	NULL,		// 4b
	NULL,		// 4c
	NULL,		// 4d
	NULL,		// 4e
	NULL,		// 4f

	"CCSR",		// 50
	"RMCR",		// 51
	NULL,		// 52
	"DERA",		// 53
	NULL,		// 54
	NULL,		// 55
	NULL,		// 56
	NULL,		// 57
	NULL,		// 58
	NULL,		// 59
	NULL,		// 5a
	NULL,		// 5b
	NULL,		// 5c
	NULL,		// 5d
	NULL,		// 5e
	NULL,		// 5f

	"IODRA",	// 60
	"IODRB",	// 61
	"IODRC",	// 62
	"IODRD",	// 63
	"IODRE",	// 64
	"IODRF",	// 65
	"IDRG",		// 66
	NULL,		// 67
	NULL,		// 68
	NULL,		// 69
	NULL,		// 6a
	NULL,		// 6b
	NULL,		// 6c
	NULL,		// 6d
	NULL,		// 6e
	NULL,		// 6f

	"DDRA",		// 70
	"DDRB",		// 71
	"DDRC",		// 72
	"DDRD",		// 73
	"DDRE",		// 74
	"DDRF",		// 75
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.