Annotation of nono/vm/romemu_luna1.cpp, revision 1.1.1.13

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1.1.6   root        7: //
1.1       root        8: // LUNA-I の ROM エミュレーション
1.1.1.4   root        9: //
1.1.1.6   root       10: 
1.1.1.4   root       11: // IODevice
1.1.1.10  root       12: //  |
                     13: //  +- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
                     14: //  |   +- PROMDevice    (LUNA* の PROM)
                     15: //  |   +- IPLROM1Device (X680x0 の IPLROM 後半)
                     16: //  |   +- IPLROM2Device (X680x0 の IPLROM 前半)
                     17: //  |   +- CGROMDevice   (X680x0 の CGROM)
                     18: //  |   |
                     19: //  |   +- ROMEmuDevice
                     20: //  |       |
                     21: //  |       +- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分)
                     22: //  |       |   |
                     23: //  |       |   | +--------------------+
                     24: //  |       |   +-| Luna1PROMEmuDevice | (LUNA-I の PROM エミュレーション)
                     25: //  |       |   | +--------------------+
                     26: //  |       |   |
                     27: //  |       |   +- Luna88kPROMEmuDevice  (LUNA-88K の PROM エミュレーション)
                     28: //  |       +- NewsROMEmuDevice    (NEWS の ROM エミュレーション)
                     29: //  |       +- ROM30EmuDevice      (X68030 の ROM30 エミュレーション)
                     30: //  |       +- Virt68kROMEmuDevice (virt-m68k の IPLROM 相当の何か)
                     31: //  |
                     32: //  +- PROM0Device   (LUNA* のブートページ切り替え用プロキシ)
                     33: //  +- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ)
1.1       root       34: 
1.1.1.6   root       35: // ROM マップ
                     36: //
                     37: //     先頭の "*" は仕様または実機と揃える必要があるアドレスを示す。
                     38: //     そうでないものはこっちが適当に割り振っているアドレスで、変更可。
                     39: //
                     40: //     *4100'0000.L    リセットベクタ(SP)
                     41: //     *4100'0004.L    リセットベクタ(PC)
                     42: //     *4100'000c.L    メモリサイズ格納先アドレス   (実 ROM は RAM をさしている)
                     43: //      4100'0010.L    メモリサイズ
                     44: //     *4100'00b8.L    プレーンマスク格納先アドレス (実 ROM は RAM をさしている)
                     45: //      4100'00bc.L    プレーンマスク
1.1.1.13! root       46: //     *4100'00d4.L    'x' コマンドの引数バッファアドレス
1.1.1.6   root       47: //
                     48: //      4100'0400              リセットハンドラ
1.1.1.13! root       49: //      4100'0500              Lv5 (Sysclk) 割り込みハンドラ
1.1.1.6   root       50: //      4100'0600              Lv6 (SIO) 割り込みハンドラ
                     51: //      4100'0700              Lv7 (NMI) 割り込みハンドラ
                     52: //      4100'0800              デフォルトハンドラ
1.1.1.13! root       53: //      4100'0900              サブルーチン
        !            54: //      4100'1000.B[64] 'x' コマンドの引数バッファ(ダミー)
1.1.1.6   root       55: //
                     56: //     *4101'ffd8〜   "ENADDR",0,0
                     57: //     *4101'ffe0〜   MACアドレス(文字列形式、英大文字、区切りなし)
                     58: //                      0123456789ab  c
                     59: //                     "0011223344AA",0
                     60: 
1.1       root       61: #include "romemu_luna1.h"
1.1.1.7   root       62: #include "bt45x.h"
1.1       root       63: #include "ethernet.h"
1.1.1.10  root       64: #include "iodevstream.h"
1.1       root       65: #include "mainapp.h"
1.1.1.7   root       66: #include "mainram.h"
1.1       root       67: #include "memorystream.h"
                     68: #include "mk48t02.h"
                     69: #include "mpu680x0.h"
