--- nono/vm/romemu_luna88k.cpp 2026/04/29 17:04:47 1.1.1.4 +++ nono/vm/romemu_luna88k.cpp 2026/04/29 17:04:55 1.1.1.7 @@ -8,32 +8,37 @@ // IODevice // | -// +----------+----------+ -// v v -// ROMDevice Luna88KPROMEmuDeivce (ROM エミュレーション) -// | -// v -// PROMDevice (実ROM) +// +----------+---------------------+ +// v v +// ROMDevice LunaPROMEmuDeivce (ROM エミュレーションの共通部分) +// | | +// | +------------+----------------+ +// v v v +// PROMDevice Luna1PROMEmuDevice Luna88kPROMEmuDevice +// (実ROM) (LUNA-I エミュレーション) (LUNA88K エミュレーション) #include "romemu_luna88k.h" -#include "aout.h" -#include "bt454.h" +#include "iodevstream.h" +#include "lunafb.h" #include "mainapp.h" #include "memorystream.h" +#include "mk48t02.h" +#include "pio.h" #include "ram.h" -#include "spc.h" +#include "sysctlr.h" // コンストラクタ Luna88kPROMEmuDevice::Luna88kPROMEmuDevice() { - logname = "prom"; - devname = "PROM"; - devaddr = baseaddr; + + // ROM の特定アドレスを読み出す人がいるかも知れないので、 + // サイズは実 ROM と同じにしておく。LUNA-I からの類推。 devlen = 256 * 1024; + romdata.reset(new uint8 [devlen]); - romdatalen = 1024; // サイズは適当 - romdata.reset(new uint8 [romdatalen]); + // プロンプトを初期化。 + prompt = default_prompt; } // デストラクタ @@ -44,16 +49,67 @@ Luna88kPROMEmuDevice::~Luna88kPROMEmuDev bool Luna88kPROMEmuDevice::Init() { + // 親クラス + if (inherited::Init() == false) { + return false; + } + MemoryStreamBE ms(romdata.get()); - // リセットベクタは本来2ワードだけだが他のベクタは使わないので - // 直接コードを書く。 - uint32 hi = ROMIO_IPL >> 16; - uint32 lo = ROMIO_IPL & 0xffff; - ms.Write32(0x5c400000 | hi); // or.u r2, r0, (ROMIO_IPL >> 16) - ms.Write32(0x58420000 | lo); // or r2, r2, (ROMIO_IPL & 0xffff) - ms.Write32(0xf4221400); // ld r1, r2, r0 - ms.Write32(0xf400c001); // jmp r1 + // リセット時のブートページには ROM (これ) が見えている。 + // ROMIO_INIT へのアクセスでブートページを RAM に切り替えて、同時に RAM の + // 0番地付近のベクタも作り直す。そのため、ここのベクタ1 以降 ($41000008〜) + // をベクタとして参照することはないので、ベクタ0 の命令列がそのまま使い潰 + // してよい。というか2ワードでは 0番地から ROM まで飛べないので使わないと + // 面倒くさい。一体どういう設計してんだ…。 + + // ; _ROM_START へジャンプ (ここは0番地) + ms.Write32(0x5cc04100); // or.u r6, r0, #0x4100 + ms.Write32(0x58c6000c); // or r6, r6, #0x000c + ms.Write32(0xf400c006); // jmp r6 + + // _ROM_START: (ここは ROM) + // ; 元の PSR を r10 に保存しつつ + // ; 割り込み許可 + ms.Write32(0x81404020); // ldcr r10, psr + ms.Write32(0xf04a8040); // clr r2, r10, 2<1> ; IND,SFRZ + ms.Write32(0x80028022); // stcr r2, psr + // ; r3 <- ROMIO_BASE + ms.Write32(0x5c600000 | // or.u r3, r0, #ROMIO_BASE.Hi + (ROMIO_BASE >> 16)); // + ms.Write32(0x58630000 | // or r3, r0, #ROMIO_BASE.Lo + (ROMIO_BASE & 0xffff)); // + // ; ROMIO_INIT を読み出す + ms.Write32(0x14430000); // ld r2, r3, #+INIT + // ; 起動先があれば GO + ms.Write32(0xe9a20005); // bcnd ne0, r2, _go + // _prompt: + // ; 疑似 STOP でキー入力を待つ + ms.Write32(0xc8000001); // bsr _stop + // ; この時点で r1 = _stop + // _stop: + ms.Write32(0xf400c001); // jmp r1 + // _back: + ms.Write32(0x14430000 | // ld r2, r3, #+ENTRY + (ROMIO_ENTRY - ROMIO_BASE));// + // ; 起動先がなければループ + ms.Write32(0xe842fffd); // bcnd eq0, r2, _prompt + // ; 起動先があれば後始末して + ms.Write32(0x14030000 | // _go: + (ROMIO_CLOSE - ROMIO_BASE));// ld r0, r3, #+CLOSE + // ; 割り込み禁止に戻す + ms.Write32(0x800a802a); // stcr r10, psr + // ; ジャンプ + ms.Write32(0xf400c002); // jmp r2 + + // ここから割り込みハンドラ。割り込みは SIO のみ許可にしてある。 + // キーボード割り込みが上がったら KEYIN をコールして _back に戻る。 + ms.SetPtr(&romdata[0x200]); + ms.Write32(0x14030000 | // ld r0, r3, #+KEYIN + (ROMIO_KEYIN - ROMIO_BASE));// + // ; 戻ったところの jmp を抜ける + ms.Write32(0x60210004); // addu r1, r1, #4 + ms.Write32(0xf400fc00); // rte return true; } @@ -61,157 +117,579 @@ Luna88kPROMEmuDevice::Init() void Luna88kPROMEmuDevice::ResetHard() { - ipl_done = false; + inherited::ResetHard(); + + b_entrypoint = 0; } -// アドレスデコーダ -inline uint64 -Luna88kPROMEmuDevice::Decoder(uint32 addr) const +// 起動時の処理を行う。 +// 次段実行ファイルの読み込みに成功すればそのエントリポイントを返す。 +// そうでなければ 0 を返すので、プロンプトに処理を移すこと。 +uint32 +Luna88kPROMEmuDevice::ROM_Init() { - // 折り返しなし - return addr - baseaddr; + IODeviceStream rs(gRAM.get()); + uint32 entry; + + // デバイスの初期化 (親クラス) + InitDevice(); + + // 割り込みマスクで SIO だけ許可 + gInterrupt->Write32(0x65000000, 0x40000000); + + rs.SetAddr(0); + // ベクタテーブルを rte で埋めておく + for (int i = 0; i < 512 * 2; i++) { + rs.Write32(0xf400fc00 /* rte */); + } + // +$08: 割り込みベクタ + rs.Write32(8, 0xc00003fe); // br $00001000 + + // 割り込みトランポリン (0x1000) + // ベクタテーブルは各2ワードしかないのに、0 番地付近にあるベクタテーブル + // から2ワードでは ROM まで飛べない。一体どういう設計してんだ…。 + rs.SetAddr(0x1000); + rs.Write32(0x5cc04100); // or.u r6, r0, #0x4100 + rs.Write32(0x58c60200); // or r6, r6, #0x0200 + rs.Write32(0xf400c006); // jmp r6 + + // ROM の機能テーブル + // 0x00001100 からあるようだ + // 0x0000110c GETC() + // 0x00001110 PUTC(c) + // 0x00001114 ビットマッププレーンの有効状態が入っている。 + // bit0: plane0 有効 + // bit1..7: plane1..7 有効 + rs.SetAddr(0x110c); + rs.Write32(0x00001300); + rs.Write32(0x00001400); + rs.Write32(0x00000001); + + // ROM GETC エミュレータ + rs.SetAddr(0x1300); + rs.Write32(0xfc000c00); // internal inst getc + rs.Write32(0xf400c001); // jmp r1 + + // ROM PUTC エミュレータ + rs.SetAddr(0x1400); + rs.Write32(0xfc001000); // internal inst putc + rs.Write32(0xf400c001); // jmp r1 + + // スクリーンを初期化 + InitScreen("LUNA88K"); + + entry = 0; + + // 表示環境が整ったところで NVRAM を照合 + if (VerifyNVRAM() == false) { + // PROM 1.20 は初期化するかどうか確認してくるけど、とりあえず。 + InitNVRAM(); + text.Print("** NVRAM Initialized.\n"); + text.Print("\n"); + // NVRAM をクリアしたら DIPSW によらずプロンプトに降りる + goto done; + } + + // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、 + // これを真似する。 + if ((gPIO0->GetDIPSW1() & 1)) { + if (gMainApp.host_file) { + // ホストのファイルを読み込んでエントリポイントアドレスを + // この Read アクセスの読み出し値として返す。 + // エラーがあればエラーメッセージは呼び出し先側で表示してある。 + entry = LoadHostFile(); + } else { + // 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) { + ClearPrompt(); + ConsoleUpdate(); + } + + return entry; } -uint64 -Luna88kPROMEmuDevice::Read8(uint32 addr) +// ROM 処理。エントリポイントを返す。 +uint32 +Luna88kPROMEmuDevice::ROM_Entry() { - // LUNA88K で Read8 呼ばれるんだっけ? - - uint64 offset = Decoder(addr) & (devlen - 1); + if (b_entrypoint != 0) { + return b_entrypoint; + } else { + return 0; + } +} - // 謎の IO 空間は(ロング)ワードアクセスのみ - if (offset < romdatalen) { - return romdata[offset]; +void +Luna88kPROMEmuDevice::GetChar(char asciicode) +{ + if (prompt_idx == 0) { + // 行入力モード (画面更新もしてある) + inherited::GetChar(asciicode); } else { - return 0xff; + // 0 以外ならノンブロッキングモード + + // 入力されたキーを表示 + text.SetAttr(TA::Normal); + if (' ' <= asciicode && asciicode < 0x7f) { + text.Putc(asciicode); + } + + switch (prompt_idx) { + case PROMPT_NVRAM_UPDATE: + CommandNvramUpdate2(asciicode); + break; + + case PROMPT_NVRAM_NEW: + CommandNvramNew2(asciicode); + break; + + case PROMPT_NVRAM_INIT: + CommandNvramInit2(asciicode); + break; + } + + // プロンプトを戻す + prompt = default_prompt; + prompt_idx = 0; + prompt_y = text.GetY(); + + // こっちは画面更新をする必要がある + ConsoleUpdate(); } } -uint64 -Luna88kPROMEmuDevice::Read16(uint32 addr) +// 入力コマンド処理 (入力行が揃ったところで呼ばれる)。 +// +// b 現在のパラメータで起動 +// b ... パラメータを指定して起動 +// nvram 全パラメータを表示 +// nvram [] name のみ表示? +// nvram 値を設定 +// nvram - 削除 +// nvram-- NVRAM 初期化 + +void +Luna88kPROMEmuDevice::Command() { - // LUNA88K で Read16 呼ばれるんだっけ? + std::vector buf(inputbuf.length() + 1); + std::vector arg; + + // 1ワードごとに分解 + strcpy(&buf[0], inputbuf.c_str()); + char *p = &buf[0]; + for (char *ap; (ap = strsep(&p, " ")) != NULL; ) { + if (*ap != '\0') { + arg.push_back(std::string(ap)); + } + } + if (loglevel >= 1) { + for (int i = 0; i < arg.size(); i++) { + putmsgn("arg[%d]=|%s|", i, arg[i].c_str()); + } + } + + // 空行 + if (arg.size() == 0) { + return; + } + + // 1ワード目がコマンド + if (arg[0] == "h") { + CommandH(arg); + return; + } + if (arg[0] == "b") { + CommandB(arg); + return; + } + if (arg[0] == "nvram") { + CommandNvram(arg); + return; + } + + text.Print("** Unknown command: %s\n", arg[0].c_str()); +} - uint64 offset = Decoder(addr) & (devlen - 1); +// "h" コマンド +// 引数なしなら、全体のヘルプメッセージ。 +// 引数ありなら、個別のヘルプメッセージ。 +void +Luna88kPROMEmuDevice::CommandH(const std::vector& arg) +{ + if (arg.size() < 2) { + // ヘルプメッセージ + mainhelp: + text.Print( +" *** Help Message ***\n" +" b : load and execute program\n" +" h : show this message\n" +" nvram : show/set nvram parameters\n" + ); + return; + } - // 謎の IO 空間は(ロング)ワードアクセスのみ - if (offset < romdatalen) { - return be16toh(*(uint16 *)(&romdata[offset])); + const std::string& key = arg[1]; + if (key == "nvram") { + text.Print( +" *** Help Message ***\n" +" nvram [] : show\n" +" nvram : set\n" +" nvram - : delete\n" +" nvram -- : initialize\n" + ); + return; } else { - return 0xffff; + goto mainhelp; } } -uint64 -Luna88kPROMEmuDevice::Read32(uint32 addr) +// "b" コマンド +// 引数なしなら NVRAM の情報に従ってプログラムをロードして実行。 +// 引数ありのほうは未実装。 +void +Luna88kPROMEmuDevice::CommandB(const std::vector& arg) { - uint64 offset = Decoder(addr); + errmsg.clear(); - // (ロング)ワードアクセスでだけ謎の I/O 空間が見える - switch (offset) { - case ROMIO_IPL - baseaddr: - if (!ipl_done) - return IPL(); - break; + // XXX とりあえず boot を起動するだけ + bootinfo_t bootinfo; + GetNVRAM(bootinfo); + b_entrypoint = LoadGuestFile(bootinfo); + if (b_entrypoint == 0) { + text.Print("** %s\n", errmsg.c_str()); } +} - offset &= (devlen - 1); - if (offset < romdatalen) { - return be32toh(*(uint32 *)(&romdata[offset])); - } else { - return 0xffffffff; +// "bh" コマンド (勝手に拡張) +// -A オプションで指定されたホストプログラムをロードして実行。 +void +Luna88kPROMEmuDevice::CommandBH() +{ + // 指定されてたら読み込む + if (gMainApp.host_file == NULL) { + text.Print("** Cannot loaded; host program is not specified.\n"); + return; } + b_entrypoint = LoadHostFile(); } -uint64 -Luna88kPROMEmuDevice::Write8(uint32 addr, uint32 data) +// "nvram" コマンド +// nvram .. 全表示 +// nvram .. 表示 +// nvram .. 追加/更新 +// nvram - .. 削除 +// nvram -- .. 初期化 +void +Luna88kPROMEmuDevice::CommandNvram(const std::vector& arg) { - return 0; + switch (arg.size()) { + case 1: + // 引数なし + CommandNvramShowAll(); + break; + case 2: + // 引数1つ + if (arg[1] == "--") { + CommandNvramInit(); + } else { + CommandNvramShow(arg); + } + break; + case 3: + // 引数2つ + if (arg[1] == "-") { + CommandNvramDelete(arg); + } else { + CommandNvramUpdate(arg); + } + break; + default: + text.Print("** Syntax error\n"); + } } -uint64 -Luna88kPROMEmuDevice::Write16(uint32 addr, uint32 data) +// NVRAM は 32バイトを1エントリとする。 +// [0] はヘッダに相当し、フォーマットは別記。 +// [1] 以降が key (16バイト)、val(16バイト) の並び。こんな感じ。 +// +// 00000020 62 6f 6f 74 5f 64 65 76 69 63 65 00 00 00 00 00 |boot_device.....| +// 00000030 73 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |sd..............| +// +// key, val とも '\0' で終端もしくは16文字で終端のようだ。 +// val に17文字を設定しようとすると怒られる。 +// key が "" ならこのエントリは空きで val は無視、 +// 空きエントリは無視して次へ (FAT のディレクトリエントリみたいな感じ)。 +// val が "" は有効。 +// +// オフセット 0x540 から始まるエントリが最後で、これ以上追加しようとすると +// "nvram set error: no area" (PROM 1.20) と言われる。 +// LUNA88K にはないが LUNA-I では 0x560 にぽつんと ENADDR があったので、 +// その辺りとの互換性だろうか。 + +// NVRAM 全項目表示 +void +Luna88kPROMEmuDevice::CommandNvramShowAll() { - return 0; + putmsg(1, "nvram ShowAll"); + for (uint32 offset = 0x20; offset < 0x560; offset += 0x20) { + std::string key = nvram->PeekString(offset); + if (key.empty()) { + continue; + } + std::string val = nvram->PeekString(offset + 16); + text.Print("%-15s : %s\n", key.c_str(), val.c_str()); + } } -uint64 -Luna88kPROMEmuDevice::Write32(uint32 addr, uint32 data) +// NVRAM 指定項目を表示 +void +Luna88kPROMEmuDevice::CommandNvramShow(const std::vector& arg) { - return 0; + assert(arg.size() >= 2); + const std::string& key = arg[1]; + + putmsg(1, "nvram Show |%s|", key.c_str()); + 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()); + } else { + text.Print("** Not found\n"); + } } -uint64 -Luna88kPROMEmuDevice::Peek8(uint32 addr) +// NVRAM 項目を追加/更新 +void +Luna88kPROMEmuDevice::CommandNvramUpdate(const std::vector& arg) { - uint64 offset = Decoder(addr) & (devlen - 1); + // キーがあれば更新、なければ追加。 + // いずれも事前にプロンプトで確認する。 + + assert(arg.size() >= 3); + nvram_key = arg[1]; + nvram_val = arg[2]; + 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"); + return; + } + if (nvram_val.size() > 16) { + text.Print("** Val too long\n"); + return; + } - if (offset < romdatalen) { - return romdata[offset]; + nvram_offset = FindNVRAM(nvram_key); + if (nvram_offset > 0) { + // キーがすでにあれば更新。 + // Update2() に申し送りするのは nvram_offset と nvram_val のみでいい。 + + std::string oldval = nvram->PeekString(nvram_offset + 16); + prompt = string_format("Update %s : \"%s\" -> \"%s\" (Y/[N]):", + nvram_key.c_str(), oldval.c_str(), nvram_val.c_str()); + prompt_idx = PROMPT_NVRAM_UPDATE; } else { - return 0xff; + // キーがなければ追加 + // New2() に申し送りするのは nvram_offset, nvram_key, nvram_val の3つ。 + + // 先に空き領域をチェックしている + nvram_offset = FindNVRAM(""); + if (nvram_offset == 0) { + text.Print("** No area available\n"); + return; + } + + prompt = string_format("Set new %s : \"%s\" (Y/[N]):", + nvram_key.c_str(), nvram_val.c_str()); + prompt_idx = PROMPT_NVRAM_NEW; } + + // 入力待ちの状態で戻る + // (prompt_idx != 0 なのでキー入力後に指定の関数へ飛んで続きを実行する) } -// 起動時の処理を行う。 -// 成功すればエントリポイント、失敗すれば 0 を返す。 -uint32 -Luna88kPROMEmuDevice::IPL() +// NVRAM 項目を更新 (キー入力後) +void +Luna88kPROMEmuDevice::CommandNvramUpdate2(char asciicode) { - uint32 entry = 0; + assert(prompt_idx == PROMPT_NVRAM_UPDATE); + assert(nvram_offset > 0); + assert(nvram_val.size() <= 16); - ipl_done = true; + text.CRLF(); - // ベクタテーブルを rte で埋めておく - for (int i = 0; i < 512; i++) { - gRAM->Write32(i * 8, 0xf400fc00 /* rte */); + if (asciicode != 'y' && asciicode != 'Y') { + text.Print("** Not updated\n"); + return; } - // ROM の機能テーブル - // 0x00001100 からあるようだ - // 0x0000110c GETC() - // 0x00001110 PUTC(c) - // 0x00001114 ビットマッププレーンの有効状態が入っている。 - // bit0: plane0 有効 - // bit1..7: plane1..7 有効 - gRAM->Write32(0x0000110c, 0x00001300); - gRAM->Write32(0x00001110, 0x00001400); - gRAM->Write32(0x00001114, 0x00000001); + if (nvram->WriteString(nvram_offset + 16, nvram_val) == false) { + text.Print("** Write error\n"); + return; + } + WriteNVRAMCsum(); - // ROM GETC エミュレータ - gRAM->Write32(0x00001300, 0xfc000c00); // internal inst getc - gRAM->Write32(0x00001304, 0xf400c001); // jmp r1 + text.Print("Updated\n"); +} - // ROM PUTC エミュレータ - gRAM->Write32(0x00001400, 0xfc001000); // internal inst putc - gRAM->Write32(0x00001404, 0xf400c001); // jmp r1 +// NVRAM 項目を追加 (キー入力後) +void +Luna88kPROMEmuDevice::CommandNvramNew2(char asciicode) +{ + assert(prompt_idx == PROMPT_NVRAM_NEW); + assert(nvram_offset > 0); + assert(!nvram_key.empty()); + assert(nvram_key.size() <= 16); + assert(nvram_val.size() <= 16); + + text.CRLF(); + + if (asciicode != 'y' && asciicode != 'Y') { + text.Print("** Not added\n"); + return; + } - // XXX このへん romemu_luna と同じところは共通化したほうがいい + if (nvram->WriteString(nvram_offset, nvram_key) == false + || nvram->WriteString(nvram_offset + 16, nvram_val) == false) { + text.Print("** Write error\n"); + return; + } + WriteNVRAMCsum(); - // 初期パレット - // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。 - uint8 val = 0xf0; - gBT454->Write8(0, 0); // select palette - for (int i = 0; i < 16; i++) { - gBT454->Write8(1, val); // R - gBT454->Write8(1, val); // G - gBT454->Write8(1, val); // B - val ^= 0xf0; - } - - // SCSI - // BDID の書き込みによってホストデバイスがバスにアタッチされる構造なので。 - gSPC->Write8(SPC::BDID, 7); - - if (gMainApp.host_file) { - // ホストのファイルを読み込んでエントリポイントアドレスを - // この Read アクセスの読み出し値として返す。 - entry = gRAM->LoadFile(gMainApp.host_file, AOUT_MID_M88K); - if (entry == 0) { - // XXX まだコンソールがなくて停止できないのでとりあえず終了 - exit(1); + text.Print("Added\n"); +} + +// NVRAM 項目削除 +// +// 削除する時は確認がないらしい… (PROM 1.20) +// 成功しても何も言わないらしい… (PROM 1.20) +// 追加削除に比べてなんか雑じゃない? +void +Luna88kPROMEmuDevice::CommandNvramDelete(const std::vector& arg) +{ + assert(arg.size() >= 3); + assert(arg[1] == "-"); + const std::string& key = arg[2]; + putmsg(1, "nvram Delete |%s|", key.c_str()); + + if (key.size() > 16) { + text.Print("** key too long\n"); + return; + } + + uint32 offset = FindNVRAM(key); + if (offset == 0) { + text.Print("** Not found\n"); + return; + } + + // キーを消せば削除になる (値のほうは消してないようだ) + nvram->WriteString(offset, ""); + WriteNVRAMCsum(); +} + +// NVRAM から key を探してそのエントリのオフセットを返す。 +// key == "" なら空きエントリを探す。 +// 見付からなければ 0 を返す (オフセット 0 はパラメータには使わないため) +uint32 +Luna88kPROMEmuDevice::FindNVRAM(const std::string& key) const +{ + for (uint32 offset = 0x20; offset < 0x560; offset += 0x20) { + std::string k = nvram->PeekString(offset); + if (k == key) { + return offset; } + // XXX 同じキーが複数あったらどうなるか } + return 0; +} - return entry; +// NVRAM 初期化 +void +Luna88kPROMEmuDevice::CommandNvramInit() +{ + putmsg(1, "nvram Init"); + + prompt = "Initialize (Y/[N]):"; + prompt_idx = PROMPT_NVRAM_INIT; + + // 入力待ちの状態で戻る +} + +// NVRAM 初期化 (キー入力後) +void +Luna88kPROMEmuDevice::CommandNvramInit2(char asciicode) +{ + assert(prompt_idx == PROMPT_NVRAM_INIT); + + text.CRLF(); + + if (asciicode != 'y' && asciicode != 'Y') { + text.Print("** Not initialized\n"); + return; + } + + InitNVRAM(); + text.Print("** Initialized\n"); +} + +// NVRAM を初期化する +bool +Luna88kPROMEmuDevice::InitNVRAM() +{ + nvram->ClearAll(); + + nvram->WriteString(0x0004, ""); + nvram->WriteString(0x0020, "boot_device"); + nvram->WriteString(0x0030, "sd"); + nvram->WriteString(0x0040, "boot_spec"); + nvram->WriteString(0x0050, "0"); + nvram->WriteString(0x0060, "boot_unit"); + nvram->WriteString(0x0070, "0"); + nvram->WriteString(0x0080, "boot_partition"); + nvram->WriteString(0x0090, "0"); + nvram->WriteString(0x00a0, "boot_filename"); + nvram->WriteString(0x00b0, "vmunix"); + nvram->WriteString(0x00c0, "main_mem_check"); + nvram->WriteString(0x00d0, "1"); + nvram->WriteString(0x00e0, "3port_mem_check"); + nvram->WriteString(0x00f0, "1"); + + // チェックサム再計算 + WriteNVRAMCsum(); + + return true; +} + +// NVRAM のブート設定を bootinfo に取得する。 +void +Luna88kPROMEmuDevice::GetNVRAM(bootinfo_t& bootinfo) +{ + // dkunit (装置番号) はたぶん boot_unit (0..) + // dkpart (パーティション) は boot_partition (0..) + // dkfile (ファイル名) は boot_filename + // sd 以外のデバイスは未対応 + bootinfo.dkunit = nvram->Peek(0x0070) - '0'; + bootinfo.dkpart = nvram->Peek(0x0090) - '0'; + bootinfo.dkfile = nvram->PeekString(0x00b0); + putmsg(1, "%s unit=%d", __func__, bootinfo.dkunit); + putmsg(1, "%s part=%c", __func__, bootinfo.dkpart + 'a'); + putmsg(1, "%s file=|%s|", __func__, bootinfo.dkfile.c_str()); }