--- nono/vm/goldfish_tty.cpp 2026/04/29 17:05:25 1.1 +++ nono/vm/goldfish_tty.cpp 2026/04/29 17:06:00 1.1.1.6 @@ -41,6 +41,7 @@ #include "hostcom.h" #include "mainbus.h" #include "scheduler.h" +#include "syncer.h" // コンストラクタ GFTTYDevice::GFTTYDevice() @@ -52,7 +53,7 @@ GFTTYDevice::GFTTYDevice() GFTTYDevice::~GFTTYDevice() { if ((bool)hostcom) { - hostcom->SetRxCallback(NULL); + hostcom->ResetRxCallback(); } } @@ -60,11 +61,14 @@ bool GFTTYDevice::Create() { // 対応するホストドライバを作成 - hostcom.reset(new HostCOMDevice(this, "HostCOM")); + try { + hostcom.reset(new HostCOMDevice(this, 0, "GoldfishTTY")); + } catch (...) { } if ((bool)hostcom == false) { + warnx("Failed to initialize HostCOMDevice at %s", __method__); return false; } - hostcom->SetRxCallback(ToDeviceCallback(&GFTTYDevice::HostRxCallback)); + hostcom->SetRxCallback(ToDeviceCallback(&GFTTYDevice::HostRxCallback), 0); return true; } @@ -74,24 +78,21 @@ GFTTYDevice::SetLogLevel(int loglevel_) { inherited::SetLogLevel(loglevel_); - assert((bool)hostcom); - hostcom->SetLogLevel(loglevel_); + if ((bool)hostcom) { + hostcom->SetLogLevel(loglevel_); + } } // 初期化 bool GFTTYDevice::Init() { - if (inherited::Init() == false) { - return false; - } - mainbus = GetMainbusDevice(); gfpic = GetGFPICDevice(1); gfpic->RegistIRQ(32, "GFTTY", this); - scheduler->ConnectMessage(MessageID::HOSTCOM_RX, this, + scheduler->ConnectMessage(MessageID::HOSTCOM0_RX, this, ToMessageCallback(&GFTTYDevice::RxMessage)); return true; } @@ -100,47 +101,47 @@ GFTTYDevice::Init() void GFTTYDevice::ResetHard(bool poweron) { + sesame_idx = 0; rxq.clear(); intr_enable = false; ChangeInterrupt(); } busdata -GFTTYDevice::Read32(uint32 addr) +GFTTYDevice::ReadPort(uint32 offset) { - uint32 offset = addr & 0xfff; busdata data; switch (offset) { case BYTES_READY: - data = rxq.size(); - putlog(2, "BYTES_READ -> $%08x", data.Data()); + data = GetREADY(); + putlog(2, "BYTES_READY -> $%08x", data.Data()); break; case VERSION: - data = 1; + data = GFTTYVersion; putlog(2, "VERSION -> $%08x", data.Data()); break; default: - putlog(1, "Read $%08x.L", addr); + putlog(1, "Read $%08x.L", mainbus->GetPaddr()); data.SetBusErr(); break; } + data |= BusData::Size4; return data; } busdata -GFTTYDevice::Write32(uint32 addr, uint32 data) +GFTTYDevice::WritePort(uint32 offset, uint32 data) { - uint32 offset = addr & 0xfff; busdata r; switch (offset) { case PUT_CHAR: putlog(2, "PUT_CHAR <- $%02x", data); - hostcom->Tx(data); + Tx(data); break; case COMMAND: @@ -158,17 +159,33 @@ GFTTYDevice::Write32(uint32 addr, uint32 break; default: - putlog(1, "Write $%08x.L", addr); + putlog(1, "Write $%08x.L", mainbus->GetPaddr()); r.SetBusErr(); break; } + + r |= BusData::Size4; return r; } busdata -GFTTYDevice::Peek8(uint32 addr) +GFTTYDevice::PeekPort(uint32 offset) { - return busdata::BusErr; + switch (offset) { + case BYTES_READY: + return GetREADY(); + case VERSION: + return GFTTYVersion; + default: + return BusData::BusErr; + } +} + +// 着信しているバイト数を返す。 +uint32 +GFTTYDevice::GetREADY() const +{ + return rxq.size(); } void @@ -194,12 +211,12 @@ GFTTYDevice::Command(uint32 cmd) uint32 addr = dma_ptr; uint32 end = addr + dma_len; for (; addr < end; addr++) { - busdata data = mainbus->HVRead8(addr); + busdata data = mainbus->HVRead1(addr); if (data.IsBusErr()) { putlog(1, "WRITE_BUFFER: BusError at $%08x", addr); break; } - hostcom->Tx(data); + Tx(data); } break; } @@ -213,7 +230,7 @@ GFTTYDevice::Command(uint32 cmd) for (uint32 end = addr + len; addr < end; addr++) { uint32 data = rxq.front(); rxq.pop_front(); - busdata bd = mainbus->HVWrite8(addr, data); + busdata bd = mainbus->HVWrite1(addr, data); if (bd.IsBusErr()) { putlog(1, "READ_BUFFER: BusError at $%08x", addr); break; @@ -229,6 +246,40 @@ GFTTYDevice::Command(uint32 cmd) } } +// 1バイト送信。 +void +GFTTYDevice::Tx(uint32 data) +{ + // --perf によるパフォーマンス測定用のギミック。 + // GFTTY に特定の文字列を書き込むと、 + // VM 電源オン時から現在までの実時間をログに出力する。NetBSD の + // マルチユーザブートがあらかた終わってログインプロンプトが出る手前の + // /etc/rc.local に + // + // printf '\e[?68008h\e[?68008l' + // + // と書いておくことで、ここまでにかかる時間を表示できる。 + // この値はホスト性能に依存するため、同一環境下での相対比較のみ可能。 + // + // このエスケープシーケンスは DEC/xterm 拡張の設定と解除を続けて行う + // もので、68008 は空いてそうな適当な値。知らない番号の拡張機能については + // おそらく黙って何もしないだけだと思うので、どの端末エミュレータを通過 + // しても副作用は少ないと思われる。 + static const char sesame[] = "\x1b[?68008h\x1b[?68008l"; + if (__predict_false(data == sesame[sesame_idx])) { + sesame_idx++; + if (__predict_false(sesame_idx >= strlen(sesame))) { + GetSyncer()->PutlogRealtime(); + sesame_idx = 0; + } + } else { + sesame_idx = 0; + } + + // 1バイト送信。 + hostcom->Tx(data); +} + void GFTTYDevice::ChangeInterrupt() { @@ -239,9 +290,9 @@ GFTTYDevice::ChangeInterrupt() // ホストスレッドからの受信通知 // (HostCOM スレッドで呼ばれる) void -GFTTYDevice::HostRxCallback() +GFTTYDevice::HostRxCallback(uint32 dummy) { - scheduler->SendMessage(MessageID::HOSTCOM_RX); + scheduler->SendMessage(MessageID::HOSTCOM0_RX); } // ホストシリアルからの1バイト(以上)受信メッセージ