1.1.1.9   root       70: #include "sysclk.h"
1.1       root       71: 
                     72: // コンストラクタ
                     73: Luna1PROMEmuDevice::Luna1PROMEmuDevice()
                     74: {
1.1.1.9   root       75:        machine_name = "LUNA-I";
1.1       root       76: }
                     77: 
                     78: // デストラクタ
                     79: Luna1PROMEmuDevice::~Luna1PROMEmuDevice()
                     80: {
                     81: }
                     82: 
1.1.1.7   root       83: // 初期化
1.1       root       84: bool
                     85: Luna1PROMEmuDevice::Init()
                     86: {
                     87:        if (inherited::Init() == false) {
                     88:                return false;
                     89:        }
                     90: 
1.1.1.12  root       91:        // LUNA-I の ROM の特定アドレスを読み出す人がいるので、
                     92:        // サイズは実 ROM と同じにしておく必要がある。
                     93:        if (AllocROM(128 * 1024, 0) == false) {
                     94:                return false;
                     95:        }
                     96: 
1.1.1.9   root       97:        SysClkDevice *sysclk = GetSysClkDevice();
                     98: 
1.1.1.10  root       99:        MemoryStreamBE roms(imagebuf.get());
                    100:        roms.Write4(0x00002000);        // +00: リセットベクタ SP
                    101:        roms.Write4(0x41000400);        // +04: リセットベクタ PC
                    102:        roms.Write4(0);                         // +08
                    103:        roms.Write4(0x41000010);        // +0c: メモリサイズ格納先
1.1.1.6   root      104:                                                                // +10: 値は ROM_Init() でセット
1.1.1.10  root      105:        roms.SetOffset(0xb8);
                    106:        roms.Write4(0x410000bc);        // +b8: プレーンマスク格納先
1.1.1.6   root      107:                                                                // +bc: 値は ROM_Init() でセット
1.1.1.13! root      108:        roms.SetOffset(0xd4);
        !           109:        roms.Write4(0x41001000);        // +d4: 'x' コマンドの引数(実際はRAM)
1.1       root      110: 
                    111:        // リセット時に実行する命令
1.1.1.10  root      112:        roms.SetOffset(0x400);
                    113:        roms.Write2(0x13c0);            //      move.b  d0,#0x41000000  ; RAMに切り替え
                    114:        roms.Write4(0x41000000);
                    115:        roms.Write2(0x2039);            //      move.l  (ROMIO_INIT),d0
                    116:        roms.Write4(ROMIO_INIT);
                    117:        roms.Write2(0x2039);            //      move.l  (ROMIO_LOAD),d0
                    118:        roms.Write4(ROMIO_LOAD);
                    119:        roms.Write2(0x72ff);            //      moveq.l #0xffffffff,d1
                    120:        roms.Write2(0x6004);            //      bra             _entry
1.1       root      121:                                                                //_prompt:
1.1.1.10  root      122:        uint32 _prompt = roms.GetOffset();
                    123:        roms.Write4(0x4e722500);        //      stop    #0x2500 ; キー入力を待つ
1.1.1.9   root      124:                                                                //_entry:
1.1.1.10  root      125:        roms.Write2(0x2039);            //      move.l  (ROMIO_ENTRY),d0
                    126:        roms.Write4(ROMIO_ENTRY);       //                                      ; エントリポイント取得
                    127:        roms.Write2(0xb081);            //      cmp.l   d1,d0
                    128:        roms.Write2(0x67f2);            //      beq             _prompt ; 起動先なければループ
1.1       root      129:                                                                //_go:
1.1.1.10  root      130:        roms.Write2(0x2040);            //      move.l  d0,a0   ; ジャンプ先を a0 にセット
                    131:        roms.Write2(0x2039);            //      move.l  (ROMIO_CLOSE),d0
                    132:        roms.Write4(ROMIO_CLOSE);       //                                      ; 後始末
                    133:        roms.Write2(0x4ed0);            //      jmp             (a0)    ; ジャンプ
1.1       root      134: 
1.1.1.9   root      135:        // Lv5 (Sysclk) 割り込みハンドラ。
1.1.1.10  root      136:        roms.SetOffset(0x500);
                    137:        roms.Write2(0x13c0);            //      move.b  d0,#0x63000000  ; ACK
                    138:        roms.Write4(0x63000000);
                    139:        roms.Write2(0x52b9);            //      addq.l  #1,(ROMIO_CLKCNT)
                    140:        roms.Write4(ROMIO_CLKCNT);
                    141:        roms.Write2(0x4e73);            //      rte
1.1.1.9   root      142: 
1.1       root      143:        // Lv6 (SIO) 割り込みハンドラ
                    144:        // キーボード割り込みが上がったら KEYIN をコールする
1.1.1.10  root      145:        roms.SetOffset(0x600);
                    146:        roms.Write2(0x4ab9);            //      tst.l   (ROMIO_KEYIN)
                    147:        roms.Write4(ROMIO_KEYIN);       //                                      ; キー入力処理
                    148:        roms.Write2(0x4e73);            //      rte
1.1       root      149: 
1.1.1.6   root      150:        // NMI のハンドラ
1.1.1.10  root      151:        roms.SetOffset(0x700);
                    152:        roms.Write4(0x46fc2700);        //      move.w  #0x2700,sr
                    153:        roms.Write2(0x91c8);            //      suba.l  a0,a0
                    154:        roms.Write4(0x4e7b8801);        //      movec   a0,vbr
                    155:        roms.Write2(0x2e50);            //      movea.l (a0),sp
                    156:        roms.Write2(0x4ef9);            //      jmp             _prompt
                    157:        roms.Write4(0x41000000 + _prompt);
1.1.1.6   root      158: 
                    159:        // デフォルトのハンドラ
1.1.1.10  root      160:        roms.SetOffset(0x800);
                    161:        roms.Write2(0x4e73);            //  rte
1.1.1.6   root      162: 
1.1.1.9   root      163:        // サブルーチン
1.1.1.10  root      164:        roms.SetOffset(0x900);          //_ap1:
                    165:        roms.Write2(0x2039);            //      move.l  (ROMIO_AP1),d0
                    166:        roms.Write4(ROMIO_AP1);         //
                    167:        uint freq = sysclk->GetFreq();
                    168:        roms.Write2(0x7200 + freq * 3);
                    169:                                                                //      moveq.l #(CLK_FREQ*3),d1
1.1.1.9   root      170:                                                                //@@:
1.1.1.10  root      171:        roms.Write4(0x4e722400);        //      stop    #0x2400 ; クロック入力を待つ
                    172:        roms.Write2(0x2039);            //      move.l  (ROMIO_CLKCNT),d0
                    173:        roms.Write4(ROMIO_CLKCNT);
                    174:        roms.Write2(0xb001);            //      cmp.b   d1,d0
                    175:        roms.Write2(0x66f2);            //      bne             @b
                    176:        roms.Write2(0x2039);            //      move.l  (ROMIO_AP2),d0
                    177:        roms.Write4(ROMIO_AP2);         //
                    178:        roms.Write2(0x4e75);            //      rts
1.1.1.9   root      179: 
1.1       root      180:        // MAC アドレス
1.1.1.11  root      181:        MacAddr macaddr;
1.1.1.8   root      182:        if (EthernetDevice::GetConfigMacAddr(0, &macaddr, false) == false) {
1.1.1.7   root      183:                // エラーメッセージは表示済み
                    184:                return false;
                    185:        }
                    186:        putmsg(1, "macaddr=%s", macaddr.ToString(':').c_str());
1.1.1.4   root      187:        strcpy((char *)&imagebuf[0x1ffd8], "ENADDR");
1.1.1.6   root      188:        memcpy(&imagebuf[0x1ffe0], macaddr.ToString().c_str(), 12);
1.1       root      189: 
                    190:        return true;
                    191: }
                    192: 
