|
|
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
};
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.