--- nono/vm/romemu_luna.cpp 2026/04/29 17:05:18 1.1.1.14 +++ nono/vm/romemu_luna.cpp 2026/04/29 17:05:25 1.1.1.15 @@ -29,6 +29,7 @@ #include "romemu_luna.h" #include "bt45x.h" +#include "builtinrom.h" #include "lunafb.h" #include "mainapp.h" #include "mainram.h" @@ -71,7 +72,7 @@ LunaPROMEmuDevice::Init() return true; } -uint64 +busdata LunaPROMEmuDevice::Read32(uint32 addr) { // ROM からのロングワードアクセスでだけ謎の I/O 空間が見える。 @@ -81,16 +82,40 @@ LunaPROMEmuDevice::Read32(uint32 addr) case ROMIO_INIT: return ROM_Init(); + case ROMIO_LOAD: + { + entrypoint = ROM_Load(); + putlog(2, "ROMIO_LOAD entrypoint=$%08x", entrypoint); + return 0; + } + case ROMIO_KEYIN: + putlog(2, "ROMIO_KEYIN"); ROM_Keyin(); return 0; case ROMIO_CLOSE: + putlog(2, "ROMIO_CLOSE"); ROM_Close(); return 0; case ROMIO_ENTRY: - return ROM_Entry(); + { + uint32 rv = ROM_Entry(); + putlog(2, "ROMIO_ENTRY entrypoint=$%08x", rv); + return rv; + } + + case ROMIO_AP1: + ROM_AP1(); + return 0; + + case ROMIO_AP2: + ROM_AP2(); + return 0; + + case ROMIO_CLKCNT: + return clkcnt; default: break; @@ -100,22 +125,30 @@ LunaPROMEmuDevice::Read32(uint32 addr) return inherited::Read32(addr); } -// デバイスの初期化の共通部分。(継承クラスの ROM_Init() から呼ぶ) -void -LunaPROMEmuDevice::InitDevice() +busdata +LunaPROMEmuDevice::Write32(uint32 addr, uint32 data) { - auto pio1 = GetPIO1Device(); + // ROM からのロングワードアクセスでだけ謎の I/O 空間が見える。 + // addr をマスクする前に評価すること。 + if ((mpu->GetPaddr() & 0xff000000) == baseaddr) { + switch (addr) { + case ROMIO_CLKCNT: + clkcnt = data; + return 0; + default: + break; + } + } + + return inherited::Write32(addr, data); +} +// ROM 処理の初期化。 +int +LunaPROMEmuDevice::ROM_Init() +{ // 初期パレット - // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。 - uint8 val = 0xff; - bt45x->Write(0, 0); // select palette - for (int i = 0; i < 16; i++) { - bt45x->Write(1, val); // R - bt45x->Write(1, val); // G - bt45x->Write(1, val); // B - val ^= 0xff; - } + InitPalette(); // SCSI // BDID の書き込みによってホストデバイスがバスにアタッチされる構造なので。 @@ -141,7 +174,82 @@ LunaPROMEmuDevice::InitDevice() // モードセットを行うと PortC のビットが %0 になる = 電源オフなので、 // 即座にこれをキャンセルしている。 // ROMEmu ではモードセットを行っていないが、キャンセルだけ発行しておく。 + auto pio1 = GetPIO1Device(); pio1->Write(3, 0x09); + + // 機種別の初期化 + ROM_InitMD(); + + // スクリーンを初期化 + InitScreen(); + + return 0; +} + +// 起動時の実行ファイル読み込み処理を行う。 +// 次段実行ファイルの読み込みに成功すれば execute を true にして、 +// エントリポイントを返す。 +// そうでなければ -1 を返す。 +uint32 +LunaPROMEmuDevice::ROM_Load() +{ + uint32 entry; + + entry = -1; + execute = false; + + // 表示環境が整ったところで NVRAM を照合 + if (VerifyNVRAM()) { + // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、 + // これを真似する。 + auto pio0 = GetPIO0Device(); + if (pio0->IsDIPSW11Up()) { + entry = LoadFile(""); + execute = true; + } + } else { + // LUNA-88K の PROM 1.20 は初期化するかどうか確認してくるけど、 + // とりあえず。 + InitNVRAM(); + errmsg = "NVRAM Initialized."; + // NVRAM をクリアしたら DIPSW によらずプロンプトに降りる + } + + if (entry == -1) { + PrintTitle(); + if (errmsg.empty() == false) { + Print("** %s\n\n", errmsg.c_str()); + } + ClearPrompt(); + } + + return entry; +} + +// 実行ファイルに処理を移すならそのエントリポイントを返す。 +// そうでなければ -1 を返す。 +uint32 +LunaPROMEmuDevice::ROM_Entry() +{ + if (execute == false) { + return -1; + } + return entrypoint; +} + +// パレットを初期化 +void +LunaPROMEmuDevice::InitPalette() +{ + // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。 + uint8 val = 0xff; + bt45x->Write(0, 0); // select palette + for (int i = 0; i < 16; i++) { + bt45x->Write(1, val); // R + bt45x->Write(1, val); // G + bt45x->Write(1, val); // B + val ^= 0xff; + } } // スクリーンを初期化 @@ -154,6 +262,7 @@ LunaPROMEmuDevice::InitScreen() screen_h = 32; cursor_x = 0; cursor_y = 0; + cursor_on = true; // 表示範囲はざっくりセンタリングする origin_px = (1280 - screen_w * 12) / 2; @@ -164,6 +273,8 @@ LunaPROMEmuDevice::InitScreen() // 必要はなくなったが、依然このほうがアクセス効率はいいので。 origin_px = (origin_px / 48) * 48; + cursor_on = true; + inputbuf.clear(); inputpos = 0; is_shift = false; @@ -172,7 +283,7 @@ LunaPROMEmuDevice::InitScreen() // タイトルを出力 void -LunaPROMEmuDevice::PrintTitle(const char *machine_name) +LunaPROMEmuDevice::PrintTitle() { Print("NONO %d.%d.%d Emulated ROM Monitor for %s\n\n", NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, machine_name); @@ -185,11 +296,33 @@ LunaPROMEmuDevice::Putc(uint ch) uint px = origin_px + cursor_x * 12; uint py = origin_py + cursor_y * 24; - // カーソル位置の反転を元に戻す - lunafb->EmuPutc(px, py, ' ', ROP::INV2); + if (cursor_on) { + // カーソル位置の反転を元に戻す + lunafb->EmuPutc(px, py, ' ', ROP::INV2); + } + + // いくつかの制御コードを勝手に使う。 + switch (ch) { + case 0x0f: // SI + bold = true; + break; + case 0x0e: // SO + bold = false; + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + // カラーコード変更 + lunafb->SetBMSEL(ch - 0x10); + break; + + case CR: + break; - if (ch == LF) { - put_LF: + case LF: + put_LF: cursor_x = 0; if (cursor_y < screen_h - 1) { cursor_y++; @@ -199,34 +332,56 @@ LunaPROMEmuDevice::Putc(uint ch) // 最終行を消す lunafb->EmuFill(0, py, 1280, 24, 0); } - } else if (ch == LEFT) { + break; + + case LEFT: if (cursor_x > 0) { cursor_x--; } else { cursor_y--; cursor_x = screen_w - 1; } - } else if (ch == RIGHT) { + break; + + case RIGHT: if (cursor_x < screen_w - 1) { cursor_x++; } else { cursor_y++; cursor_x = 0; } - } else { - if (cursor_x < screen_w - 1) { + break; + + default: + if (ch < 0x80) { lunafb->EmuPutc(px, py, ch); - cursor_x++; + if (bold) { + for (int i = 1; i < 2; i++) { + lunafb->EmuPutc(px + i, py, ch, ROP::OR1); + } + } } else { - lunafb->EmuPutc(px, py, ch); + lunafb->EmuPutc(px, py, ' '); + lunafb->EmuPutc(px, py + 10, ch); + if (bold) { + for (int i = 1; i < 2; i++) { + lunafb->EmuPutc(px + i, py + 10, ch, ROP::OR1); + } + } + } + cursor_x++; + if (cursor_x >= screen_w) { goto put_LF; } + break; } - // カーソル位置を再計算して描画 (文字を反転) - px = origin_px + cursor_x * 12; - py = origin_py + cursor_y * 24; - lunafb->EmuPutc(px, py, ' ', ROP::INV2); + if (cursor_on) { + // カーソル位置を再計算して描画 (文字を反転) + px = origin_px + cursor_x * 12; + py = origin_py + cursor_y * 24; + lunafb->EmuPutc(px, py, ' ', ROP::INV2); + } } // 文字列 s を出力 @@ -262,6 +417,11 @@ LunaPROMEmuDevice::ROM_Close() // SIO のバッファにデータが残っていると、NetBSD のブートローダが // 起動してこないようだ。リセットして RXEN を落としておけば大丈夫ぽい。 sio->ResetHard(false); + + // 実行ファイルにジャンプ後、NMI でプロンプトにもう一度戻ってこれるので + // その時のためにエントリポイント等も初期化しておく。 + entrypoint = -1; + execute = false; } // ROM プロンプトのキー入力。 @@ -273,7 +433,7 @@ LunaPROMEmuDevice::ROM_Keyin() { int asciicode = Getc(); - if (asciicode != -1) { + if (cursor_on && asciicode != -1) { ProcessChar(asciicode); } } @@ -454,8 +614,28 @@ LunaPROMEmuDevice::VerifyNVRAM() const return true; } +static const uint8 __unused test0[] = { + 0x12, 0x0f, 0x4e, 0x4f, 0x4e, 0x4f, 0x0e, 0x1e, 0x13, 0x00, +}; +static const uint8 __unused test1[] = { + 0xcd, 0xd5, 0xcc, 0xd4, 0xc9, 0xad, 0xd2, 0xc9, 0xd3, 0xc3, + 0x20, 0xd7, 0xcf, 0xd2, 0xcb, 0xd3, 0xd4, 0xc1, 0xd4, 0xc9, + 0xcf, 0xce, 0x20, 0x11, 0x0f, 0x4c, 0x55, 0x4e, 0x41, 0x2d, + 0x38, 0x38, 0x4b, 0x00, 0xaa, 0x12, 0x43, 0x58, 0xc2, 0x00, +}; +static const uint8 __unused test2[] = { + 0xc8, 0xcf, 0xcc, 0xcf, 0xce, 0xc9, 0xc3, 0x20, 0xd7, 0xcf, + 0xd2, 0xcb, 0xd3, 0xd4, 0xc1, 0xd4, 0xc9, 0xcf, 0xce, 0x20, + 0x11, 0x0f, 0x4c, 0x55, 0x4e, 0x41, 0x00, 0x21, 0xd8, 0x67, +}; +static const uint8 __unused test3[] = { + 0x0e, 0x1e, 0x13, 0xd3, 0xc5, 0xd2, 0xc9, 0xc5, 0xd3, 0x0a, + 0x00, 0x0f, 0xd0, 0x4f, 0x7e, 0x40, 0x41, 0xcc, 0xdf, 0x09, +}; + // -X オプションで指定されたホストファイルをロードする。 // ロードできればエントリポイントを返す。 +// 失敗ならエラーメッセージを errmsg にセットして (uint32)-1 を返す。 // exec_file が指定されている時に呼ぶこと。 uint32 LunaPROMEmuDevice::LoadHostFile() @@ -463,18 +643,17 @@ LunaPROMEmuDevice::LoadHostFile() assert(gMainApp.exec_file); LoadInfo info(gMainApp.exec_file); - if (mainram->LoadFromFile(&info)) { - Print("Host program loaded. Entry point = $%08x\n", info.entry); + if (mainram->LoadExec(&info)) { return info.entry; } else { - Print("** Couldn't load specified host program.\n"); - return 0; + errmsg = "Couldn't load specified host program."; + return -1; } } // bootinfo に従ってゲストから起動先をロードする。 -// 成功すればエントリポイントを返す。 -// 失敗ならをエラーメッセージを errmsg にセットして (uint32)-1 を返す。 +// ロードできればエントリポイントを返す。 +// 失敗ならエラーメッセージを errmsg にセットして (uint32)-1 を返す。 uint32 LunaPROMEmuDevice::LoadGuestFile(const bootinfo_t& bootinfo) { @@ -558,7 +737,7 @@ LunaPROMEmuDevice::LoadGuestFile(const b std::string name = string_format("SCSIHD %d,%c:%s", id, dkpart + 'a', dkfile.c_str()); LoadInfo info(name.c_str(), f.data.data(), f.data.size()); - if (mainram->LoadFromData(&info) == false) { + if (mainram->LoadExec(&info) == false) { errmsg = string_format("dk%d,%c,%s load failed", dkunit, dkpart + 'a', dkfile.c_str()); putmsg(0, "%s: %s", __func__, errmsg.c_str()); @@ -575,6 +754,82 @@ LunaPROMEmuDevice::LoadGuestFile(const b return info.entry; } +void +LunaPROMEmuDevice::ROM_AP1() +{ + char buf[100]; + int n; + + cursor_on = false; + + static uint8 ap1pal[] = { + 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xf8, + 0xf8, 0xf8, 0x00, + 0xf8, 0xf8, 0xf8, + }; + bt45x->Write(0, 0); + for (int i = 0; i < countof(ap1pal); i++) { + bt45x->Write(1, ap1pal[i]); + } + + Print(std::string((const char *)test0)); + if (gMainApp.IsLUNA88K()) { + Print(std::string((const char *)test1)); + } else { + Print(std::string((const char *)test2)); + } + Print(std::string((const char *)test3)); + + n = strlcpy(buf, (const char *)&Builtin::IPLROM30[0x111e3], sizeof(buf)); + snprintf(buf + n, sizeof(buf) - n, "%d.%d.%d %s", + NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, NONO_DATE); + for (int i = 0; buf[i]; i++) { + if (buf[i] == '/') + buf[i] = '.'; + } + Print("%s\n", buf); + + memcpy(buf, &Builtin::IPLROM30[0x111f5], 0x28); + memcpy(buf + 0x1e, mpu->GetMPUName(), 7); + n = 0x27; + n += snprintf(buf + n, sizeof(buf) - n, "%4.1f", + (double)mpu->GetClockSpeed() / 1000); + strlcpy(buf + n, (const char *)&Builtin::IPLROM30[0x1121f], + sizeof(buf) - n); + Print(std::string(buf)); + + strlcpy(buf, (const char *)&Builtin::IPLROM30[0x11226], sizeof(buf)); + if (gMainApp.Has(VMCap::M88K)) { + memcpy(buf + 0x1e, mpu->GetMPUName(), 7); + memcpy(buf + 0x25, &Builtin::IPLROM30[0x11251], 3); + } + Print(std::string(buf)); + + strlcpy(buf, (const char *)&Builtin::IPLROM30[0x11254], sizeof(buf)); + buf[0x0c] = 'e'; + if (gMainApp.Has(VMCap::M88K)) { + memcpy(buf + 0x1e, mpu->GetMPUName(), 7); + memcpy(buf + 0x25, &Builtin::IPLROM30[0x1127d], 3); + buf[0x22] = 0x32; + } + Print(std::string(buf)); + + strlcpy(buf, (const char *)&Builtin::IPLROM30[0x11280], sizeof(buf)); + n = 0x1e; + n += snprintf(buf + n, sizeof(buf) - n, "%d", mainram->GetSizeMB()); + strlcpy(buf + n, (const char *)&Builtin::IPLROM30[0x1129f], + sizeof(buf) - n); + Print(std::string(buf)); +} + +void +LunaPROMEmuDevice::ROM_AP2() +{ + InitPalette(); + InitScreen(); +} + // キーコードから文字への変換 /*static*/ const uint8 LunaPROMEmuDevice::lunakey2asciitable[] = {