--- nono/vm/romemu_luna88k.cpp 2026/04/29 17:05:03 1.1.1.9 +++ nono/vm/romemu_luna88k.cpp 2026/04/29 17:05:14 1.1.1.12 @@ -4,8 +4,10 @@ // Licensed under nono-license.txt // +// // LUNA88K の ROM エミュレーション // + // IODevice // | // +-- ROMDevice (LoadROM()、ウェイト、マスク等を持つ) @@ -26,16 +28,14 @@ // +-- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ) #include "romemu_luna88k.h" +#include "interrupt.h" #include "iodevstream.h" -#include "lunafb.h" -#include "m88100.h" #include "mainapp.h" #include "memorystream.h" #include "mk48t02.h" #include "mpu88xx0.h" #include "pio.h" #include "ram.h" -#include "sysctlr.h" static bool luna88k_fline_callback(m88kcpu *cpu, void *arg); @@ -66,54 +66,59 @@ enum OPcr { psr = 0x01, }; -static constexpr uint32 OP3(uint32 base, uint32 rd, uint32 rs1, uint32 rs2) { +#define USC __unused static constexpr + +USC uint32 OP3(uint32 base, uint32 rd, uint32 rs1, uint32 rs2) { return (base) | (rd << 21) | (rs1 << 16) | rs2; } -static constexpr uint32 OP4(uint32 base, uint32 rd, uint32 rs1, +USC uint32 OP4(uint32 base, uint32 rd, uint32 rs1, uint32 w, uint32 o) { return (base) | (rd << 21) | (rs1 << 16) | (w << 5) | o; } -static constexpr uint32 OP_addu(OPr rd, OPr rs1, uint32 imm) { +USC uint32 OP_addu(OPr rd, OPr rs1, uint32 imm) { return OP3(0x60000000, (uint32)rd, (uint32)rs1, imm); } -static constexpr uint32 OP_bcnd(OPm5 m5, OPr rs1, uint32 d16) { - return OP3(0xe8000000, (uint32)m5, (uint32)rs1, d16); +USC uint32 OP_addu(OPr rd, OPr rs1, OPr rs2) { + return OP3(0xf4006000, (uint32)rd, (uint32)rs1, (uint32)rs2); } -static constexpr uint32 OP_bsr(uint32 d26) { - return (0xc8000000 | d26); +USC uint32 OP_bcnd(OPm5 m5, OPr rs1, uint32 d16) { + return OP3(0xe8000000, (uint32)m5, (uint32)rs1, d16 & 0xffff); } -static constexpr uint32 OP_clr(OPr rd, OPr rs1, uint32 w, uint32 o) { +USC uint32 OP_bsr(uint32 d26) { + return (0xc8000000 | (d26 & 0x03ffffff)); +} +USC uint32 OP_clr(OPr rd, OPr rs1, uint32 w, uint32 o) { return OP4(0xf0008000, (uint32)rd, (uint32)rs1, w, o); } -static constexpr uint32 OP_jmp(OPr rs2) { +USC uint32 OP_jmp(OPr rs2) { return OP3(0xf400c000, 0, 0, (uint32)rs2); } -static constexpr uint32 OP_ld(OPr rd, OPr rs1, uint32 imm) { +USC uint32 OP_ld(OPr rd, OPr rs1, uint32 imm) { return OP3(0x14000000, (uint32)rd, (uint32)rs1, imm); } -static constexpr uint32 OP_ldcr(OPr rd, uint32 crs) { +USC uint32 OP_ldcr(OPr rd, uint32 crs) { return OP4(0x80004000, (uint32)rd, 0, crs, 0); } -static constexpr uint32 __unused OP_or(OPr rd, OPr rs1, OPr rs2) { +USC uint32 __unused OP_or(OPr rd, OPr rs1, OPr rs2) { return OP3(0xf4005800, (uint32)rd, (uint32)rs1, (uint32)rs2); } -static constexpr uint32 OP_or(OPr rd, OPr rs1, uint32 imm) { +USC uint32 OP_or(OPr rd, OPr rs1, uint32 imm) { return OP3(0x58000000, (uint32)rd, (uint32)rs1, imm); } -static constexpr uint32 OP_or_u(OPr rd, OPr rs1, uint32 imm) { +USC uint32 OP_or_u(OPr rd, OPr rs1, uint32 imm) { return OP3(0x5c000000, (uint32)rd, (uint32)rs1, imm); } -static constexpr uint32 OP_rte() { +USC uint32 OP_rte() { return 0xf400fc00; } -static constexpr uint32 OP_st(OPr rd, OPr rs1, OPr rs2) { +USC uint32 OP_st(OPr rd, OPr rs1, OPr rs2) { return OP3(0xf4002400, (uint32)rd, (uint32)rs1, (uint32)rs2); } -static constexpr uint32 OP_stcr(OPr rs1, uint32 crd) { +USC uint32 OP_stcr(OPr rs1, uint32 crd) { return OP4(0x80008000, 0, (uint32)rs1, crd, (uint32)rs1); } -static constexpr uint32 OP_doscall(OPr rd, OPr rs1, uint32 imm) { +USC uint32 OP_doscall(OPr rd, OPr rs1, uint32 imm) { return OP3(0xfc000400, (uint32)rd, (uint32)rs1, imm); } #define DOS_GETCHAR (1) @@ -175,20 +180,20 @@ Luna88kPROMEmuDevice::Init() // RAM に切り替え ms.Write32(OP_st (r0, r6, r0)); - // 元の PSR を r10 に保存しつつ割り込み許可 + // 元の PSR を r10 に保存し、r9 に割り込み許可の値を作る ms.Write32(OP_ldcr (r10, psr)); - ms.Write32(OP_clr (r2, r10, 2, 0)); // clear IND,SFRZ - ms.Write32(OP_stcr (r2, psr)); + ms.Write32(OP_clr (r9, r10, 2, 0)); // clear IND,SFRZ ms.Write32(OP_or_u (r3, r0, ROMIO_BASE >> 16)); ms.Write32(OP_or (r3, r3, ROMIO_BASE & 0xfff)); // ROMIO_INIT を読み出す ms.Write32(OP_ld (r2, r3, (ROMIO_INIT - ROMIO_BASE))); // 起動先があれば GO - ms.Write32(OP_bcnd (ne0, r2, 5)); // 5 = _go + ms.Write32(OP_bcnd (ne0, r2, 7)); // 7 = _go // _prompt: // 疑似 STOP でキー入力を待つ + ms.Write32(OP_stcr (r9, psr)); // 割り込み許可 ms.Write32(OP_bsr (1)); // 1 = _stop // この時点で r1 = _stop @@ -196,34 +201,35 @@ Luna88kPROMEmuDevice::Init() ms.Write32(OP_jmp (r1)); // _back: + // 割り込み禁止に戻す + ms.Write32(OP_stcr (r10, psr)); + ms.Write32(OP_ld (r2, r3, (ROMIO_ENTRY - ROMIO_BASE))); // 起動先がなければループ - ms.Write32(OP_bcnd (eq0, r2, 0xfffd)); // 0xfffd = _prompt + ms.Write32(OP_bcnd (eq0, r2, -5)); // -5 = _prompt // _go: // 起動先があれば後始末して ms.Write32(OP_ld (r0, r3, (ROMIO_CLOSE - ROMIO_BASE))); - // 割り込み禁止に戻す - ms.Write32(OP_stcr (r10, psr)); // ジャンプ ms.Write32(OP_jmp (r2)); // ここから割り込みハンドラ。割り込みは SIO のみ許可にしてある。 // キーボード割り込みが上がったら KEYIN をコールして _back に戻る。 - ms.SetPtr(&imagebuf[0x200]); + ms.SetOffset(0x200); ms.Write32(OP_ld (r0, r3, (ROMIO_KEYIN - ROMIO_BASE))); // 戻ったところの jmp を抜ける ms.Write32(OP_addu (r1, r1, 0x04)); ms.Write32(OP_rte ()); // ROM GETC エミュレータ - ms.SetPtr(&imagebuf[0x300]); + ms.SetOffset(0x300); ms.Write32(OP_doscall(r2, r0, DOS_GETCHAR)); ms.Write32(OP_jmp (r1)); // ROM PUTC エミュレータ // 表示する文字は r3 に置かれている。 - ms.SetPtr(&imagebuf[0x400]); + ms.SetOffset(0x400); ms.Write32(OP_doscall(r0, r3, DOS_PUTCHAR)); ms.Write32(OP_jmp (r1)); @@ -233,21 +239,17 @@ Luna88kPROMEmuDevice::Init() return true; } -void -Luna88kPROMEmuDevice::ResetHard() -{ - b_entrypoint = 0; -} - // 起動時の処理を行う。 // 次段実行ファイルの読み込みに成功すればそのエントリポイントを返す。 // そうでなければ 0 を返すので、プロンプトに処理を移すこと。 uint32 Luna88kPROMEmuDevice::ROM_Init() { - IODeviceStream rs(gRAM.get()); + IODeviceStream rs(gRAM); uint32 entry; + b_entrypoint = 0; + // デバイスの初期化 (親クラス) InitDevice(); @@ -285,7 +287,7 @@ Luna88kPROMEmuDevice::ROM_Init() rs.Write32(0x00000001); // スクリーンを初期化 - InitScreen("LUNA88K"); + InitScreen(); entry = 0; @@ -293,42 +295,43 @@ Luna88kPROMEmuDevice::ROM_Init() if (VerifyNVRAM() == false) { // PROM 1.20 は初期化するかどうか確認してくるけど、とりあえず。 InitNVRAM(); - text.Print("** NVRAM Initialized.\n"); - text.Print("\n"); + errmsg = "NVRAM Initialized."; // NVRAM をクリアしたら DIPSW によらずプロンプトに降りる goto done; } - // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、 - // これを真似する。 - if ((gPIO0->GetDIPSW1() & 0x80)) { - if (gMainApp.exec_file) { - // ホストのファイルを読み込んでエントリポイントアドレスを - // この Read アクセスの読み出し値として返す。 - // エラーがあればエラーメッセージは呼び出し先側で表示してある。 - entry = LoadHostFile(); - } else { + // -X file + // DIPSW の状態に関わらず、ファイルをロードし実行する。 + // --load-only file + // DIPSW の状態に関わらず、ファイルをロードし、プロンプトで止まる。 + if (gMainApp.exec_file) { + // ホストのファイルを読み込んでエントリポイントアドレスを + // この Read アクセスの読み出し値として返す。 + // エラーがあればエラーメッセージは呼び出し先側で表示してある。 + b_entrypoint = LoadHostFile(); + if (gMainApp.load_and_exec) { + entry = b_entrypoint; + } + } else { + // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、 + // これを真似する。 + if (gPIO0->IsDIPSW11Up()) { // NVRAM の設定に従ってブート先を探す。 errmsg.clear(); bootinfo_t bootinfo; GetNVRAM(bootinfo); entry = LoadGuestFile(bootinfo); - if (entry == 0) { - text.Print("** %s\n", errmsg.c_str()); - } } } - // ここまでタイトルなどを Print してはいるが、実際の画面更新は - // ConsoleUpdate() を呼ぶまで行われないことを利用(悪用?)して、 - // ここでエラーなくブートプログラムに制御を渡せる場合には何も表示せずに - // ゲストに処理を移す。意図して或いは意図せずプロンプトに降りる場合だけ - // ConsoleUpdate を呼ぶことでタイトルを含めて画面を表示する。 done: if (entry == 0) { + PrintTitle("LUNA88K"); + if (errmsg.empty() == false) { + Print("** %s\n\n", errmsg.c_str()); + } ClearPrompt(); - ConsoleUpdate(); } return entry; @@ -355,9 +358,8 @@ Luna88kPROMEmuDevice::GetChar(char ascii // 0 以外ならノンブロッキングモード // 入力されたキーを表示 - text.SetAttr(TA::Normal); if (' ' <= asciicode && asciicode < 0x7f) { - text.Putc(asciicode); + Putc(asciicode); } switch (prompt_idx) { @@ -377,10 +379,8 @@ Luna88kPROMEmuDevice::GetChar(char ascii // プロンプトを戻す prompt = default_prompt; prompt_idx = 0; - prompt_y = text.GetY(); - - // こっちは画面更新をする必要がある - ConsoleUpdate(); + prompt_y = cursor_y; + ClearPrompt(); } } @@ -433,7 +433,7 @@ Luna88kPROMEmuDevice::Command() return; } - text.Print("** Unknown command: %s\n", arg[0].c_str()); + Print("** Unknown command: %s\n", arg[0].c_str()); } // "h" コマンド @@ -445,7 +445,7 @@ Luna88kPROMEmuDevice::CommandH(const std if (arg.size() < 2) { // ヘルプメッセージ mainhelp: - text.Print( + Print( " *** Help Message ***\n" " b : load and execute program\n" " h : show this message\n" @@ -456,7 +456,7 @@ Luna88kPROMEmuDevice::CommandH(const std const std::string& key = arg[1]; if (key == "nvram") { - text.Print( + Print( " *** Help Message ***\n" " nvram [] : show\n" " nvram : set\n" @@ -482,7 +482,7 @@ Luna88kPROMEmuDevice::CommandB(const std GetNVRAM(bootinfo); b_entrypoint = LoadGuestFile(bootinfo); if (b_entrypoint == 0) { - text.Print("** %s\n", errmsg.c_str()); + Print("** %s\n", errmsg.c_str()); } } @@ -493,7 +493,7 @@ Luna88kPROMEmuDevice::CommandBH() { // 指定されてたら読み込む if (gMainApp.exec_file == NULL) { - text.Print("** Cannot loaded; host program is not specified.\n"); + Print("** Cannot loaded; host program is not specified.\n"); return; } b_entrypoint = LoadHostFile(); @@ -530,7 +530,7 @@ Luna88kPROMEmuDevice::CommandNvram(const } break; default: - text.Print("** Syntax error\n"); + Print("** Syntax error\n"); } } @@ -563,7 +563,7 @@ Luna88kPROMEmuDevice::CommandNvramShowAl continue; } std::string val = nvram->PeekString(offset + 16); - text.Print("%-15s : %s\n", key.c_str(), val.c_str()); + Print("%-15s : %s\n", key.c_str(), val.c_str()); } } @@ -578,9 +578,9 @@ Luna88kPROMEmuDevice::CommandNvramShow(c uint32 offset = FindNVRAM(key); if (offset > 0) { std::string val = nvram->PeekString(offset + 16); - text.Print("%-15s : %s\n", key.c_str(), val.c_str()); + Print("%-15s : %s\n", key.c_str(), val.c_str()); } else { - text.Print("** Not found\n"); + Print("** Not found\n"); } } @@ -597,11 +597,11 @@ Luna88kPROMEmuDevice::CommandNvramUpdate putmsg(1, "nvram Update |%s|%s|", nvram_key.c_str(), nvram_val.c_str()); if (nvram_key.size() > 16) { - text.Print("** Key too long\n"); + Print("** Key too long\n"); return; } if (nvram_val.size() > 16) { - text.Print("** Val too long\n"); + Print("** Val too long\n"); return; } @@ -621,7 +621,7 @@ Luna88kPROMEmuDevice::CommandNvramUpdate // 先に空き領域をチェックしている nvram_offset = FindNVRAM(""); if (nvram_offset == 0) { - text.Print("** No area available\n"); + Print("** No area available\n"); return; } @@ -642,20 +642,20 @@ Luna88kPROMEmuDevice::CommandNvramUpdate assert(nvram_offset > 0); assert(nvram_val.size() <= 16); - text.CRLF(); + Putc('\n'); if (asciicode != 'y' && asciicode != 'Y') { - text.Print("** Not updated\n"); + Print("** Not updated\n"); return; } if (nvram->WriteString(nvram_offset + 16, nvram_val) == false) { - text.Print("** Write error\n"); + Print("** Write error\n"); return; } WriteNVRAMCsum(); - text.Print("Updated\n"); + Print("Updated\n"); } // NVRAM 項目を追加 (キー入力後) @@ -668,21 +668,21 @@ Luna88kPROMEmuDevice::CommandNvramNew2(c assert(nvram_key.size() <= 16); assert(nvram_val.size() <= 16); - text.CRLF(); + Putc('\n'); if (asciicode != 'y' && asciicode != 'Y') { - text.Print("** Not added\n"); + Print("** Not added\n"); return; } if (nvram->WriteString(nvram_offset, nvram_key) == false || nvram->WriteString(nvram_offset + 16, nvram_val) == false) { - text.Print("** Write error\n"); + Print("** Write error\n"); return; } WriteNVRAMCsum(); - text.Print("Added\n"); + Print("Added\n"); } // NVRAM 項目削除 @@ -699,13 +699,13 @@ Luna88kPROMEmuDevice::CommandNvramDelete putmsg(1, "nvram Delete |%s|", key.c_str()); if (key.size() > 16) { - text.Print("** key too long\n"); + Print("** key too long\n"); return; } uint32 offset = FindNVRAM(key); if (offset == 0) { - text.Print("** Not found\n"); + Print("** Not found\n"); return; } @@ -748,15 +748,15 @@ Luna88kPROMEmuDevice::CommandNvramInit2( { assert(prompt_idx == PROMPT_NVRAM_INIT); - text.CRLF(); + Putc('\n'); if (asciicode != 'y' && asciicode != 'Y') { - text.Print("** Not initialized\n"); + Print("** Not initialized\n"); return; } InitNVRAM(); - text.Print("** Initialized\n"); + Print("** Initialized\n"); } // NVRAM を初期化する @@ -836,11 +836,11 @@ Luna88kPROMEmuDevice::FLineCallback(m88k break; case 0x02: // _PUTCHAR - putchar(cpu->r[S1++] & 0xffff); + Putc(cpu->r[S1++] & 0xff); break; default: - putlog(0, "未実装 DOS call #$%02x", num); + putlog(0, "DOS call #$%02x (NOT IMPLEMENTED)", num); cpu->r[D] = 0xffffffff; break; }