1.1.1.9   root      193: // ROM 起動時の初期化 (機種依存部分) を行う。
                    194: void
                    195: Luna1PROMEmuDevice::ROM_InitMD()
1.1       root      196: {
1.1.1.10  root      197:        IODeviceStream rams(mainram);
                    198:        MemoryStreamBE roms(imagebuf.get());
1.1.1.7   root      199: 
1.1.1.6   root      200:        // +0010: メモリサイズ
1.1.1.10  root      201:        roms.SetOffset(0x10);
1.1.1.12  root      202:        roms.Write4((uint32)mainram->GetSize());
1.1       root      203: 
1.1.1.7   root      204:        // プレーン数(1,4,8)をプレーンマスク(0x01, 0x0f, 0xff)に
                    205:        int nplane = bt45x->GetPlaneCount();
1.1.1.13! root      206:        int planemask = (1U << nplane) - 1;
1.1.1.6   root      207:        // プレーンマスク。実際は RAM に書き込まれるがとりあえず
1.1.1.10  root      208:        roms.SetOffset(0xbc);
                    209:        roms.Write4(planemask);
1.1       root      210: 
1.1.1.6   root      211:        // RAM にベクタを書き込む
1.1.1.10  root      212:        roms.SetOffset(0);
1.1.1.12  root      213:        rams.SetAddr(0);
1.1.1.10  root      214:        rams.Write4(roms.Read4());              // ROM のリセットベクタをコピー
                    215:        rams.Write4(roms.Read4());
                    216:        for (uint i = 2; i < 256; i++) {        // デフォルトベクタで埋める
                    217:                rams.Write4(0x41000800);
                    218:        }
                    219:        rams.Write4(0x74, 0x41000500);          // +74: Lv5 割り込み
                    220:        rams.Write4(0x78, 0x41000600);          // +78: Lv6 割り込み
                    221:        rams.Write4(0x7c, 0x41000700);          // +7c: Lv7 割り込み = RESET
1.1.1.6   root      222: 
1.1       root      223:        prompt_idx = 0;
                    224:        prompt = default_prompt;
                    225: 
1.1.1.10  root      226:        uint32 ap = (nvram->PeekPort(0x7fd) << 8) | nvram->PeekPort(0x7fe);
1.1.1.9   root      227:        if (__predict_false(0||(ap & 0x3f1f) == 0x0104)) {
                    228:                auto mpu680x0 = GetMPU680x0Device(mpu);
                    229:                m68kreg& reg = mpu680x0->reg;
                    230:                reg.A[7] -= 4;
1.1.1.10  root      231:                rams.Write4(reg.A[7], reg.pc);
1.1.1.9   root      232:                reg.pc = 0x41000900;
1.1       root      233:        }
                    234: }
                    235: 
                    236: // ROM 処理のクローズ。
                    237: // 次段プログラムにジャンプするための処理も含む。
                    238: void
                    239: Luna1PROMEmuDevice::ROM_Close()
                    240: {
                    241:        inherited::ROM_Close();
                    242: 
                    243:        // NetBSD のブートローダがカーネルを読み込む時にはいくつかレジスタ
                    244:        // 渡しのパラメータがあるので、ここで用意する。本当はターゲットが
                    245:        // NetBSD カーネルの時に限定すべきのような気もするけど、とりあえず。
                    246:        // ROM がブートローダを読み込む時にはそのような取り決め事は一切ない
                    247:        // ので、ブートローダを読む時にも同じ値が入ってしまうが気にしない
                    248:        // ことにする。
                    249:        // 必要なパラメータは
                    250:        // %d6 に bootdev、NetBSD/luna68k の場合は
                    251:        // bootdev = $MACUPP00
                    252:        //            ||||++-- パーティション番号
                    253:        //            |||+---- SCSI ID (XXX ただしここでは 6 決め打ち)
                    254:        //            ||+----- unit (spc0 なら 0 のやつのはず)
                    255:        //            |+------ アダプタ (spc = 0、lance = 1)
                    256:        //            +------- magic ($a)
                    257:        //
                    258:        // %d7 に howto (0 でよい)
                    259:        // (と %a0 にジャンプ先を入れるがこれは Init() が書き出した ROM
                    260:        // アセンブラコード側で行っている)
1.1.1.9   root      261:        m68kreg& reg = GetMPU680x0Device(mpu)->reg;
1.1.1.7   root      262:        reg.D[6] = 0xa0060000;
                    263:        reg.D[7] = 0;
1.1.1.9   root      264: }
1.1.1.6   root      265: 
1.1.1.9   root      266: // ファイルをロードする。
                    267: // -X が指定されていればそのホストファイル。
                    268: // そうでなければゲストファイル。この場合引数 fname があれば
                    269: // NVRAM で指定されたデバイスから読み込む際のファイル名とする。
                    270: // 空なら NVRAM で指定されたファイル名。
                    271: // ロードできればエントリポイントを返す。
                    272: // ロードできなければ errmsg にメッセージをセットし -1 を返す。
                    273: uint32
                    274: Luna1PROMEmuDevice::LoadFile(const std::string& fname)
                    275: {
                    276:        uint32 entry = -1;
                    277: 
                    278:        if (gMainApp.exec_file) {
                    279:                // -X が指定されてたらホストプログラムを読み込む。
                    280:                entry = LoadHostFile();
                    281:        } else {
                    282:                // NVRAM で指定されるゲストプログラムを読み込む。
                    283:                std::string ctlr = nvram->PeekString(0x0030);
                    284:                if (ctlr == "dk") {                     // harddisk
                    285:                        bootinfo_t bootinfo;
                    286:                        GetNVRAM(bootinfo);
                    287:                        // 引数で指定されたらファイル名だけ上書き
                    288:                        if (fname.empty() == false) {
                    289:                                bootinfo.dkfile = fname;
                    290:                        }
                    291:                        entry = LoadGuestFile(bootinfo);
                    292: 
                    293:                } else if (ctlr == "et" ||      // netboot
                    294:                           ctlr == "sd" ||      // cassette tape
                    295:                           ctlr == "fl"   )     // floppy
                    296:                {
                    297:                        errmsg = ctlr + " boot not supported.";
                    298:                } else {
                    299:                        // 起きないはず
                    300:                        errmsg = ctlr + ": Invalid boot controller name.";
                    301:                }
                    302:        }
                    303: 
                    304:        return entry;
1.1       root      305: }
                    306: 
                    307: // 入力コマンド処理 (入力行が揃ったところで呼ばれる)。
                    308: void
                    309: Luna1PROMEmuDevice::Command()
                    310: {
                    311:        std::vector<char> buf(inputbuf.length() + 1);
                    312:        std::vector<std::string> arg;
                    313: 
                    314:        // 1ワードごとに分解
1.1.1.10  root      315:        strlcpy(buf.data(), inputbuf.c_str(), buf.size());
1.1       root      316:        char *p = &buf[0];
1.1.1.2   root      317:        for (char *ap; (ap = strsep(&p, " ")) != NULL; ) {
                    318:                if (*ap != '\0') {
                    319:                        arg.push_back(std::string(ap));
1.1       root      320:                }
                    321:        }
                    322:        if (loglevel >= 1) {
                    323:                for (int i = 0; i < arg.size(); i++) {
1.1.1.10  root      324:                        putmsgn("arg[%u]=|%s|", i, arg[i].c_str());
1.1       root      325:                }
                    326:        }
                    327: 
                    328:        // "k" コマンド中ならここで先に処理する
                    329:        if (prompt_idx != 0) {
                    330:                CommandK(arg);
                    331:                return;
                    332:        }
                    333: 
                    334:        // 空行
                    335:        if (arg.size() == 0) {
                    336:                return;
                    337:        }
                    338: 
                    339:        // 1ワード目がコマンド
                    340:        if (arg[0] == "h") {
                    341:                // ヘルプメッセージ
1.1.1.6   root      342:                Print("Commands\n");
                    343:                Print(
1.1       root      344: "  g [<filename>]     : load program\n"
                    345: "  h                  : show this message\n"
                    346: "  k                  : show/set boot constants\n"
                    347: "  x                  : execute loaded program\n"
                    348:                );
                    349:                return;
                    350:        }
                    351:        if (arg[0] == "g") {
                    352:                CommandG(arg);
                    353:                return;
                    354:        }
                    355:        if (arg[0] == "k") {
                    356:                CommandK(arg);
                    357:                return;
                    358:        }
                    359:        if (arg[0] == "x") {
                    360:                CommandX();
                    361:                return;
                    362:        }
                    363: 
1.1.1.6   root      364:        Print("** Unknown command: %s\n", arg[0].c_str());
1.1       root      365: }
                    366: 
                    367: // "g" コマンド
