--- nono/vm/romemu_luna.cpp 2026/04/29 17:05:11 1.1.1.13 +++ nono/vm/romemu_luna.cpp 2026/04/29 17:05:18 1.1.1.14 @@ -21,27 +21,28 @@ // | +--| LunaPROMEmuDevice | (LUNA PROM エミュレーションの共通部分) // | +-------------------+ // | | -// | +-- Luna1PROMEmuDevice (LUNA1 の PROM エミュレーション) -// | +-- Luna88kPROMEmuDevice (LUNA88K の PROM エミュレーション) +// | +-- Luna1PROMEmuDevice (LUNA-I の PROM エミュレーション) +// | +-- Luna88kPROMEmuDevice (LUNA-88K の PROM エミュレーション) // | // +-- PROM0Device (LUNA* のブートページ切り替え用プロキシ) // +-- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ) #include "romemu_luna.h" -#include "bt454.h" +#include "bt45x.h" #include "lunafb.h" #include "mainapp.h" +#include "mainram.h" #include "mk48t02.h" #include "mpu.h" +#include "pio.h" #include "prom.h" -#include "ram.h" #include "sio.h" #include "spc.h" #include "ufs.h" // コンストラクタ LunaPROMEmuDevice::LunaPROMEmuDevice() - : inherited("PROM") + : inherited(OBJ_PROM) { // LUNA では ROM への書き込みは何も起きない write_op = 0; @@ -50,14 +51,22 @@ LunaPROMEmuDevice::LunaPROMEmuDevice() // デストラクタ LunaPROMEmuDevice::~LunaPROMEmuDevice() { - gPROM = NULL; } +// 初期化 bool LunaPROMEmuDevice::Init() { - // 都度都度 dynamic_cast は面倒なので、ここで一度代入しとく - nvram = dynamic_cast(gRTC); + if (inherited::Init() == false) { + return false; + } + + bt45x = GetBT45xDevice(); + lunafb = GetLunafbDevice(); + mainram = GetMainRAMDevice(); + nvram = GetMK48T02Device(); + sio = GetSIODevice(); + spc = GetSPCDevice(); return true; } @@ -67,7 +76,7 @@ LunaPROMEmuDevice::Read32(uint32 addr) { // ROM からのロングワードアクセスでだけ謎の I/O 空間が見える。 // addr をマスクする前に評価すること。 - if ((gMPU->GetPaddr() & 0xff000000) == baseaddr) { + if ((mpu->GetPaddr() & 0xff000000) == baseaddr) { switch (addr) { case ROMIO_INIT: return ROM_Init(); @@ -95,42 +104,51 @@ LunaPROMEmuDevice::Read32(uint32 addr) void LunaPROMEmuDevice::InitDevice() { + auto pio1 = GetPIO1Device(); + // 初期パレット // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。 - uint8 val = 0xf0; - gBT454->Write(0, 0); // select palette + uint8 val = 0xff; + bt45x->Write(0, 0); // select palette for (int i = 0; i < 16; i++) { - gBT454->Write(1, val); // R - gBT454->Write(1, val); // G - gBT454->Write(1, val); // B - val ^= 0xf0; + bt45x->Write(1, val); // R + bt45x->Write(1, val); // G + bt45x->Write(1, val); // B + val ^= 0xff; } // SCSI // BDID の書き込みによってホストデバイスがバスにアタッチされる構造なので。 - gSPC->Write(SPC::BDID, 7); + spc->Write(SPC::BDID, 7); // キーボード(chB)を初期化 - gSIO->Write(3, 0x01); // CR1 - gSIO->Write(3, 0x10); // RX Int(all char) - 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 + sio->Write(3, 0x01); // CR1 + sio->Write(3, 0x10); // RX Int(all char) + sio->Write(3, 0x04); // CR4 + sio->Write(3, 0x44); // Stop 1bit + sio->Write(3, 0x03); // CR3 + sio->Write(3, 0xc1); // RX Enable, 8bit + sio->Write(3, 0x05); // CR5 + sio->Write(3, 0x68); // TX Enable, 8bit // LED を(明示的に)オフ、マウスサンプリングをオフ - gSIO->Write(2, 0x00); - gSIO->Write(2, 0x01); - gSIO->Write(2, 0x20); + sio->Write(2, 0x00); + sio->Write(2, 0x01); + sio->Write(2, 0x20); + + // 電源オフをキャンセル。 + // 実 PROM では、リセット後に PIO のモードセットを行っている。 + // モードセットを行うと PortC のビットが %0 になる = 電源オフなので、 + // 即座にこれをキャンセルしている。 + // ROMEmu ではモードセットを行っていないが、キャンセルだけ発行しておく。 + pio1->Write(3, 0x09); } // スクリーンを初期化 void LunaPROMEmuDevice::InitScreen() { - gLunafb->EmuInitScreen(); + lunafb->EmuInitScreen(); screen_w = 80; screen_h = 32; @@ -168,7 +186,7 @@ LunaPROMEmuDevice::Putc(uint ch) uint py = origin_py + cursor_y * 24; // カーソル位置の反転を元に戻す - gLunafb->EmuPutc(px, py, ' ', ROP::INV2); + lunafb->EmuPutc(px, py, ' ', ROP::INV2); if (ch == LF) { put_LF: @@ -177,9 +195,9 @@ LunaPROMEmuDevice::Putc(uint ch) cursor_y++; } else { // 上スクロールして.. - gLunafb->EmuScrollY(origin_py, origin_py + 24, (screen_h - 1) * 24); + lunafb->EmuScrollY(origin_py, origin_py + 24, (screen_h - 1) * 24); // 最終行を消す - gLunafb->EmuFill(0, py, 1280, 24, 0); + lunafb->EmuFill(0, py, 1280, 24, 0); } } else if (ch == LEFT) { if (cursor_x > 0) { @@ -197,10 +215,10 @@ LunaPROMEmuDevice::Putc(uint ch) } } else { if (cursor_x < screen_w - 1) { - gLunafb->EmuPutc(px, py, ch); + lunafb->EmuPutc(px, py, ch); cursor_x++; } else { - gLunafb->EmuPutc(px, py, ch); + lunafb->EmuPutc(px, py, ch); goto put_LF; } } @@ -208,7 +226,7 @@ LunaPROMEmuDevice::Putc(uint ch) // カーソル位置を再計算して描画 (文字を反転) px = origin_px + cursor_x * 12; py = origin_py + cursor_y * 24; - gLunafb->EmuPutc(px, py, ' ', ROP::INV2); + lunafb->EmuPutc(px, py, ' ', ROP::INV2); } // 文字列 s を出力 @@ -243,7 +261,7 @@ LunaPROMEmuDevice::ROM_Close() // SIO をリセットしておく。 // SIO のバッファにデータが残っていると、NetBSD のブートローダが // 起動してこないようだ。リセットして RXEN を落としておけば大丈夫ぽい。 - gSIO->ResetHard(false); + sio->ResetHard(false); } // ROM プロンプトのキー入力。 @@ -253,51 +271,74 @@ LunaPROMEmuDevice::ROM_Close() void LunaPROMEmuDevice::ROM_Keyin() { - uint32 lunakey = gSIO->Read(2); + int asciicode = Getc(); + + if (asciicode != -1) { + ProcessChar(asciicode); + } +} + +// キー入力。 +// 押されているキーの ASCII コードを返す。 +// キー入力が無いときは -1 を返す。 +int +LunaPROMEmuDevice::Getc() +{ + // コントロールレジスタポインタを確実に 0 にするため読み捨てる + sio->Read(3); + + uint8 sr0 = sio->Read(3); + if ((sr0 & MPSCC::SR0_RXAVAIL) == 0) { + return -1; + } + + uint32 lunakey = sio->Read(2); // マウス入力の 2, 3バイト目は無視 if (mousecnt > 0) { mousecnt--; - return; + return -1; } // SHIFT キーだけ状態を持つので先に処理 if (lunakey == 0x0c || lunakey == 0x0d) { // 左右SHIFT押下 is_shift = true; - return; + return -1; } if (lunakey == 0x8c || lunakey == 0x8d) { // 左右SHIFT開放 is_shift = false; - return; + return -1; } // マウスデータの1バイト目なら、後続2バイトをスキップ if ((lunakey & 0xf8) == 0x80) { mousecnt = 2; - return; + return -1; } // キー開放は無視してよい if ((lunakey & 0x80)) { - return; + return -1; } // キーコードから文字を取得 - char asciicode; + int asciicode; if (is_shift) { asciicode = lunakey2shifttable[lunakey]; } else { asciicode = lunakey2asciitable[lunakey]; } - if (asciicode != 0) { - GetChar(asciicode); + if (asciicode == 0) { + return -1; } + + return asciicode; } // キー入力ハンドラ (キー入力割り込みによって呼ばれる)。 // 引数 asciicode は概ね ASCII コード (ただし 0x1c..0x1f が上下左右)。 void -LunaPROMEmuDevice::GetChar(char asciicode) +LunaPROMEmuDevice::ProcessChar(char asciicode) { - // LUNA1 の場合、 + // LUNA-I の場合、 // 実機 PROM にはカーソル左右移動の機能はなく、カーソルは常に行末にいる。 // そのためかどうか Delete も BackSpace と同じく1文字前を消す動作をして // いる。カーソル位置に文字はないので、Delete をそうするのはまあ分からん @@ -421,18 +462,19 @@ LunaPROMEmuDevice::LoadHostFile() { assert(gMainApp.exec_file); - uint32 entry = gRAM->LoadFile(gMainApp.exec_file); - if (entry) { - Print("Host program loaded. Entry point = $%08x\n", entry); + LoadInfo info(gMainApp.exec_file); + if (mainram->LoadFromFile(&info)) { + Print("Host program loaded. Entry point = $%08x\n", info.entry); + return info.entry; } else { Print("** Couldn't load specified host program.\n"); + return 0; } - return entry; } // bootinfo に従ってゲストから起動先をロードする。 // 成功すればエントリポイントを返す。 -// 失敗ならをエラーメッセージを errmsg にセットして 0 を返す。 +// 失敗ならをエラーメッセージを errmsg にセットして (uint32)-1 を返す。 uint32 LunaPROMEmuDevice::LoadGuestFile(const bootinfo_t& bootinfo) { @@ -442,16 +484,16 @@ LunaPROMEmuDevice::LoadGuestFile(const b // ユニット (今は SCSI ID=6 決め打ち) int id = 6; - SCSITarget *target = gSPC->GetTarget(id); + SCSITarget *target = spc->GetTarget(id); if (target == NULL) { errmsg = "No bootable disks"; putmsg(0, "%s", errmsg.c_str()); - return 0; + return -1; } if (target->GetDevType() != SCSI::DevType::HD) { errmsg = "No bootable disks"; putmsg(0, "%s", errmsg.c_str()); - return 0; + return -1; } SCSIDisk *hd = dynamic_cast(target); @@ -462,7 +504,7 @@ LunaPROMEmuDevice::LoadGuestFile(const b if (hd->Peek(&dk, 0, sizeof(dk)) == false) { putmsg(0, "SCSIHD[%d] ReadSector failed", id); errmsg = string_format("dk%d Read disklabel failed.", dkunit); - return 0; + return -1; } // +$1fc の MAGIC をチェック @@ -471,7 +513,7 @@ LunaPROMEmuDevice::LoadGuestFile(const b putmsg(0, "SCSIHD[%d] Bad magic 0x%04x (!= 0x%x)", id, magic, scd_dk_label::DKL_MAGIC); errmsg = string_format("dk%d Bad disklabel magic.", dkunit); - return 0; + return -1; } // チェックサム照合は手抜きで省略 @@ -497,7 +539,7 @@ LunaPROMEmuDevice::LoadGuestFile(const b errmsg = string_format("dk%d,%c Open ffs failed: %s", dkunit, dkpart + 'a', fsys.errstr.c_str()); putmsg(0, "%s: %s", __func__, errmsg.c_str()); - return 0; + return -1; } // ファイルを探してオープンする @@ -506,23 +548,31 @@ LunaPROMEmuDevice::LoadGuestFile(const b errmsg = string_format("dk%d,%c,%s open failed: %s", dkunit, dkpart + 'a', dkfile.c_str(), fsys.errstr.c_str()); putmsg(0, "%s: %s", __func__, errmsg.c_str()); - return 0; + return -1; } // ファイル本体を読み込み fsys.ReadData(f); // ロード - uint32 entry; std::string name = string_format("SCSIHD %d,%c:%s", id, dkpart + 'a', dkfile.c_str()); - entry = gRAM->LoadFile(name.c_str(), f.data.data(), f.data.size()); - if (entry == 0) { + LoadInfo info(name.c_str(), f.data.data(), f.data.size()); + if (mainram->LoadFromData(&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()); + return -1; + } + + if (info.entry == -1) { errmsg = string_format("dk%d,%c,%s not executable", dkunit, dkpart + 'a', dkfile.c_str()); + putmsg(0, "%s: %s", __func__, errmsg.c_str()); + return -1; } - return entry; + return info.entry; } // キーコードから文字への変換