--- nono/vm/romemu_luna.cpp 2026/04/29 17:05:38 1.1.1.17 +++ nono/vm/romemu_luna.cpp 2026/04/29 17:06:01 1.1.1.20 @@ -34,6 +34,7 @@ #include "romemu_luna.h" #include "bt45x.h" #include "builtinrom.h" +#include "dipsw.h" #include "lance.h" #include "lunafb.h" #include "mainapp.h" @@ -42,7 +43,9 @@ #include "mpu.h" #include "pio.h" #include "prom.h" +#include "rtc.h" #include "scsidev.h" +#include "scsidomain.h" #include "sio.h" #include "spc.h" #include "ufs.h" @@ -92,9 +95,9 @@ LunaPROMEmuDevice::ReadROMIO(busaddr add putlog(2, "ROMIO_LOAD entrypoint=$%08x", entrypoint); return 0; - case ROMIO_KEYIN: - putlog(2, "ROMIO_KEYIN"); - ROM_Keyin(); + case ROMIO_SIOINTR: + putlog(2, "ROMIO_SIOINTR"); + ROM_SIOIntr(); return 0; case ROMIO_CLOSE: @@ -120,6 +123,9 @@ LunaPROMEmuDevice::ReadROMIO(busaddr add case ROMIO_CLKCNT: return clkcnt; + case ROMIO_QUITSTOP: + return quitstop; + default: break; } @@ -139,6 +145,11 @@ LunaPROMEmuDevice::WriteROMIO(busaddr ad case ROMIO_CLKCNT: clkcnt = data; return true; + + case ROMIO_QUITSTOP: + quitstop = data; + return true; + default: break; } @@ -162,20 +173,38 @@ LunaPROMEmuDevice::ROM_Init() lance->WritePort(0, 0x00); // RAP=CSR0 lance->WritePort(1, AM7990::CSR0_STOP); - // キーボード(chB)を初期化 - sio->WritePort(3, 0x01); // CR1 - sio->WritePort(3, 0x10); // RX Int(all char) - sio->WritePort(3, 0x04); // CR4 - sio->WritePort(3, 0x44); // Stop 1bit - sio->WritePort(3, 0x03); // CR3 - sio->WritePort(3, 0xc1); // RX Enable, 8bit - sio->WritePort(3, 0x05); // CR5 - sio->WritePort(3, 0x68); // TX Enable, 8bit - - // LED を(明示的に)オフ、マウスサンプリングをオフ - sio->WritePort(2, 0x00); - sio->WritePort(2, 0x01); - sio->WritePort(2, 0x20); + // DIP-SW の #1-2 が down(=false) ならシリアル。 + auto dipsw = GetDipswDevice(); + use_serial = (dipsw->Get(1) == false); + + if (use_serial) { + // シリアル(chA)を初期化 + sio->WritePort(1, 0x01); // CR1 + sio->WritePort(1, 0x12); // RX Int(all char) | TXIntEnable + sio->WritePort(1, 0x04); // CR4 + sio->WritePort(1, 0x44); // Stop 1bit + sio->WritePort(1, 0x03); // CR3 + sio->WritePort(1, 0xc1); // RX Enable, 8bit + sio->WritePort(1, 0x05); // CR5 + sio->WritePort(1, 0x68); // TX Enable, 8bit + + sio_txq.Clear(); + } else { + // キーボード(chB)を初期化 + sio->WritePort(3, 0x01); // CR1 + sio->WritePort(3, 0x10); // RX Int(all char) + sio->WritePort(3, 0x04); // CR4 + sio->WritePort(3, 0x44); // Stop 1bit + sio->WritePort(3, 0x03); // CR3 + sio->WritePort(3, 0xc1); // RX Enable, 8bit + sio->WritePort(3, 0x05); // CR5 + sio->WritePort(3, 0x68); // TX Enable, 8bit + + // LED を(明示的に)オフ、マウスサンプリングをオフ + sio->WritePort(2, 0x00); + sio->WritePort(2, 0x01); + sio->WritePort(2, 0x20); + } // 電源オフをキャンセル。 // 実 PROM では、リセット後に PIO のモードセットを行っている。 @@ -292,6 +321,13 @@ LunaPROMEmuDevice::InitScreen() void LunaPROMEmuDevice::PrintTitle() { + // シリアルモードなら、画面に何か出しておく。 + // 実機 PROM は、LUNA-I (4.22) はカーソルが出るだけ、 + // LUNA-88K (1.20) は " Use UART-A.\n" が表示される。 + if (use_serial) { + PrintDisplay("Use HostCom0.\n"); + } + Print("NONO %u.%u.%u Emulated ROM Monitor for %s\n\n", NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, machine_name); } @@ -300,6 +336,47 @@ LunaPROMEmuDevice::PrintTitle() void LunaPROMEmuDevice::Putc(uint ch) { + if (use_serial) { + PutcSerial(ch); + } else { + PutcDisplay(ch); + } +} + +// シリアルコンソールに1文字出力。 +// 実際にはキューに1文字追加して、キュー先頭の1文字を可能なら送信する。 +void +LunaPROMEmuDevice::PutcSerial(uint ch) +{ + sio_txq.Enqueue(ch); + ProcessSerial(); +} + +// シリアルコンソールにキュー先頭の1文字を可能なら送信する。 +void +LunaPROMEmuDevice::ProcessSerial() +{ + // コントロールレジスタポインタを確実に 0 にするため読み捨てる。 + sio->ReadPort(1); + + // 送信完了なら割り込みを下ろす。 + uint sr0 = sio->ReadPort(1); + if ((sr0 & MPSCC::SR0_INTPEND)) { + sio->WritePort(1, 5 << 3); // Reset TXIntr Pending + } + + if ((sr0 & MPSCC::SR0_TXEMPTY)) { + uint8 ch; + if (sio_txq.Dequeue(&ch)) { + sio->WritePort(0, ch); + } + } +} + +// 画面に1文字出力。 +void +LunaPROMEmuDevice::PutcDisplay(uint ch) +{ uint px = origin_px + cursor_x * 12; uint py = origin_py + cursor_y * 24; @@ -317,12 +394,17 @@ LunaPROMEmuDevice::Putc(uint ch) bold = false; break; - case 0x10: + case 0x10: // カラーコード変更 + lunafb->SetBMSEL(0); + break; case 0x11: + lunafb->SetBMSEL(1); + break; case 0x12: + lunafb->SetBMSEL(3); + break; case 0x13: - // カラーコード変更 - lunafb->SetBMSEL(ch - 0x10); + lunafb->SetBMSEL(5); break; case CR: @@ -391,7 +473,7 @@ LunaPROMEmuDevice::Putc(uint ch) } } -// 文字列 s を出力 +// 文字列 s を画面かシリアルに出力。 void LunaPROMEmuDevice::Print(const std::string& s) { @@ -400,7 +482,7 @@ LunaPROMEmuDevice::Print(const std::stri } } -// 文字列 fmt... を出力 +// 文字列 fmt... を画面かシリアルに出力。 void LunaPROMEmuDevice::Print(const char *fmt, ...) { @@ -416,6 +498,15 @@ LunaPROMEmuDevice::Print(const char *fmt } } +// 文字列 s を画面に出力。 +void +LunaPROMEmuDevice::PrintDisplay(const char *s) +{ + for (; *s; s++) { + PutcDisplay(*s); + } +} + // ROM 処理のクローズ void LunaPROMEmuDevice::ROM_Close() @@ -429,27 +520,67 @@ LunaPROMEmuDevice::ROM_Close() // その時のためにエントリポイント等も初期化しておく。 entrypoint = -1; execute = false; + clkcnt = 0; + quitstop = 0; } -// ROM プロンプトのキー入力。 -// ゲストコードの割り込みハンドラから呼ばれて、キー入力で行を構成し、 -// あるいは行が完成すればコマンドを実行する。 -// 実行結果により画面を更新したりメンバ変数を更新する。 +// SIO 割り込みハンドラ。 +// シリアル送信の進行と、シリアルもしくはキーボード(どちらもSIO)からの入力を +// 受け取って、コマンド処理を進行させる。 +// コマンド処理の進行は、キー入力で行を構成し、行が完成すればそのコマンドを +// 実行する、実行結果により出力(画面もしくはシリアル)を行ったり、メンバ変数を +// 更新したり、までを含む。要するにここがメインループみたいなところ。 void -LunaPROMEmuDevice::ROM_Keyin() +LunaPROMEmuDevice::ROM_SIOIntr() { - int asciicode = Getc(); + // シリアル送信を進行。 + if (use_serial) { + ProcessSerial(); + } + // 入力を処理。 + int asciicode = Getc(); if (cursor_on && asciicode != -1) { ProcessChar(asciicode); } } // キー入力。 +int +LunaPROMEmuDevice::Getc() +{ + int asciicode; + + if (use_serial) { + asciicode = GetcSerial(); + } else { + asciicode = GetcKeyboard(); + } + + return asciicode; +} + +// シリアルポートからのキー入力。 +int +LunaPROMEmuDevice::GetcSerial() +{ + // コントロールレジスタポインタを確実に 0 にするため読み捨てる + sio->ReadPort(1); + + uint8 sr0 = sio->ReadPort(1); + if ((sr0 & MPSCC::SR0_RXAVAIL) == 0) { + return -1; + } + + int asciicode = sio->ReadPort(0); + return asciicode; +} + +// キーボードからのキー入力。 // 押されているキーの ASCII コードを返す。 // キー入力が無いときは -1 を返す。 int -LunaPROMEmuDevice::Getc() +LunaPROMEmuDevice::GetcKeyboard() { // コントロールレジスタポインタを確実に 0 にするため読み捨てる sio->ReadPort(3); @@ -650,7 +781,7 @@ LunaPROMEmuDevice::LoadHostFile() assert(gMainApp.exec_file); LoadInfo info(gMainApp.exec_file); - if (mainram->LoadExec(&info)) { + if (BootLoader::LoadExec(mainram, &info)) { return info.entry; } else { errmsg = "Couldn't load specified host program."; @@ -670,7 +801,7 @@ LunaPROMEmuDevice::LoadGuestFile(const b // ユニット (今は SCSI ID=6 決め打ち) uint id = 6; - SCSITarget *target = spc->GetSCSI()->GetTarget(id); + SCSITarget *target = spc->GetDomain()->GetTarget(id); if (target == NULL) { errmsg = "No bootable disks"; putmsg(0, "%s", errmsg.c_str()); @@ -744,7 +875,7 @@ LunaPROMEmuDevice::LoadGuestFile(const b std::string name = string_format("SCSIHD %u,%c:%s", id, dkpart + 'a', dkfile.c_str()); LoadInfo info(name.c_str(), f.data.data(), f.data.size()); - if (mainram->LoadExec(&info) == false) { + if (BootLoader::LoadExec(mainram, &info) == false) { errmsg = string_format("dk%u,%c,%s load failed", dkunit, dkpart + 'a', dkfile.c_str()); putmsg(0, "%s: %s", __func__, errmsg.c_str()); @@ -772,30 +903,35 @@ LunaPROMEmuDevice::ROM_AP1() static uint8 ap1pal[] = { 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, + 0, 0, 0, 0xf8, 0xf8, 0x00, + 0, 0, 0, 0xf8, 0xf8, 0xf8, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0x00, 0x00, 0x00, + 0xf8, 0xf8, 0xf8 }; bt45x->WritePort(0, 0); for (int i = 0; i < countof(ap1pal); i++) { bt45x->WritePort(1, ap1pal[i]); } - Print(std::string((const char *)test0)); + PrintDisplay((const char *)test0); if (gMainApp.IsLUNA88K()) { - Print(std::string((const char *)test1)); + PrintDisplay((const char *)test1); } else { - Print(std::string((const char *)test2)); + PrintDisplay((const char *)test2); } - Print(std::string((const char *)test3)); + PrintDisplay((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); + snprintf(buf + n, sizeof(buf) - n, "%d.%d.%d '%02d.%02d.%02d\n", + NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, + GetRTCDevice()->GetYear() % 100, 4, 1); + PrintDisplay(buf); memcpy(buf, &Builtin::IPLROM30[0x111f5], 0x28); memcpy(buf + 0x1e, mpu->GetMPUName(), 7); @@ -804,14 +940,14 @@ LunaPROMEmuDevice::ROM_AP1() (double)mpu->GetClockSpeed() / 1000); strlcpy(buf + n, (const char *)&Builtin::IPLROM30[0x1121f], sizeof(buf) - n); - Print(std::string(buf)); + PrintDisplay(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)); + PrintDisplay(buf); strlcpy(buf, (const char *)&Builtin::IPLROM30[0x11254], sizeof(buf)); buf[0x0c] = 'e'; @@ -820,14 +956,14 @@ LunaPROMEmuDevice::ROM_AP1() memcpy(buf + 0x25, &Builtin::IPLROM30[0x1127d], 3); buf[0x22] = 0x32; } - Print(std::string(buf)); + PrintDisplay(buf); strlcpy(buf, (const char *)&Builtin::IPLROM30[0x11280], sizeof(buf)); n = 0x1e; - n += snprintf(buf + n, sizeof(buf) - n, "%d", mainram->GetSizeMB()); + n += snprintf(buf + n, sizeof(buf) - n, "%u", mainram->GetSizeMB()); strlcpy(buf + n, (const char *)&Builtin::IPLROM30[0x1129f], sizeof(buf) - n); - Print(std::string(buf)); + PrintDisplay(buf); } void