1.1.1.9   root      368: // g なら NVRAM の情報 (もしくは -X オプション) に従ってプログラムをロード。
1.1       root      369: // g <fname> なら NVRAM の fname だけ指定の名前を使ってロード。NVRAM には
                    370: // 書き込まない。
                    371: void
                    372: Luna1PROMEmuDevice::CommandG(const std::vector<std::string>& arg)
                    373: {
1.1.1.9   root      374:        std::string fname {};
1.1       root      375: 
1.1.1.9   root      376:        switch (arg.size()) {
                    377:         case 1:
                    378:                break;
                    379:         case 2:
                    380:                fname = arg[1];
                    381:                break;
                    382:         default:
                    383:                Print("** Invalid argument.\n");
                    384:                return;
1.1       root      385:        }
                    386: 
1.1.1.9   root      387:        entrypoint = LoadFile(fname);
                    388:        if (entrypoint == -1) {
                    389:                Print("** %s\n", errmsg.c_str());
                    390:        } else {
                    391:                Print("%s.  Entry point = $%08x\n",
                    392:                        (gMainApp.exec_file ? "Host program loaded" : "Loaded"),
                    393:                        entrypoint);
1.1       root      394:        }
                    395: }
                    396: 
                    397: // k コマンドのパラメータ表
                    398: struct kinfo {
                    399:        uint32 offset;                          // NVRAM 上のオフセット
                    400:        const char * const name;        // 表示名
                    401:        int next;                                       // 次インデックス
                    402: };
                    403: static const struct kinfo kinfo[] = {
                    404:        { 0 },  // 0 は通常プロンプトを指すのでここでは使わない
                    405:        { 0x0030,       "controller",  0 },     // [1] BOOT (next は動的判定する)
                    406:        { 0x0090,       "drive unit",  3 },     // [2] DKUNIT
                    407:        { 0x00b0,       "partition ",  4 },     // [3] DKPART
                    408:        { 0x00d0,       "filename  ",  0 },     // [4] FLNAME
                    409:        { 0x0050,       "hostname  ",  6 },     // [5] HOST
                    410:        { 0x0070,       "servername",  7 },     // [6] SERVER
                    411:        { 0x0190,       "filename  ",  8 },     // [7] ETBOOT
                    412:        { 0x01b0,       "",                        0 }, // [8] ETFILE (ETBOOT と1行で処理する)
                    413: };
                    414: 
                    415: // "k" コマンド
                    416: void
                    417: Luna1PROMEmuDevice::CommandK(const std::vector<std::string>& arg)
                    418: {
                    419:        uint32 offset;
                    420:        const char *name;
                    421:        int next;
                    422: 
                    423:        // 入力を処理
                    424:        if (prompt_idx == 0) {
                    425:                // ここは1行目表示前なので前行の入力はない。
                    426:                next = 1;
                    427:        } else {
                    428:                std::string val;
                    429:                bool rv;
                    430: 
                    431:                // 入力があれば更新
                    432:                if (arg.size() != 0) {
                    433:                        rv = CommandKInput(arg[0]);
                    434:                } else {
                    435:                        // [7] の時に入力があれば CommandKInput() の中で更新されるが、
                    436:                        // 入力がなければそこを通らないので、こっちでやらないといけない。
                    437:                        // うーん。
                    438:                        if (prompt_idx == 7) {
                    439:                                prompt_idx = kinfo[prompt_idx].next;
                    440:                        }
                    441:                        rv = true;
                    442:                }
                    443: 
                    444:                // これ以降は更新後の prompt_idx を使う
                    445: 
                    446:                // 入力エラーがあった時はこの行を再入力するため
                    447:                next = prompt_idx;
                    448: 
                    449:                if (rv == true) {
                    450:                        // 入力があっても空でも次インデックスへ。
                    451:                         if (prompt_idx == 1) {
                    452:                                // BOOT なら現在値によって次のインデックスが変わる
                    453:                                // "dk" なら [2]、"et" なら [5]。他は未対応
                    454:                                offset = kinfo[prompt_idx].offset;
                    455:                                val = nvram->PeekString(offset);
                    456:                                if (val == "dk") {
                    457:                                        next = 2;
                    458:                                } else if (val == "et") {
                    459:                                        next = 5;
                    460:                                } else {
                    461:                                        // 起きることはないはず
1.1.1.6   root      462:                                        Print("** Inconsistent boot parameter: %s\n",
1.1       root      463:                                                val.c_str());
                    464:                                }
                    465:                        } else {
                    466:                                // それ以外はテーブルにかかれている通り
                    467:                                next = kinfo[prompt_idx].next;
                    468:                        }
                    469:                }
                    470:        }
                    471: 
                    472:        // この行のプロンプト文字列を作成
                    473:        prompt_idx = next;
                    474:        if (prompt_idx == 0) {
                    475:                // 最終行なら元に戻す
                    476:                prompt = default_prompt;
                    477:        } else {
                    478:                // 次のプロンプトに変更
                    479:                name = kinfo[prompt_idx].name;
                    480:                offset = kinfo[prompt_idx].offset;
                    481:                std::string val = nvram->PeekString(offset);
                    482: 
                    483:                // [7] ETBOOT だけ1行で ETBOOT:ETFILE 形式
                    484:                if (prompt_idx == 7) {
                    485:                        next = kinfo[prompt_idx].next;  // ETFILE
                    486:                        offset = kinfo[next].offset;
                    487:                        val += ":";
                    488:                        val += nvram->PeekString(offset);
                    489:                }
                    490: 
                    491:                prompt = string_format("%s: %s  ?", name, val.c_str());
                    492:        }
                    493: }
                    494: 
                    495: // k コマンドの入力値を処理する部分。
                    496: // 成功すれば true を返す。
                    497: // 失敗すれば false を返す。
                    498: // 実機 ROM は入力値にエラーがあると黙って再入力を促す。
                    499: // エラーメッセージくらい表示してもいいかもだがとりあえず真似しておく。
                    500: bool
                    501: Luna1PROMEmuDevice::CommandKInput(const std::string& val)
                    502: {
                    503:        int offset;
                    504:        bool rv = true;
                    505: 
                    506:        offset = kinfo[prompt_idx].offset;
                    507: 
                    508:        switch (prompt_idx) {
                    509:         case 1:        // BOOT
                    510:                // 正常な入力値は "dk", "et", "sd", "fl" のみ。
                    511:                if (val != "dk" && val != "et" && val != "sd" && val != "fl") {
                    512:                        return false;
                    513:                }
                    514:                rv = nvram->WriteString(offset, val);
                    515:                if (rv == false) {
                    516:                        return false;
                    517:                }
                    518:                break;
                    519: 
                    520:         case 7:        // ETBOOT
                    521:         {
                    522:                // こいつだけ ETBOOT:ETFILE 形式で2つのパラメータを同時に処理する
                    523: 
                    524:                // ':' で前後に分ける
                    525:                int sep = val.find(':');
                    526:                if (sep == std::string::npos) {
                    527:                        return false;
                    528:                }
                    529:                std::string etboot = val.substr(0, sep);
                    530:                std::string etfile = val.substr(sep + 1, val.size() - sep + 1);
                    531:                if (etboot.empty() || etfile.empty()) {
                    532:                        return false;
                    533:                }
                    534: 
                    535:                // ETBOOT
                    536:                rv = nvram->WriteString(offset, etboot);
                    537:                if (rv == false) {
                    538:                        return false;
                    539:                }
                    540: 
                    541:                // 次へ
                    542:                prompt_idx = kinfo[prompt_idx].next;
                    543: 
                    544:                // ETFILE
                    545:                offset = kinfo[prompt_idx].offset;
                    546:                rv = nvram->WriteString(offset, etfile);
                    547:                if (rv == false) {
                    548:                        return false;
                    549:                }
                    550:                break;
                    551:         }
                    552: 
                    553:         default:
                    554:                rv = nvram->WriteString(offset, val);
                    555:                if (rv == false) {
                    556:                        return false;
                    557:                }
                    558:                break;
                    559:        }
                    560: 
                    561:        WriteNVRAMCsum();
                    562:        return rv;
                    563: }
                    564: 
                    565: // "x" コマンド
                    566: // 読み込まれていたらフラグを立てるだけ。
                    567: void
                    568: Luna1PROMEmuDevice::CommandX()
                    569: {
1.1.1.9   root      570:        if (entrypoint == -1) {
1.1.1.6   root      571:                Print("** Program is not loaded.\n");
1.1.1.9   root      572:                return;
1.1       root      573:        }
1.1.1.9   root      574:        execute = true;
1.1       root      575: }
                    576: 
                    577: // NVRAM を初期化する
                    578: bool
                    579: Luna1PROMEmuDevice::InitNVRAM()
                    580: {
1.1.1.3   root      581:        nvram->ClearAll();
                    582: 
1.1       root      583:        // 初期値どうしたもんか
                    584:        nvram->WriteString(0x0004, "<nv>");
                    585:        nvram->WriteString(0x0020, "BOOT");
                    586:        nvram->WriteString(0x0030, "dk");
                    587:        nvram->WriteString(0x0040, "HOST");
                    588:        nvram->WriteString(0x0050, "nono");     // 偽札的なアレ
                    589:        nvram->WriteString(0x0060, "SERVER");
                    590:        nvram->WriteString(0x0070, "servername");
                    591:        nvram->WriteString(0x0080, "DKUNIT");
                    592:        nvram->WriteString(0x0090, "0");
                    593:        nvram->WriteString(0x00a0, "DKPART");
                    594:        nvram->WriteString(0x00b0, "c");
                    595:        nvram->WriteString(0x00c0, "DKFILE");
                    596:        nvram->WriteString(0x00d0, "vmunix");
                    597:        nvram->WriteString(0x00e0, "FLUNIT");
                    598:        nvram->WriteString(0x00f0, "2");
                    599:        nvram->WriteString(0x0100, "FLFILE");
                    600:        nvram->WriteString(0x0110, "vmunix");
                    601:        nvram->WriteString(0x0120, "STUNIT");
                    602:        nvram->WriteString(0x0130, "0");
                    603:        nvram->WriteString(0x0140, "STFLNO");
                    604:        nvram->WriteString(0x0150, "1");
                    605:        nvram->WriteString(0x0160, "STFILE");
                    606:        nvram->WriteString(0x0170, "vmunix");
                    607:        nvram->WriteString(0x0180, "ETBOOT");
                    608:        nvram->WriteString(0x0190, "server");
                    609:        nvram->WriteString(0x01a0, "ETFILE");
                    610:        nvram->WriteString(0x01b0, "/vmunix");
                    611:        nvram->WriteString(0x0560, "ENADDR");
                    612:        nvram->WriteString(0x0570, ""); // どうするか
                    613: 
                    614:        // チェックサム再計算
                    615:        WriteNVRAMCsum();
                    616: 
                    617:        return true;
                    618: }
                    619: 
                    620: // NVRAM のブート設定を bootinfo に取得する。
                    621: void
                    622: Luna1PROMEmuDevice::GetNVRAM(bootinfo_t& bootinfo)
                    623: {
                    624:        // 起動先情報を NVRAM (mk48t02) に問い合わせる
                    625:        // DKUNIT が装置番号(今はまだ SCSI ID=6 固定)。
                    626:        // DKPART が 'a'..'h' でパーティション。
                    627:        // DKFILE が読み込む次段プログラム (NetBSD では通常 /boot のこと)。
1.1.1.10  root      628:        bootinfo.dkunit = nvram->PeekPort(0x0090) - '0';
                    629:        bootinfo.dkpart = nvram->PeekPort(0x00b0) - 'a';
1.1       root      630:        bootinfo.dkfile = nvram->PeekString(0x00d0);
1.1.1.10  root      631:        putmsg(1, "%s DKUNIT=%u", __func__, bootinfo.dkunit);
1.1       root      632:        putmsg(1, "%s DKPART=%c", __func__, bootinfo.dkpart + 'a');
                    633:        putmsg(1, "%s DKFILE=|%s|", __func__, bootinfo.dkfile.c_str());
                    634: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.