--- nono/vm/romemu_luna.cpp 2026/04/29 17:04:53 1.1.1.8 +++ nono/vm/romemu_luna.cpp 2026/04/29 17:04:55 1.1.1.9 @@ -18,8 +18,8 @@ // (実ROM) (LUNA-I エミュレーション) (LUNA88K エミュレーション) #include "romemu_luna.h" -#include "bitmap.h" #include "bt454.h" +#include "lunafb.h" #include "mainapp.h" #include "mk48t02.h" #include "ram.h" @@ -29,9 +29,8 @@ // コンストラクタ LunaPROMEmuDevice::LunaPROMEmuDevice() + : inherited("PROM") { - logname = "prom"; - devname = "PROM"; } // デストラクタ @@ -51,8 +50,6 @@ LunaPROMEmuDevice::Init() void LunaPROMEmuDevice::ResetHard() { - is_closed = false; - // ブートページを ROM に切り替える。 isrom = true; gVM->SwitchBootPage(this, true); @@ -89,21 +86,21 @@ LunaPROMEmuDevice::Read32(uint32 addr) { uint64 offset = Decoder(addr); - // ロングワードアクセスでだけ謎の I/O 空間が見える - if (!is_closed) { - switch (offset) { - case ROMIO_INIT - baseaddr: + // ROM からのロングワードアクセスでだけ謎の I/O 空間が見える + if ((gMPU->GetPaddr() & 0xff000000) == baseaddr) { + switch (addr) { + case ROMIO_INIT: return ROM_Init(); - case ROMIO_KEYIN - baseaddr: + case ROMIO_KEYIN: ROM_Keyin(); return 0; - case ROMIO_CLOSE - baseaddr: + case ROMIO_CLOSE: ROM_Close(); return 0; - case ROMIO_ENTRY - baseaddr: + case ROMIO_ENTRY: return ROM_Entry(); default: @@ -179,8 +176,8 @@ LunaPROMEmuDevice::InitDevice() void LunaPROMEmuDevice::InitScreen(const char *machine_name) { - text.Init(80, 32); - gBitmap->EmuConsoleOpen(&text); + text.Init(80, 32, TextScreen::Console); + gLunafb->EmuConsoleOpen(&text); inputbuf.clear(); inputpos = 0; is_shift = false; @@ -195,9 +192,6 @@ LunaPROMEmuDevice::InitScreen(const char void LunaPROMEmuDevice::ROM_Close() { - // ここでバックドアに蓋をする - is_closed = true; - // SIO からキーの Break 入力を取り除いておく。 // コマンド入力によってここへ来る時は、キーの Make で呼ばれるため // Break はまだ取り出されておらず SIO のバッファに残っている。 @@ -205,7 +199,7 @@ LunaPROMEmuDevice::ROM_Close() (void)gSIO->Read(2); // コンソールクローズ - gBitmap->EmuConsoleClose(); + gLunafb->EmuConsoleClose(); } // ROM プロンプトのキー入力。 @@ -242,74 +236,165 @@ LunaPROMEmuDevice::ROM_Keyin() return; } - switch (lunakey) { - case 0x11: // BS - if (inputpos > 0) { - inputbuf.erase(--inputpos); + // キーコードから文字を取得 + char asciicode; + if (is_shift) { + asciicode = lunakey2shifttable[lunakey]; + } else { + asciicode = lunakey2asciitable[lunakey]; + } + if (asciicode != 0) { + GetChar(asciicode); + } +} + +// キー入力ハンドラ (キー入力割り込みによって呼ばれる)。 +// 引数 asciicode は概ね ASCII コード (ただし 0x1c..0x1f が上下左右)。 +void +LunaPROMEmuDevice::GetChar(char asciicode) +{ + // LUNA1 の場合、 + // 実機 PROM にはカーソル左右移動の機能はなく、カーソルは常に行末にいる。 + // そのためかどうか Delete も BackSpace と同じく1文字前を消す動作をして + // いる。カーソル位置に文字はないので、Delete をそうするのはまあ分からん + // でもない。 + // 一方、エミュレーション ROM では、カーソルの左右移動をサポートしてみた + // ため Delete を「カーソル位置の文字を消す」にすることは出来るが、それは + // それで実機と乖離が広がるので、どうしたもんか。 + + switch (asciicode) { + case BS: + if (inputbuf.empty() == false && inputpos != 0) { + inputbuf.erase(--inputpos, 1); } break; - case 0x12: // Enter - { - // 現在位置のカーソルを消去 - int curx = prompt.length() + inputpos; - // TA::On かそうでないかしか使っていないので - // とりあえずこうしておく - text.Locate(curx, text.GetY()); + + case LF: + // 改行を起こす前にカーソル(ただの反転)を戻しておく必要がある text.SetAttr(TA::Normal); // 改行 - text.Putc('\n'); - // コマンド処理。 + text.Putc(asciicode); + prompt_y = text.GetY(); + // コマンド実行 Command(); - inputbuf.clear(); - inputpos = 0; + // プロンプトを更新 + ClearPrompt(); break; - } - case 0x1d: // ← + + case LEFT: if (inputpos > 0) { inputpos--; } break; - case 0x1e: // → + case RIGHT: if (inputpos < inputbuf.length()) { inputpos++; } break; - default: // 通常文字 - { - char asciicode; - if (is_shift) { - asciicode = lunakey2shifttable[lunakey]; - } else { - asciicode = lunakey2asciitable[lunakey]; - } - if (asciicode == 0) { - // 割り当てなし - return; - } + + case UP: + case DOWN: + case 0: // キー割り当てなし、これは来ないはずだが一応 + return; + + default: // 通常文字のはず inputbuf.insert(inputbuf.begin() + inputpos, asciicode); inputpos++; break; - } } - putmsg(2, "inputbuf=%zd|%s|", inputbuf.length(), inputbuf.c_str()); ConsoleUpdate(); } +// 入力バッファを初期化する。 +void +LunaPROMEmuDevice::ClearPrompt() +{ + prompt_y = text.GetY(); + // 入力行をクリア + inputbuf.clear(); + inputpos = 0; +} + // 画面を更新 void LunaPROMEmuDevice::ConsoleUpdate() { - // 入力行全体を都度更新 (面倒なので行をはみ出さないようにする) - std::string buf = prompt + inputbuf; - text.Print(0, text.GetY(), "%-79s", buf.c_str()); + int x; + int y; + + // カーソルを描画する予定の行が最下行を越えていたらスクロール + int len = prompt.length() + inputpos; + y = prompt_y + (len / text.GetCol()); + if (y >= text.GetRow()) { + text.ScrollUp(); + prompt_y--; + } + + // プロンプト行から下を一旦全部クリア + // (手抜きだが、見た目問題ないはず) + text.Mode = TextScreen::Fixed; + for (y = prompt_y; y < text.GetRow(); y++) { + text.Locate(0, y); + for (x = 0; x < text.GetCol(); x++) { + text.Putc(' '); + } + } + text.Locate(0, prompt_y); + text.Mode = TextScreen::Console; + + // プロンプトと現在の入力行を出力 + text.Puts(prompt.c_str()); + text.Puts(inputbuf.c_str()); + // カーソルを描画 - int curx = prompt.length() + inputpos; - // TA::On かそうでないかしか使っていないので - // とりあえずこうしておく - text.Locate(curx, text.GetY()); + y = prompt_y + (len / text.GetCol()); + x = len % text.GetCol(); + putmsg(2, "|%s|%s| pos=%d prompt_y=%d cur=(%d,%d)", + prompt.c_str(), inputbuf.c_str(), inputpos, prompt_y, x, y); + text.Locate(x, y); text.SetAttr(TA::On); + // 画面更新 - gBitmap->EmuConsoleUpdate(); + gLunafb->EmuConsoleUpdate(); +} + +// NVRAM のチェックサムを返す +uint8 +LunaPROMEmuDevice::CalcNVRAMCsum() const +{ + uint8 eor = 0; + for (uint32 addr = 0x20; addr < 0x560; addr++) { + eor ^= nvram->Peek(addr); + } + return eor; +} + +// NVRAM のチェックサムを計算して書き込む +void +LunaPROMEmuDevice::WriteNVRAMCsum() +{ + uint8 eor = CalcNVRAMCsum(); + + nvram->Write(0x001c, eor); + nvram->Write(0x001d, eor); + nvram->Write(0x001e, eor); +} + +// NVRAM のマジックとチェックサムを照合する +bool +LunaPROMEmuDevice::VerifyNVRAM() const +{ + if (nvram->PeekString(0x0004) != "") { + return false; + } + + uint8 eor = CalcNVRAMCsum(); + for (uint32 addr = 0x1c; addr < 0x1f; addr++) { + if (nvram->Peek(addr) != eor) { + return false; + } + } + return true; } // -A オプションで指定されたホストファイルをロードする。 @@ -428,10 +513,10 @@ LunaPROMEmuDevice::LoadGuestFile(const b // キーコードから文字への変換 /*static*/ const uint8 LunaPROMEmuDevice::lunakey2asciitable[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, ' ', 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, BS, LF, 0, ' ', 0, 0, 0, + 0, 0, 0, 0, UP,LEFT,RIGHT,DOWN, 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', '\\', 0, 0, 0, 'q', 'w', 'e', 'r', 't', 'y', @@ -447,12 +532,12 @@ LunaPROMEmuDevice::lunakey2asciitable[] }; /*static*/ const uint8 LunaPROMEmuDevice::lunakey2shifttable[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, ' ', 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, '!', '\"', '#', '$', '%', '&', - '\'', '(', ')', ' ', '=', '~', '|', 0, // XXX SHIFT+'0'は? + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, BS, LF, 0, ' ', 0, 0, 0, + 0, 0, 0, 0, UP,LEFT,RIGHT,DOWN, + 0, 0, '!', '\"','#', '$', '%', '&', + '\'','(', ')', ' ', '=', '~', '|', 0, // XXX SHIFT+'0'は? 0, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0, 0, 0, 0, 'A', 'S', 'D', 'F', 'G', 'H',