--- nono/vm/mfp.cpp 2026/04/29 17:05:25 1.1.1.15 +++ nono/vm/mfp.cpp 2026/04/29 17:05:29 1.1.1.16 @@ -22,18 +22,6 @@ static const busdata wait = busdata::Wai MFPDevice::MFPDevice() : inherited(OBJ_MFP) { - for (int ch = 0; ch < event.size(); ch++) { - event[ch].dev = this; - event[ch].func = ToEventCallback(&MFPDevice::TimerCallback); - event[ch].code = ch; - event[ch].Regist(string_format("MFP Timer-%c", ch + 'A')); - } - - // キーボード周りは x68kkbd.cpp のコメント参照 - key_event.func = ToEventCallback(&MFPDevice::KeyCallback); - key_event.time = 3750_usec; - key_event.Regist("MFP USART"); - monitor.func = ToMonitorCallback(&MFPDevice::MonitorUpdate); monitor.SetSize(77, 26); monitor.Regist(ID_MONITOR_MFP); @@ -55,6 +43,20 @@ MFPDevice::Init() interrupt = GetInterruptDevice(); keyboard = dynamic_cast(GetKeyboard()); + for (int ch = 0; ch < event.size(); ch++) { + event[ch].dev = this; + event[ch].func = ToEventCallback(&MFPDevice::TimerCallback); + event[ch].code = ch; + event[ch].SetName(string_format("MFP Timer-%c", ch + 'A')); + scheduler->RegistEvent(event[ch]); + } + + // キーボード周りは x68kkbd.cpp のコメント参照 + key_event.func = ToEventCallback(&MFPDevice::KeyCallback); + key_event.time = 3750_usec; + key_event.SetName("MFP USART"); + scheduler->RegistEvent(key_event); + return true; } @@ -73,9 +75,9 @@ MFPDevice::ResetHard(bool poweron) mfp.ipr.w = 0; mfp.isr.w = 0; mfp.imr.w = 0; - for (int i = 0; i < countof(mfp.tcr); i++) { - mfp.tcr[i] = 0; - mfp.next_tdr[i] = 256; + for (int i = 0; i < countof(mfp.timer); i++) { + mfp.timer[i].tcr = 0; + mfp.timer[i].next_tdr = 256; } mfp.scr = 0; mfp.ucr = 0; @@ -108,7 +110,7 @@ MFPDevice::ResetHard(bool poweron) } busdata -MFPDevice::Read(uint32 offset) +MFPDevice::ReadPort(uint32 offset) { busdata data; @@ -150,13 +152,13 @@ MFPDevice::Read(uint32 offset) data = mfp.GetVR(); break; case MFP::TACR: - data = mfp.tcr[0]; + data = mfp.timer[0].tcr; break; case MFP::TBCR: - data = mfp.tcr[1]; + data = mfp.timer[1].tcr; break; case MFP::TCDCR: - data = (mfp.tcr[2] << 4) | mfp.tcr[3]; + data = mfp.GetTCDCR(); break; case MFP::TADR: data = GetTDR(0); @@ -192,12 +194,22 @@ MFPDevice::Read(uint32 offset) break; } + if (__predict_false(loglevel >= 3)) { + if (offset == MFP::TCDR) { + putlog(4, "%s -> $%02x", regname[offset], data.Data()); + } else if (offset < MFP::RegMax) { + putlogn("%s -> $%02x", regname[offset], data.Data()); + } else { + putlogn("$%06x -> $%02x", mpu->GetPaddr(), data.Data()); + } + } data |= wait; + data |= BusData::Size1; return data; } busdata -MFPDevice::Write(uint32 offset, uint32 data) +MFPDevice::WritePort(uint32 offset, uint32 data) { switch (offset) { case MFP::GPIP: @@ -205,7 +217,7 @@ MFPDevice::Write(uint32 offset, uint32 d mfp.gpip = data; break; case MFP::AER: - putlog(2, "AER <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); mfp.aer = data; break; case MFP::DDR: @@ -215,73 +227,73 @@ MFPDevice::Write(uint32 offset, uint32 d mfp.ddr = data; break; case MFP::IERA: - putlog(2, "IERA <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetIER(mfp.ier.a, mfp.ipr.a, data); break; case MFP::IERB: - putlog(2, "IERB <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetIER(mfp.ier.b, mfp.ipr.b, data); break; case MFP::IPRA: - putlog(2, "IPRA <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); mfp.ipr.a = data; ChangeInterrupt(); break; case MFP::IPRB: - putlog(2, "IPRB <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); mfp.ipr.b = data; ChangeInterrupt(); break; case MFP::ISRA: - putlog(2, "ISRA <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); mfp.isr.a = data; break; case MFP::ISRB: - putlog(2, "ISRB <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); mfp.isr.b = data; break; case MFP::IMRA: - putlog(2, "IMRA <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); mfp.imr.a = data; ChangeInterrupt(); break; case MFP::IMRB: - putlog(2, "IMRB <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); mfp.imr.b = data; ChangeInterrupt(); break; case MFP::VR: mfp.vr_vec = data & 0xf0; mfp.vr_s = data & 0x08; - putlog(2, "VR <- $%02x", mfp.GetVR()); + putlog(2, "%s <- $%02x", regname[offset], mfp.GetVR()); break; case MFP::TACR: - putlog(2, "TACR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetTCR(0, data); break; case MFP::TBCR: - putlog(2, "TBCR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetTCR(1, data); break; case MFP::TCDCR: - putlog(2, "TCDCR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetTCR(2, data >> 4); SetTCR(3, data & 7); break; case MFP::TADR: - putlog(2, "TADR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetTDR(0, data); break; case MFP::TBDR: - putlog(2, "TBDR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetTDR(1, data); break; case MFP::TCDR: - putlog(2, "TCDR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetTDR(2, data); break; case MFP::TDDR: - putlog(2, "TDDR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetTDR(3, data); break; case MFP::SCR: @@ -289,11 +301,11 @@ MFPDevice::Write(uint32 offset, uint32 d mfp.scr = data; break; case MFP::UCR: - putlog(2, "UCR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetUCR(data); break; case MFP::RSR: - putlog(2, "RSR <- $%02x", data); + putlog(2, "%s <- $%02x", regname[offset], data); SetRSR(data); break; case MFP::TSR: @@ -304,11 +316,13 @@ MFPDevice::Write(uint32 offset, uint32 d mfp.tsr = (mfp.tsr & 0xf0) | (data & 0x0f); break; case MFP::UDR: - if (data == 0x40 || data == 0x41) { - // MSCTRL だけ頻度が高いのでログレベルを上げておく - putlog(3, "UDR <- $%02x", data); - } else { - putlog(2, "UDR <- $%02x", data); + if (__predict_false(loglevel >= 2)) { + if (data == 0x40 || data == 0x41) { + // MSCTRL だけ頻度が高いのでログレベルを上げておく + putlog(3, "%s <- $%02x", regname[offset], data); + } else { + putlogn("%s <- $%02x", regname[offset], data); + } } SetUDR(data); break; @@ -316,11 +330,13 @@ MFPDevice::Write(uint32 offset, uint32 d break; } - return wait; + busdata r = wait; + r |= BusData::Size1; + return r; } busdata -MFPDevice::Peek(uint32 offset) +MFPDevice::PeekPort(uint32 offset) { uint8 data; @@ -362,13 +378,13 @@ MFPDevice::Peek(uint32 offset) data = mfp.GetVR(); break; case MFP::TACR: - data = mfp.tcr[0]; + data = mfp.timer[0].tcr; break; case MFP::TBCR: - data = mfp.tcr[1]; + data = mfp.timer[1].tcr; break; case MFP::TCDCR: - data = (mfp.tcr[2] << 4) | mfp.tcr[3]; + data = mfp.GetTCDCR(); break; case MFP::TADR: data = GetTDR(0); @@ -403,6 +419,12 @@ MFPDevice::Peek(uint32 offset) return data; } +bool +MFPDevice::PokePort(uint32 offset, uint32 data) +{ + return false; +} + void MFPDevice::MonitorUpdate(Monitor *, TextScreen& screen) { @@ -449,10 +471,9 @@ MFPDevice::MonitorUpdate(Monitor *, Text // 3列目(タイマー関連) x = 40; y = 0; - screen.Print(x, y++, "$%06x(TACR): $%02x", A(MFP::TACR), mfp_.tcr[0]); - screen.Print(x, y++, "$%06x(TBCR): $%02x", A(MFP::TBCR), mfp_.tcr[1]); - screen.Print(x, y++, "$%06x(TCDCR):$%02x", A(MFP::TCDCR), - (mfp_.tcr[2] << 4) | mfp_.tcr[3]); + screen.Print(x, y++, "$%06x(TACR): $%02x", A(MFP::TACR), mfp_.timer[0].tcr); + screen.Print(x, y++, "$%06x(TBCR): $%02x", A(MFP::TBCR), mfp_.timer[1].tcr); + screen.Print(x, y++, "$%06x(TCDCR):$%02x", A(MFP::TCDCR), mfp_.GetTCDCR()); screen.Print(x, y++, "$%06x(TADR): $%02x", A(MFP::TADR), tdr_[0]); screen.Print(x, y++, "$%06x(TBDR): $%02x", A(MFP::TBDR), tdr_[1]); screen.Print(x, y++, "$%06x(TCDR): $%02x", A(MFP::TCDR), tdr_[2]); @@ -477,7 +498,7 @@ MFPDevice::MonitorUpdate(Monitor *, Text "IER", "IMR", "IPR", "ISR"); for (int i = 15; i >= 0; i--, y++) { uint16 mask = (1 << i); - screen.Print(0, y, "%c%d:%-12s %-6s %-4s %-4s %-4s", + screen.Print(0, y, "%c%u:%-12s %-6s %-4s %-4s %-4s", i >= 8 ? 'A' : 'B', (i % 8), intrname[i], @@ -493,18 +514,19 @@ MFPDevice::MonitorUpdate(Monitor *, Text screen.Print(x, y++, " Mode TDR Next"); for (int ch = 0; ch < 4; ch++) { screen.Print(x, y, "Timer-%c", ch + 'A'); - if (mfp_.tcr[ch] == 0) { + uint8 tcr = mfp_.timer[ch].tcr; + if (tcr == 0) { screen.Print(x + 8, y, "Stopped"); - } else if (mfp_.tcr[ch] == 8) { + } else if (tcr == 8) { screen.Print(x + 8, y, "Event"); - } else if (mfp_.tcr[ch] > 8) { - screen.Print(x + 8, y, "Pulse(%s)", prescale_str[mfp_.tcr[ch] - 8]); + } else if (tcr > 8) { + screen.Print(x + 8, y, "Pulse(%s)", prescale_str[tcr - 8]); } else { - screen.Print(x + 8, y, "Delay(%s)", prescale_str[mfp_.tcr[ch]]); + screen.Print(x + 8, y, "Delay(%s)", prescale_str[tcr]); } - screen.Print(x + 20, y, "%3d", tdr_[ch]); - screen.Print(x + 25, y, "%3d", mfp_.next_tdr[ch] & 0xff); + screen.Print(x + 20, y, "%3u", tdr_[ch]); + screen.Print(x + 25, y, "%3u", mfp_.timer[ch].next_tdr & 0xff); y++; } @@ -514,7 +536,7 @@ MFPDevice::MonitorUpdate(Monitor *, Text screen.Puts(x, y++, " GPIP AER DDR"); for (int i = 7; i >= 0; i--, y++) { uint mask = (1 << i); - screen.Print(x, y, "b%d %-6s %d %d %s", i, gpipname[i], + screen.Print(x, y, "b%u %-6s %u %u %s", i, gpipname[i], (mfp_.gpip & mask) ? 1 : 0, (mfp_.aer & mask) ? 1 : 0, (mfp_.ddr & mask) ? "OUT" : "IN"); @@ -554,7 +576,7 @@ MFPDevice::gpipname[] = { }; // TxCR の設定値から分周期間というかメインカウンタ1回分の時間を返す -/*static*/ const int +/*static*/ const uint MFPDevice::prescale_ns[8] = { 0, 1000, // /4 @@ -579,7 +601,7 @@ MFPDevice::prescale_str[8] = { }; // タイマーのチャンネルから MFP 割り込みチャンネル番号に変換する -/*static*/ const int +/*static*/ const uint MFPDevice::timer_vector[4] = { MFP::INTR_TIMER_A, MFP::INTR_TIMER_B, @@ -608,10 +630,10 @@ MFPDevice::SetTCR(int ch, uint32 data) { uint32 prev; - prev = mfp.tcr[ch]; + prev = mfp.timer[ch].tcr; data &= 0x0f; - mfp.tcr[ch] = data; + mfp.timer[ch].tcr = data; if (data == 0) { if (prev == 0) { // 0 -> 0 なら何も起きない @@ -626,7 +648,7 @@ MFPDevice::SetTCR(int ch, uint32 data) // 停止前に求めておく。 uint64 period = prescale_ns[prev]; uint64 now = scheduler->GetVirtTime(); - mfp.tdr[ch] = ((event[ch].vtime - now) + period - 1) / period; + mfp.timer[ch].tdr = ((event[ch].vtime - now) + period - 1) / period; // でイベント停止 scheduler->StopEvent(event[ch]); @@ -642,13 +664,13 @@ MFPDevice::SetTCR(int ch, uint32 data) // タイマー開始 // TDR は触らずイベントを開始。 - uint64 period = prescale_ns[mfp.tcr[ch]]; - event[ch].time = period * mfp.tdr[ch]; + uint64 period = prescale_ns[mfp.timer[ch].tcr]; + event[ch].time = period * mfp.timer[ch].tdr; scheduler->RestartEvent(event[ch]); putlog(1, "Timer-%c Start Delay mode(%u x %u.%uusec)", ch + 'A', - mfp.tdr[ch], + mfp.timer[ch].tdr, (uint)period / 1000, (uint)(period / 100) % 10); return; @@ -657,7 +679,7 @@ MFPDevice::SetTCR(int ch, uint32 data) // イベントカウントモード // TDR をロードする - mfp.next_tdr[ch] = mfp.tdr[ch]; + mfp.timer[ch].next_tdr = mfp.timer[ch].tdr; putlog(1, "Timer-%c Event count mode", ch + 'A'); return; @@ -673,11 +695,11 @@ MFPDevice::SetTCR(int ch, uint32 data) uint8 MFPDevice::GetTDR(int ch) const { - uint8 tcr = mfp.tcr[ch]; + uint8 tcr = mfp.timer[ch].tcr; if (tcr == 0) { // 停止中なら tdr に現在値が保持されている - return mfp.tdr[ch] & 0xff; + return mfp.timer[ch].tdr & 0xff; } else if (tcr < 8) { // ディレイモード動作中なら現在値は保持していないので、 @@ -690,7 +712,7 @@ MFPDevice::GetTDR(int ch) const } else { // イベントモード、パルス幅測定モードは未対応 - return mfp.tdr[ch] & 0xff; + return mfp.timer[ch].tdr & 0xff; } } @@ -699,16 +721,16 @@ MFPDevice::GetTDR(int ch) const void MFPDevice::SetTDR(int ch, uint32 data) { - uint8& tcr = mfp.tcr[ch]; + uint8& tcr = mfp.timer[ch].tcr; if (data == 0) { data = 256; } - mfp.next_tdr[ch] = data; + mfp.timer[ch].next_tdr = data; if (tcr == 0) { // 停止中の書き込みはメインカウンタも更新。 - mfp.tdr[ch] = data; + mfp.timer[ch].tdr = data; } else if (tcr < 8) { // ディレイモード動作中の書き込みは @@ -717,7 +739,7 @@ MFPDevice::SetTDR(int ch, uint32 data) } else { // イベントモード、パルス幅測定モードは未対応 putlog(0, "Write T%cDR $%02x during unsupported mode (NOT IMPLEMENTED)", - ch + 'A', mfp.next_tdr[ch]); + ch + 'A', mfp.timer[ch].next_tdr); } } @@ -728,7 +750,7 @@ MFPDevice::TimerCallback(Event& ev) int& ch = ev.code; // TDR がゼロになったところで呼ばれるので、TDR をリロードする - mfp.tdr[ch] = mfp.next_tdr[ch]; + mfp.timer[ch].tdr = mfp.timer[ch].next_tdr; // 割り込みを上げる SetInterrupt(timer_vector[ch]); @@ -738,8 +760,8 @@ MFPDevice::TimerCallback(Event& ev) // period が1メインパルス期間 // time が1タイムアウトパルス期間 - uint64 period = prescale_ns[mfp.tcr[ch]]; - ev.time = period * mfp.tdr[ch]; + uint64 period = prescale_ns[mfp.timer[ch].tcr]; + ev.time = period * mfp.timer[ch].tdr; scheduler->RestartEvent(ev); } @@ -755,15 +777,15 @@ void MFPDevice::SetVDisp(bool vdisp) { // TAI への入力はイベントカウントモードの時のみ - if (mfp.tcr[0] == 8) { + if (mfp.timer[0].tcr == 8) { // AER が示す方向と同じエッジ方向の時 bool aer = (mfp.aer & (1 << MFP::GPIP_VDISP)); if (aer == vdisp) { // カウンタを減算 - mfp.tdr[0]--; - if (mfp.tdr[0] == 0) { + mfp.timer[0].tdr--; + if (mfp.timer[0].tdr == 0) { // 0 になったらリロード - mfp.tdr[0] = mfp.next_tdr[0]; + mfp.timer[0].tdr = mfp.timer[0].next_tdr; SetInterrupt(MFP::INTR_TIMER_A); } @@ -837,10 +859,10 @@ MFPDevice::SetUCR(uint32 data) putlog(0, "UCR CLK=0 (NOT IMPLEMENTED)"); } if (((mfp.ucr & MFP::UCR_WL) >> 5) != 0) { - putlog(0, "UCR WL=%d (NOT IMPLEMENTED)", (mfp.ucr >> 5) & 3); + putlog(0, "UCR WL=%u (NOT IMPLEMENTED)", (mfp.ucr >> 5) & 3); } if (((mfp.ucr & MFP::UCR_ST) >> 3) != 1) { - putlog(0, "UCR ST=%d (NOT IMPLEMENTED)", (mfp.ucr >> 3) & 3); + putlog(0, "UCR ST=%u (NOT IMPLEMENTED)", (mfp.ucr >> 3) & 3); } } @@ -880,7 +902,9 @@ MFPDevice::ClearBF() // 実際のハードウェアでは、キーボードが本体 MFP が Ready になるのを待って // いるが、それに相当。 // システムポートの KEYCTRL はキーボード側で処理している。 - keyboard->Ready(); + if (RxIsReady()) { + keyboard->Ready(); + } } // UDR への書き込み @@ -1035,3 +1059,31 @@ MFPDevice::InterruptAcknowledge() return data; } + +/*static*/ const char * +MFPDevice::regname[MFP::RegMax] = { + "GPIP", + "AER", + "DDR", + "IERA", + "IERB", + "IPRA", + "IPRB", + "ISRA", + "ISRB", + "IMRA", + "IMRB", + "VR", + "TACR", + "TBCR", + "TCDCR", + "TADR", + "TBDR", + "TCDR", + "TDDR", + "SCR", + "UCR", + "RSR", + "TSR", + "UDR", +};