--- nono/vm/romemu_luna.cpp 2026/04/29 17:05:03 1.1.1.11 +++ nono/vm/romemu_luna.cpp 2026/04/29 17:05:11 1.1.1.13 @@ -4,8 +4,10 @@ // Licensed under nono-license.txt // +// // LUNA シリーズの ROM エミュレーション共通部分 // + // IODevice // | // +-- ROMDevice (LoadROM()、ウェイト、マスク等を持つ) @@ -30,6 +32,8 @@ #include "lunafb.h" #include "mainapp.h" #include "mk48t02.h" +#include "mpu.h" +#include "prom.h" #include "ram.h" #include "sio.h" #include "spc.h" @@ -46,13 +50,14 @@ LunaPROMEmuDevice::LunaPROMEmuDevice() // デストラクタ LunaPROMEmuDevice::~LunaPROMEmuDevice() { + gPROM = NULL; } bool LunaPROMEmuDevice::Init() { // 都度都度 dynamic_cast は面倒なので、ここで一度代入しとく - nvram = dynamic_cast(gRTC.get()); + nvram = dynamic_cast(gRTC); return true; } @@ -108,28 +113,127 @@ LunaPROMEmuDevice::InitDevice() // キーボード(chB)を初期化 gSIO->Write(3, 0x01); // CR1 gSIO->Write(3, 0x10); // RX Int(all char) - gSIO->Write(3, 0x03); // CR3 - gSIO->Write(3, 0xc1); // RX Enable, 8bit gSIO->Write(3, 0x04); // CR4 gSIO->Write(3, 0x44); // Stop 1bit + gSIO->Write(3, 0x03); // CR3 + gSIO->Write(3, 0xc1); // RX Enable, 8bit gSIO->Write(3, 0x05); // CR5 gSIO->Write(3, 0x68); // TX Enable, 8bit + + // LED を(明示的に)オフ、マウスサンプリングをオフ + gSIO->Write(2, 0x00); + gSIO->Write(2, 0x01); + gSIO->Write(2, 0x20); } // スクリーンを初期化 void -LunaPROMEmuDevice::InitScreen(const char *machine_name) +LunaPROMEmuDevice::InitScreen() { - text.Init(80, 32, TextScreen::Console); - gLunafb->EmuConsoleOpen(&text); + gLunafb->EmuInitScreen(); + + screen_w = 80; + screen_h = 32; + cursor_x = 0; + cursor_y = 0; + + // 表示範囲はざっくりセンタリングする + origin_px = (1280 - screen_w * 12) / 2; + origin_py = (1024 - screen_h * 24) / 2; + // 横は 48ドット境界から始めておく。 + // こうすると1(,2)文字目の24ビットが必ずワード境界から始まるため。 + // 今となっては任意の場所から文字が描画できるようになったので揃える + // 必要はなくなったが、依然このほうがアクセス効率はいいので。 + origin_px = (origin_px / 48) * 48; + inputbuf.clear(); inputpos = 0; is_shift = false; mousecnt = 0; +} - text.Print(0, 0, "NONO %d.%d.%d Emulated ROM Monitor for %s", +// タイトルを出力 +void +LunaPROMEmuDevice::PrintTitle(const char *machine_name) +{ + Print("NONO %d.%d.%d Emulated ROM Monitor for %s\n\n", NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, machine_name); - text.Locate(0, 2); +} + +// 1文字出力 +void +LunaPROMEmuDevice::Putc(uint ch) +{ + uint px = origin_px + cursor_x * 12; + uint py = origin_py + cursor_y * 24; + + // カーソル位置の反転を元に戻す + gLunafb->EmuPutc(px, py, ' ', ROP::INV2); + + if (ch == LF) { + put_LF: + cursor_x = 0; + if (cursor_y < screen_h - 1) { + cursor_y++; + } else { + // 上スクロールして.. + gLunafb->EmuScrollY(origin_py, origin_py + 24, (screen_h - 1) * 24); + // 最終行を消す + gLunafb->EmuFill(0, py, 1280, 24, 0); + } + } else if (ch == LEFT) { + if (cursor_x > 0) { + cursor_x--; + } else { + cursor_y--; + cursor_x = screen_w - 1; + } + } else if (ch == RIGHT) { + if (cursor_x < screen_w - 1) { + cursor_x++; + } else { + cursor_y++; + cursor_x = 0; + } + } else { + if (cursor_x < screen_w - 1) { + gLunafb->EmuPutc(px, py, ch); + cursor_x++; + } else { + gLunafb->EmuPutc(px, py, ch); + goto put_LF; + } + } + + // カーソル位置を再計算して描画 (文字を反転) + px = origin_px + cursor_x * 12; + py = origin_py + cursor_y * 24; + gLunafb->EmuPutc(px, py, ' ', ROP::INV2); +} + +// 文字列 s を出力 +void +LunaPROMEmuDevice::Print(const std::string& s) +{ + for (auto *p = s.c_str(); *p; p++) { + Putc(*p); + } +} + +// 文字列 fmt... を出力 +void +LunaPROMEmuDevice::Print(const char *fmt, ...) +{ + char buf[1024]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + for (char *p = buf; *p; p++) { + Putc(*p); + } } // ROM 処理のクローズ @@ -139,10 +243,7 @@ LunaPROMEmuDevice::ROM_Close() // SIO をリセットしておく。 // SIO のバッファにデータが残っていると、NetBSD のブートローダが // 起動してこないようだ。リセットして RXEN を落としておけば大丈夫ぽい。 - gSIO->ResetHard(); - - // コンソールクローズ - gLunafb->EmuConsoleClose(); + gSIO->ResetHard(false); } // ROM プロンプトのキー入力。 @@ -209,15 +310,21 @@ LunaPROMEmuDevice::GetChar(char asciicod case BS: if (inputbuf.empty() == false && inputpos != 0) { inputbuf.erase(--inputpos, 1); + Putc(LEFT); + for (int i = inputpos; i < inputbuf.size(); i++) { + Putc(inputbuf[i]); + } + Putc(' '); + for (int i = 0; i < 1 + inputbuf.size() - inputpos; i++) { + Putc(LEFT); + } } break; case LF: - // 改行を起こす前にカーソル(ただの反転)を戻しておく必要がある - text.SetAttr(TA::Normal); // 改行 - text.Putc(asciicode); - prompt_y = text.GetY(); + Putc(asciicode); + prompt_y = cursor_y; // コマンド実行 Command(); // プロンプトを更新 @@ -227,11 +334,13 @@ LunaPROMEmuDevice::GetChar(char asciicod case LEFT: if (inputpos > 0) { inputpos--; + Putc(LEFT); } break; case RIGHT: if (inputpos < inputbuf.length()) { inputpos++; + Putc(RIGHT); } break; @@ -242,63 +351,27 @@ LunaPROMEmuDevice::GetChar(char asciicod default: // 通常文字のはず inputbuf.insert(inputbuf.begin() + inputpos, asciicode); + for (int i = inputpos; i < inputbuf.size(); i++) { + Putc(inputbuf[i]); + } + for (int i = 0; i < inputbuf.size() - inputpos - 1; i++) { + Putc(LEFT); + } inputpos++; break; } - ConsoleUpdate(); } // 入力バッファを初期化する。 void LunaPROMEmuDevice::ClearPrompt() { - prompt_y = text.GetY(); + prompt_y = cursor_y; // 入力行をクリア inputbuf.clear(); inputpos = 0; -} -// 画面を更新 -void -LunaPROMEmuDevice::ConsoleUpdate() -{ - 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()); - - // カーソルを描画 - 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); - - // 画面更新 - gLunafb->EmuConsoleUpdate(); + Print(prompt); } // NVRAM のチェックサムを返す @@ -350,10 +423,9 @@ LunaPROMEmuDevice::LoadHostFile() uint32 entry = gRAM->LoadFile(gMainApp.exec_file); if (entry) { - text.Print("Host program loaded. Entry point = $%08x\n", - entry); + Print("Host program loaded. Entry point = $%08x\n", entry); } else { - text.Print("** Couldn't load specified host program.\n"); + Print("** Couldn't load specified host program.\n"); } return entry; } @@ -468,10 +540,10 @@ LunaPROMEmuDevice::lunakey2asciitable[] 'j', 'k', 'l', ';', ':', ']', 0, 0, 0, 0, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, // XXX テンキー - 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, '+', '-', '7', '8', '9', '4', '5', + '6', '1', '2', '3', '0', '.', LF, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, '*', '/', '=', ',', }; /*static*/ const uint8 LunaPROMEmuDevice::lunakey2shifttable[] = { @@ -487,8 +559,8 @@ LunaPROMEmuDevice::lunakey2shifttable[] 'J', 'K', 'L', '+', '*', '}', 0, 0, 0, 0, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '_', 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, // XXX テンキー - 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, '+', '-', '7', '8', '9', '4', '5', + '6', '1', '2', '3', '0', '.', LF, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, '*', '/', '=', ',', };