Annotation of nono/vm/romemu_luna88k.cpp, revision 1.1.1.8

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.2   root        7: // LUNA88K の ROM エミュレーション
1.1.1.8 ! root        8: //
        !             9: // IODevice
        !            10: //    |
        !            11: //    +-- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
        !            12: //    |     |
        !            13: //    |     +-- PROMDevice    (LUNA* の PROM)
        !            14: //    |     +-- IPLROM1Device (X680x0 の IPLROM 後半)
        !            15: //    |     +-- IPLROM2Device (X680x0 の IPLROM 前半)
        !            16: //    |     +-- CGROMDevice   (X680x0 の CGROM)
        !            17: //    |     +-- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分)
        !            18: //    |           |
        !            19: //    |           +-- Luna1PROMEmuDevice      (LUNA1 の PROM エミュレーション)
        !            20: //    |           |
        !            21: //    |           |  +----------------------+
        !            22: //    |           +--| Luna88kPROMEmuDevice | (LUNA88K の PROM エミュレーション)
        !            23: //    |              +----------------------+
        !            24: //    |
        !            25: //    +-- PROM0Device   (LUNA* のブートページ切り替え用プロキシ)
        !            26: //    +-- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ)
1.1.1.2   root       27: 
                     28: #include "romemu_luna88k.h"
1.1.1.5   root       29: #include "iodevstream.h"
1.1.1.7   root       30: #include "lunafb.h"
1.1.1.8 ! root       31: #include "m88100.h"
1.1       root       32: #include "mainapp.h"
                     33: #include "memorystream.h"
1.1.1.7   root       34: #include "mk48t02.h"
1.1.1.8 ! root       35: #include "mpu88xx0.h"
1.1.1.5   root       36: #include "pio.h"
1.1       root       37: #include "ram.h"
1.1.1.5   root       38: #include "sysctlr.h"
1.1       root       39: 
1.1.1.8 ! root       40: static bool luna88k_fline_callback(m88kcpu *cpu, void *arg);
        !            41: 
        !            42: // m88k の命令コードを少し読みやすく書きたい。
        !            43: // 必要なものは適宜足すこと。
        !            44: enum class OPr {
        !            45:        r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
        !            46:        r8,  r9,  r10, r11, r12, r13, r14, r15,
        !            47:        r16, r17, r18, r19, r20, r21, r22, r23,
        !            48:        r24, r25, r26, r27, r28, r29, r30, r31,
        !            49: };
        !            50: #define r0     OPr::r0
        !            51: #define r1     OPr::r1
        !            52: #define r2     OPr::r2
        !            53: #define r3     OPr::r3
        !            54: #define r4     OPr::r4
        !            55: #define r5     OPr::r5
        !            56: #define r6     OPr::r6
        !            57: #define r7     OPr::r7
        !            58: #define r8     OPr::r8
        !            59: #define r9     OPr::r9
        !            60: #define r10    OPr::r10
        !            61: enum OPm5 {
        !            62:        eq0 = 0x02,
        !            63:        ne0 = 0x0d,
        !            64: };
        !            65: enum OPcr {
        !            66:        psr = 0x01,
        !            67: };
        !            68: 
        !            69: static constexpr uint32 OP3(uint32 base, uint32 rd, uint32 rs1, uint32 rs2) {
        !            70:        return (base) | (rd << 21) | (rs1 << 16) | rs2;
        !            71: }
        !            72: static constexpr uint32 OP4(uint32 base, uint32 rd, uint32 rs1,
        !            73:        uint32 w, uint32 o) {
        !            74:        return (base) | (rd << 21) | (rs1 << 16) | (w << 5) | o;
        !            75: }
        !            76: 
        !            77: static constexpr uint32 OP_addu(OPr rd, OPr rs1, uint32 imm) {
        !            78:        return OP3(0x60000000, (uint32)rd, (uint32)rs1, imm);
        !            79: }
        !            80: static constexpr uint32 OP_bcnd(OPm5 m5, OPr rs1, uint32 d16) {
        !            81:        return OP3(0xe8000000, (uint32)m5, (uint32)rs1, d16);
        !            82: }
        !            83: static constexpr uint32 OP_bsr(uint32 d26) {
        !            84:        return (0xc8000000 | d26);
        !            85: }
        !            86: static constexpr uint32 OP_clr(OPr rd, OPr rs1, uint32 w, uint32 o) {
        !            87:        return OP4(0xf0008000, (uint32)rd, (uint32)rs1, w, o);
        !            88: }
        !            89: static constexpr uint32 OP_jmp(OPr rs2) {
        !            90:        return OP3(0xf400c000, 0, 0, (uint32)rs2);
        !            91: }
        !            92: static constexpr uint32 OP_ld(OPr rd, OPr rs1, uint32 imm) {
        !            93:        return OP3(0x14000000, (uint32)rd, (uint32)rs1, imm);
        !            94: }
        !            95: static constexpr uint32 OP_ldcr(OPr rd, uint32 crs) {
        !            96:        return OP4(0x80004000, (uint32)rd, 0, crs, 0);
        !            97: }
        !            98: static constexpr uint32 __unused OP_or(OPr rd, OPr rs1, OPr rs2) {
        !            99:        return OP3(0xf4005800, (uint32)rd, (uint32)rs1, (uint32)rs2);
        !           100: }
        !           101: static constexpr uint32 OP_or(OPr rd, OPr rs1, uint32 imm) {
        !           102:        return OP3(0x58000000, (uint32)rd, (uint32)rs1, imm);
        !           103: }
        !           104: static constexpr uint32 OP_or_u(OPr rd, OPr rs1, uint32 imm) {
        !           105:        return OP3(0x5c000000, (uint32)rd, (uint32)rs1, imm);
        !           106: }
        !           107: static constexpr uint32 OP_rte() {
        !           108:        return 0xf400fc00;
        !           109: }
        !           110: static constexpr uint32 OP_st(OPr rd, OPr rs1, OPr rs2) {
        !           111:        return OP3(0xf4002400, (uint32)rd, (uint32)rs1, (uint32)rs2);
        !           112: }
        !           113: static constexpr uint32 OP_stcr(OPr rs1, uint32 crd) {
        !           114:        return OP4(0x80008000, 0, (uint32)rs1, crd, (uint32)rs1);
        !           115: }
        !           116: static constexpr uint32 OP_doscall(OPr rd, OPr rs1, uint32 imm) {
        !           117:        return OP3(0xfc000400, (uint32)rd, (uint32)rs1, imm);
        !           118: }
        !           119: #define DOS_GETCHAR    (1)
        !           120: #define DOS_PUTCHAR    (2)
        !           121: 
        !           122: 
1.1       root      123: // コンストラクタ
                    124: Luna88kPROMEmuDevice::Luna88kPROMEmuDevice()
                    125: {
                    126:        devaddr = baseaddr;
1.1.1.5   root      127: 
                    128:        // ROM の特定アドレスを読み出す人がいるかも知れないので、
                    129:        // サイズは実 ROM と同じにしておく。LUNA-I からの類推。
1.1.1.2   root      130:        devlen = 256 * 1024;
1.1.1.8 ! root      131:        imagebuf.reset(new uint8 [devlen]);
        !           132:        memset(&imagebuf[0], 0, devlen);
        !           133:        mem = &imagebuf[0];
        !           134: 
        !           135:        mask = devlen - 1;
1.1.1.2   root      136: 
1.1.1.5   root      137:        // プロンプトを初期化。
1.1.1.7   root      138:        prompt = default_prompt;
1.1       root      139: }
                    140: 
                    141: // デストラクタ
                    142: Luna88kPROMEmuDevice::~Luna88kPROMEmuDevice()
                    143: {
                    144: }
                    145: 
                    146: bool
                    147: Luna88kPROMEmuDevice::Init()
                    148: {
1.1.1.5   root      149:        // 親クラス
                    150:        if (inherited::Init() == false) {
                    151:                return false;
                    152:        }
                    153: 
1.1.1.8 ! root      154:        // DOS call エミュレーションのコールバックを登録
        !           155:        gMPU88xx0->SetFLineCallback(luna88k_fline_callback, this);
        !           156: 
        !           157:        MemoryStreamBE ms(imagebuf.get());
1.1       root      158: 
1.1.1.6   root      159:        // リセット時のブートページには ROM (これ) が見えている。
                    160:        // ROMIO_INIT へのアクセスでブートページを RAM に切り替えて、同時に RAM の
                    161:        // 0番地付近のベクタも作り直す。そのため、ここのベクタ1 以降 ($41000008〜)
                    162:        // をベクタとして参照することはないので、ベクタ0 の命令列がそのまま使い潰
                    163:        // してよい。というか2ワードでは 0番地から ROM まで飛べないので使わないと
                    164:        // 面倒くさい。一体どういう設計してんだ…。
                    165: 
1.1.1.8 ! root      166:        // ここからややアセンブラっぽいインデント
        !           167: 
        !           168:        // _START:
        !           169:                // ここは 0番地。ここから _ROM_START へジャンプ
        !           170:                ms.Write32(OP_or_u      (r6, r0, 0x4100));
        !           171:                ms.Write32(OP_or        (r6, r6, 0x000c));
        !           172:                ms.Write32(OP_jmp       (r6));
        !           173: 
        !           174:        // _ROM_START: (ここは ROM)
        !           175:                // RAM に切り替え
        !           176:                ms.Write32(OP_st        (r0, r6, r0));
        !           177: 
        !           178:                // 元の PSR を r10 に保存しつつ割り込み許可
        !           179:                ms.Write32(OP_ldcr      (r10, psr));
        !           180:                ms.Write32(OP_clr       (r2, r10, 2, 1));       // clear IND,SFRZ
        !           181:                ms.Write32(OP_stcr      (r2, psr));
        !           182: 
        !           183:                ms.Write32(OP_or_u      (r3, r0, ROMIO_BASE >> 16));
        !           184:                ms.Write32(OP_or        (r3, r3, ROMIO_BASE & 0xfff));
        !           185:                // ROMIO_INIT を読み出す
        !           186:                ms.Write32(OP_ld        (r2, r3, (ROMIO_INIT - ROMIO_BASE)));
        !           187:                // 起動先があれば GO
        !           188:                ms.Write32(OP_bcnd      (ne0, r2, 5));  // 5 = _go
        !           189: 
        !           190:        // _prompt:
        !           191:                // 疑似 STOP でキー入力を待つ
        !           192:                ms.Write32(OP_bsr       (1));                   // 1 = _stop
        !           193:                // この時点で r1 = _stop
        !           194: 
        !           195:        // _stop:
        !           196:                ms.Write32(OP_jmp       (r1));
        !           197: 
        !           198:        // _back:
        !           199:                ms.Write32(OP_ld        (r2, r3, (ROMIO_ENTRY - ROMIO_BASE)));
        !           200:                // 起動先がなければループ
        !           201:                ms.Write32(OP_bcnd      (ne0, r2, 0xfffd));     // 0xfffd = _prompt
        !           202: 
        !           203:        // _go:
        !           204:                // 起動先があれば後始末して
        !           205:                ms.Write32(OP_ld        (r0, r3, (ROMIO_CLOSE - ROMIO_BASE)));
        !           206:                // 割り込み禁止に戻す
        !           207:                ms.Write32(OP_stcr      (r10, psr));
        !           208:                // ジャンプ
        !           209:                ms.Write32(OP_jmp       (r2));
1.1.1.5   root      210: 
                    211:        // ここから割り込みハンドラ。割り込みは SIO のみ許可にしてある。
                    212:        // キーボード割り込みが上がったら KEYIN をコールして _back に戻る。
1.1.1.8 ! root      213:        ms.SetPtr(&imagebuf[0x200]);
        !           214:                ms.Write32(OP_ld        (r0, r3, (ROMIO_KEYIN - ROMIO_BASE)));
        !           215:                // 戻ったところの jmp を抜ける
        !           216:                ms.Write32(OP_addu      (r1, r1, 0x04));
        !           217:                ms.Write32(OP_rte       ());
        !           218: 
        !           219:        // ROM GETC エミュレータ
        !           220:        ms.SetPtr(&imagebuf[0x300]);
        !           221:                ms.Write32(OP_doscall(r2, r0, DOS_GETCHAR));
        !           222:                ms.Write32(OP_jmp       (r1));
        !           223: 
        !           224:        // ROM PUTC エミュレータ
        !           225:        // 表示する文字は r3 に置かれている。
        !           226:        ms.SetPtr(&imagebuf[0x400]);
        !           227:                ms.Write32(OP_doscall(r0, r3, DOS_PUTCHAR));
        !           228:                ms.Write32(OP_jmp       (r1));
        !           229: 
        !           230: 
        !           231:        // 変なインデントここまで
1.1       root      232: 
                    233:        return true;
                    234: }
                    235: 
1.1.1.6   root      236: void
                    237: Luna88kPROMEmuDevice::ResetHard()
                    238: {
                    239:        b_entrypoint = 0;
                    240: }
                    241: 
1.1.1.5   root      242: // 起動時の処理を行う。
                    243: // 次段実行ファイルの読み込みに成功すればそのエントリポイントを返す。
                    244: // そうでなければ 0 を返すので、プロンプトに処理を移すこと。
                    245: uint32
                    246: Luna88kPROMEmuDevice::ROM_Init()
1.1       root      247: {
1.1.1.5   root      248:        IODeviceStream rs(gRAM.get());
                    249:        uint32 entry;
1.1       root      250: 
1.1.1.5   root      251:        // デバイスの初期化 (親クラス)
                    252:        InitDevice();
1.1.1.6   root      253: 
1.1.1.5   root      254:        // 割り込みマスクで SIO だけ許可
                    255:        gInterrupt->Write32(0x65000000, 0x40000000);
1.1       root      256: 
1.1.1.5   root      257:        rs.SetAddr(0);
                    258:        // ベクタテーブルを rte で埋めておく
                    259:        for (int i = 0; i < 512 * 2; i++) {
1.1.1.8 ! root      260:                rs.Write32(OP_rte());
1.1.1.5   root      261:        }
                    262:        // +$08: 割り込みベクタ
                    263:        rs.Write32(8, 0xc00003fe);              // br   $00001000
                    264: 
                    265:        // 割り込みトランポリン (0x1000)
                    266:        // ベクタテーブルは各2ワードしかないのに、0 番地付近にあるベクタテーブル
                    267:        // から2ワードでは ROM まで飛べない。一体どういう設計してんだ…。
                    268:        rs.SetAddr(0x1000);
1.1.1.8 ! root      269:                rs.Write32(OP_or_u      (r6, r0, 0x4100));
        !           270:                rs.Write32(OP_or        (r6, r6, 0x0200));
        !           271:                rs.Write32(OP_jmp       (r6));
1.1.1.2   root      272: 
1.1.1.5   root      273:        // ROM の機能テーブル
1.1.1.8 ! root      274:        // 0x00001100 ?
        !           275:        // 0x00001104 ?
        !           276:        // 0x00001108 ?
        !           277:        // 0x0000110c GETC() のアドレス
        !           278:        // 0x00001110 PUTC(c) のアドレス
1.1.1.5   root      279:        // 0x00001114 ビットマッププレーンの有効状態が入っている。
                    280:        //  bit0: plane0 有効
                    281:        //  bit1..7: plane1..7 有効
                    282:        rs.SetAddr(0x110c);
1.1.1.8 ! root      283:                rs.Write32(0x41000300);
        !           284:                rs.Write32(0x41000400);
        !           285:                rs.Write32(0x00000001);
1.1.1.5   root      286: 
                    287:        // スクリーンを初期化
                    288:        InitScreen("LUNA88K");
                    289: 
                    290:        entry = 0;
                    291: 
                    292:        // 表示環境が整ったところで NVRAM を照合
                    293:        if (VerifyNVRAM() == false) {
1.1.1.7   root      294:                // PROM 1.20 は初期化するかどうか確認してくるけど、とりあえず。
1.1.1.5   root      295:                InitNVRAM();
                    296:                text.Print("** NVRAM Initialized.\n");
                    297:                text.Print("\n");
                    298:                // NVRAM をクリアしたら DIPSW によらずプロンプトに降りる
                    299:                goto done;
                    300:        }
                    301: 
                    302:        // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、
                    303:        // これを真似する。
                    304:        if ((gPIO0->GetDIPSW1() & 1)) {
1.1.1.8 ! root      305:                if (gMainApp.exec_file) {
1.1.1.5   root      306:                        // ホストのファイルを読み込んでエントリポイントアドレスを
                    307:                        // この Read アクセスの読み出し値として返す。
                    308:                        // エラーがあればエラーメッセージは呼び出し先側で表示してある。
                    309:                        entry = LoadHostFile();
                    310:                } else {
                    311:                        // NVRAM の設定に従ってブート先を探す。
                    312:                        errmsg.clear();
                    313: 
                    314:                        bootinfo_t bootinfo;
                    315:                        GetNVRAM(bootinfo);
                    316:                        entry = LoadGuestFile(bootinfo);
                    317:                        if (entry == 0) {
                    318:                                text.Print("** %s\n", errmsg.c_str());
                    319:                        }
                    320:                }
                    321:        }
                    322: 
                    323:        // ここまでタイトルなどを Print してはいるが、実際の画面更新は
                    324:        // ConsoleUpdate() を呼ぶまで行われないことを利用(悪用?)して、
                    325:        // ここでエラーなくブートプログラムに制御を渡せる場合には何も表示せずに
                    326:        // ゲストに処理を移す。意図して或いは意図せずプロンプトに降りる場合だけ
                    327:        // ConsoleUpdate を呼ぶことでタイトルを含めて画面を表示する。
                    328:  done:
                    329:        if (entry == 0) {
1.1.1.7   root      330:                ClearPrompt();
1.1.1.5   root      331:                ConsoleUpdate();
                    332:        }
                    333: 
                    334:        return entry;
                    335: }
                    336: 
                    337: // ROM 処理。エントリポイントを返す。
                    338: uint32
                    339: Luna88kPROMEmuDevice::ROM_Entry()
                    340: {
                    341:        if (b_entrypoint != 0) {
                    342:                return b_entrypoint;
1.1.1.2   root      343:        } else {
1.1.1.5   root      344:                return 0;
1.1.1.2   root      345:        }
                    346: }
                    347: 
1.1.1.7   root      348: void
                    349: Luna88kPROMEmuDevice::GetChar(char asciicode)
                    350: {
                    351:        if (prompt_idx == 0) {
                    352:                // 行入力モード (画面更新もしてある)
                    353:                inherited::GetChar(asciicode);
                    354:        } else {
                    355:                // 0 以外ならノンブロッキングモード
                    356: 
                    357:                // 入力されたキーを表示
                    358:                text.SetAttr(TA::Normal);
                    359:                if (' ' <= asciicode && asciicode < 0x7f) {
                    360:                        text.Putc(asciicode);
                    361:                }
                    362: 
                    363:                switch (prompt_idx) {
                    364:                 case PROMPT_NVRAM_UPDATE:
                    365:                        CommandNvramUpdate2(asciicode);
                    366:                        break;
                    367: 
                    368:                 case PROMPT_NVRAM_NEW:
                    369:                        CommandNvramNew2(asciicode);
                    370:                        break;
                    371: 
                    372:                 case PROMPT_NVRAM_INIT:
                    373:                        CommandNvramInit2(asciicode);
                    374:                        break;
                    375:                }
                    376: 
                    377:                // プロンプトを戻す
                    378:                prompt = default_prompt;
                    379:                prompt_idx = 0;
                    380:                prompt_y = text.GetY();
                    381: 
                    382:                // こっちは画面更新をする必要がある
                    383:                ConsoleUpdate();
                    384:        }
                    385: }
                    386: 
1.1.1.5   root      387: // 入力コマンド処理 (入力行が揃ったところで呼ばれる)。
                    388: //
                    389: // b                                   現在のパラメータで起動
                    390: // b ...                               パラメータを指定して起動
                    391: // nvram                               全パラメータを表示
                    392: // nvram [<name>]              name のみ表示?
                    393: // nvram <name> <val>  値を設定
                    394: // nvram - <name>              削除
                    395: // nvram--                             NVRAM 初期化
                    396: 
                    397: void
                    398: Luna88kPROMEmuDevice::Command()
1.1.1.2   root      399: {
1.1.1.5   root      400:        std::vector<char> buf(inputbuf.length() + 1);
                    401:        std::vector<std::string> arg;
1.1.1.2   root      402: 
1.1.1.5   root      403:        // 1ワードごとに分解
                    404:        strcpy(&buf[0], inputbuf.c_str());
                    405:        char *p = &buf[0];
1.1.1.6   root      406:        for (char *ap; (ap = strsep(&p, " ")) != NULL; ) {
                    407:                if (*ap != '\0') {
                    408:                        arg.push_back(std::string(ap));
1.1.1.5   root      409:                }
                    410:        }
                    411:        if (loglevel >= 1) {
                    412:                for (int i = 0; i < arg.size(); i++) {
                    413:                        putmsgn("arg[%d]=|%s|", i, arg[i].c_str());
                    414:                }
                    415:        }
1.1.1.2   root      416: 
1.1.1.5   root      417:        // 空行
                    418:        if (arg.size() == 0) {
                    419:                return;
                    420:        }
                    421: 
                    422:        // 1ワード目がコマンド
                    423:        if (arg[0] == "h") {
1.1.1.7   root      424:                CommandH(arg);
1.1.1.5   root      425:                return;
                    426:        }
                    427:        if (arg[0] == "b") {
                    428:                CommandB(arg);
                    429:                return;
                    430:        }
                    431:        if (arg[0] == "nvram") {
                    432:                CommandNvram(arg);
                    433:                return;
1.1.1.2   root      434:        }
1.1.1.5   root      435: 
                    436:        text.Print("** Unknown command: %s\n", arg[0].c_str());
1.1.1.2   root      437: }
                    438: 
1.1.1.7   root      439: // "h" コマンド
                    440: // 引数なしなら、全体のヘルプメッセージ。
                    441: // 引数ありなら、個別のヘルプメッセージ。
                    442: void
                    443: Luna88kPROMEmuDevice::CommandH(const std::vector<std::string>& arg)
                    444: {
                    445:        if (arg.size() < 2) {
                    446:                // ヘルプメッセージ
                    447:  mainhelp:
                    448:                text.Print(
                    449: "         *** Help Message ***\n"
                    450: "  b      : load and execute program\n"
                    451: "  h      : show this message\n"
                    452: "  nvram  : show/set nvram parameters\n"
                    453:                );
                    454:                return;
                    455:        }
                    456: 
                    457:        const std::string& key = arg[1];
                    458:        if (key == "nvram") {
                    459:                text.Print(
                    460: "         *** Help Message ***\n"
                    461: " nvram [<symbol>]       : show\n"
                    462: " nvram <symbol> <value> : set\n"
                    463: " nvram - <symbol>       : delete\n"
                    464: " nvram --               : initialize\n"
                    465:                );
                    466:                return;
                    467:        } else {
                    468:                goto mainhelp;
                    469:        }
                    470: }
                    471: 
1.1.1.5   root      472: // "b" コマンド
                    473: // 引数なしなら NVRAM の情報に従ってプログラムをロードして実行。
                    474: // 引数ありのほうは未実装。
                    475: void
                    476: Luna88kPROMEmuDevice::CommandB(const std::vector<std::string>& arg)
1.1       root      477: {
1.1.1.5   root      478:        errmsg.clear();
1.1       root      479: 
1.1.1.5   root      480:        // XXX とりあえず boot を起動するだけ
                    481:        bootinfo_t bootinfo;
                    482:        GetNVRAM(bootinfo);
                    483:        b_entrypoint = LoadGuestFile(bootinfo);
                    484:        if (b_entrypoint == 0) {
                    485:                text.Print("** %s\n", errmsg.c_str());
1.1       root      486:        }
1.1.1.5   root      487: }
1.1       root      488: 
1.1.1.5   root      489: // "bh" コマンド (勝手に拡張)
1.1.1.8 ! root      490: // -X オプションで指定されたホストプログラムをロードして実行。
1.1.1.5   root      491: void
                    492: Luna88kPROMEmuDevice::CommandBH()
                    493: {
                    494:        // 指定されてたら読み込む
1.1.1.8 ! root      495:        if (gMainApp.exec_file == NULL) {
1.1.1.5   root      496:                text.Print("** Cannot loaded; host program is not specified.\n");
                    497:                return;
1.1.1.2   root      498:        }
1.1.1.5   root      499:        b_entrypoint = LoadHostFile();
1.1.1.2   root      500: }
                    501: 
1.1.1.7   root      502: // "nvram" コマンド
                    503: // nvram             .. 全表示
                    504: // nvram <key>       .. 表示
                    505: // nvram <key> <val> .. 追加/更新
                    506: // nvram - <key>     .. 削除
                    507: // nvram --          .. 初期化
1.1.1.5   root      508: void
                    509: Luna88kPROMEmuDevice::CommandNvram(const std::vector<std::string>& arg)
1.1.1.2   root      510: {
1.1.1.7   root      511:        switch (arg.size()) {
                    512:         case 1:
                    513:                // 引数なし
                    514:                CommandNvramShowAll();
                    515:                break;
                    516:         case 2:
                    517:                // 引数1つ
                    518:                if (arg[1] == "--") {
                    519:                        CommandNvramInit();
                    520:                } else {
                    521:                        CommandNvramShow(arg);
                    522:                }
                    523:                break;
                    524:         case 3:
                    525:                // 引数2つ
                    526:                if (arg[1] == "-") {
                    527:                        CommandNvramDelete(arg);
                    528:                } else {
                    529:                        CommandNvramUpdate(arg);
                    530:                }
                    531:                break;
                    532:         default:
                    533:                text.Print("** Syntax error\n");
                    534:        }
                    535: }
                    536: 
                    537: // NVRAM は 32バイトを1エントリとする。
                    538: // [0] はヘッダに相当し、フォーマットは別記。
                    539: // [1] 以降が key (16バイト)、val(16バイト) の並び。こんな感じ。
                    540: //
                    541: // 00000020  62 6f 6f 74 5f 64 65 76 69 63 65 00 00 00 00 00 |boot_device.....|
                    542: // 00000030  73 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |sd..............|
                    543: //
                    544: // key, val とも '\0' で終端もしくは16文字で終端のようだ。
                    545: // val に17文字を設定しようとすると怒られる。
                    546: // key が "" ならこのエントリは空きで val は無視、
                    547: // 空きエントリは無視して次へ (FAT のディレクトリエントリみたいな感じ)。
                    548: // val が "" は有効。
                    549: //
                    550: // オフセット 0x540 から始まるエントリが最後で、これ以上追加しようとすると
                    551: // "nvram set error: no area" (PROM 1.20) と言われる。
                    552: // LUNA88K にはないが LUNA-I では 0x560 にぽつんと ENADDR があったので、
                    553: // その辺りとの互換性だろうか。
                    554: 
                    555: // NVRAM 全項目表示
                    556: void
                    557: Luna88kPROMEmuDevice::CommandNvramShowAll()
                    558: {
                    559:        putmsg(1, "nvram ShowAll");
                    560:        for (uint32 offset = 0x20; offset < 0x560; offset += 0x20) {
                    561:                std::string key = nvram->PeekString(offset);
                    562:                if (key.empty()) {
                    563:                        continue;
                    564:                }
                    565:                std::string val = nvram->PeekString(offset + 16);
                    566:                text.Print("%-15s : %s\n", key.c_str(), val.c_str());
                    567:        }
                    568: }
                    569: 
                    570: // NVRAM 指定項目を表示
                    571: void
                    572: Luna88kPROMEmuDevice::CommandNvramShow(const std::vector<std::string>& arg)
                    573: {
                    574:        assert(arg.size() >= 2);
                    575:        const std::string& key = arg[1];
                    576: 
                    577:        putmsg(1, "nvram Show |%s|", key.c_str());
                    578:        uint32 offset = FindNVRAM(key);
                    579:        if (offset > 0) {
                    580:                std::string val = nvram->PeekString(offset + 16);
                    581:                text.Print("%-15s : %s\n", key.c_str(), val.c_str());
                    582:        } else {
                    583:                text.Print("** Not found\n");
                    584:        }
                    585: }
                    586: 
                    587: // NVRAM 項目を追加/更新
                    588: void
                    589: Luna88kPROMEmuDevice::CommandNvramUpdate(const std::vector<std::string>& arg)
                    590: {
                    591:        // キーがあれば更新、なければ追加。
                    592:        // いずれも事前にプロンプトで確認する。
                    593: 
                    594:        assert(arg.size() >= 3);
                    595:        nvram_key = arg[1];
                    596:        nvram_val = arg[2];
                    597:        putmsg(1, "nvram Update |%s|%s|", nvram_key.c_str(), nvram_val.c_str());
                    598: 
                    599:        if (nvram_key.size() > 16) {
                    600:                text.Print("** Key too long\n");
                    601:                return;
                    602:        }
                    603:        if (nvram_val.size() > 16) {
                    604:                text.Print("** Val too long\n");
                    605:                return;
                    606:        }
                    607: 
                    608:        nvram_offset = FindNVRAM(nvram_key);
                    609:        if (nvram_offset > 0) {
                    610:                // キーがすでにあれば更新。
                    611:                // Update2() に申し送りするのは nvram_offset と nvram_val のみでいい。
                    612: 
                    613:                std::string oldval = nvram->PeekString(nvram_offset + 16);
                    614:                prompt = string_format("Update %s : \"%s\" -> \"%s\" (Y/[N]):",
                    615:                        nvram_key.c_str(), oldval.c_str(), nvram_val.c_str());
                    616:                prompt_idx = PROMPT_NVRAM_UPDATE;
                    617:        } else {
                    618:                // キーがなければ追加
                    619:                // New2() に申し送りするのは nvram_offset, nvram_key, nvram_val の3つ。
                    620: 
                    621:                // 先に空き領域をチェックしている
                    622:                nvram_offset = FindNVRAM("");
                    623:                if (nvram_offset == 0) {
                    624:                        text.Print("** No area available\n");
                    625:                        return;
                    626:                }
                    627: 
                    628:                prompt = string_format("Set new %s : \"%s\" (Y/[N]):",
                    629:                        nvram_key.c_str(), nvram_val.c_str());
                    630:                prompt_idx = PROMPT_NVRAM_NEW;
                    631:        }
                    632: 
                    633:        // 入力待ちの状態で戻る
                    634:        // (prompt_idx != 0 なのでキー入力後に指定の関数へ飛んで続きを実行する)
                    635: }
                    636: 
                    637: // NVRAM 項目を更新 (キー入力後)
                    638: void
                    639: Luna88kPROMEmuDevice::CommandNvramUpdate2(char asciicode)
                    640: {
                    641:        assert(prompt_idx == PROMPT_NVRAM_UPDATE);
                    642:        assert(nvram_offset > 0);
                    643:        assert(nvram_val.size() <= 16);
                    644: 
                    645:        text.CRLF();
                    646: 
                    647:        if (asciicode != 'y' && asciicode != 'Y') {
                    648:                text.Print("** Not updated\n");
                    649:                return;
                    650:        }
                    651: 
                    652:        if (nvram->WriteString(nvram_offset + 16, nvram_val) == false) {
                    653:                text.Print("** Write error\n");
                    654:                return;
                    655:        }
                    656:        WriteNVRAMCsum();
                    657: 
                    658:        text.Print("Updated\n");
                    659: }
                    660: 
                    661: // NVRAM 項目を追加 (キー入力後)
                    662: void
                    663: Luna88kPROMEmuDevice::CommandNvramNew2(char asciicode)
                    664: {
                    665:        assert(prompt_idx == PROMPT_NVRAM_NEW);
                    666:        assert(nvram_offset > 0);
                    667:        assert(!nvram_key.empty());
                    668:        assert(nvram_key.size() <= 16);
                    669:        assert(nvram_val.size() <= 16);
                    670: 
                    671:        text.CRLF();
                    672: 
                    673:        if (asciicode != 'y' && asciicode != 'Y') {
                    674:                text.Print("** Not added\n");
                    675:                return;
                    676:        }
                    677: 
                    678:        if (nvram->WriteString(nvram_offset, nvram_key) == false
                    679:         || nvram->WriteString(nvram_offset + 16, nvram_val) == false) {
                    680:                text.Print("** Write error\n");
                    681:                return;
                    682:        }
                    683:        WriteNVRAMCsum();
                    684: 
                    685:        text.Print("Added\n");
1.1.1.2   root      686: }
                    687: 
1.1.1.7   root      688: // NVRAM 項目削除
                    689: //
                    690: // 削除する時は確認がないらしい… (PROM 1.20)
                    691: // 成功しても何も言わないらしい… (PROM 1.20)
                    692: // 追加削除に比べてなんか雑じゃない?
                    693: void
                    694: Luna88kPROMEmuDevice::CommandNvramDelete(const std::vector<std::string>& arg)
                    695: {
                    696:        assert(arg.size() >= 3);
                    697:        assert(arg[1] == "-");
                    698:        const std::string& key = arg[2];
                    699:        putmsg(1, "nvram Delete |%s|", key.c_str());
                    700: 
                    701:        if (key.size() > 16) {
                    702:                text.Print("** key too long\n");
                    703:                return;
                    704:        }
                    705: 
                    706:        uint32 offset = FindNVRAM(key);
                    707:        if (offset == 0) {
                    708:                text.Print("** Not found\n");
                    709:                return;
                    710:        }
                    711: 
                    712:        // キーを消せば削除になる (値のほうは消してないようだ)
                    713:        nvram->WriteString(offset, "");
                    714:        WriteNVRAMCsum();
                    715: }
                    716: 
                    717: // NVRAM から key を探してそのエントリのオフセットを返す。
                    718: // key == "" なら空きエントリを探す。
                    719: // 見付からなければ 0 を返す (オフセット 0 はパラメータには使わないため)
                    720: uint32
                    721: Luna88kPROMEmuDevice::FindNVRAM(const std::string& key) const
1.1.1.2   root      722: {
1.1.1.7   root      723:        for (uint32 offset = 0x20; offset < 0x560; offset += 0x20) {
                    724:                std::string k = nvram->PeekString(offset);
                    725:                if (k == key) {
                    726:                        return offset;
                    727:                }
                    728:                // XXX 同じキーが複数あったらどうなるか
                    729:        }
1.1.1.2   root      730:        return 0;
                    731: }
                    732: 
1.1.1.7   root      733: // NVRAM 初期化
1.1.1.5   root      734: void
1.1.1.7   root      735: Luna88kPROMEmuDevice::CommandNvramInit()
1.1.1.2   root      736: {
1.1.1.7   root      737:        putmsg(1, "nvram Init");
                    738: 
                    739:        prompt = "Initialize (Y/[N]):";
                    740:        prompt_idx = PROMPT_NVRAM_INIT;
                    741: 
                    742:        // 入力待ちの状態で戻る
1.1.1.2   root      743: }
                    744: 
1.1.1.7   root      745: // NVRAM 初期化 (キー入力後)
                    746: void
                    747: Luna88kPROMEmuDevice::CommandNvramInit2(char asciicode)
1.1.1.2   root      748: {
1.1.1.7   root      749:        assert(prompt_idx == PROMPT_NVRAM_INIT);
                    750: 
                    751:        text.CRLF();
                    752: 
                    753:        if (asciicode != 'y' && asciicode != 'Y') {
                    754:                text.Print("** Not initialized\n");
                    755:                return;
                    756:        }
                    757: 
                    758:        InitNVRAM();
                    759:        text.Print("** Initialized\n");
1.1       root      760: }
                    761: 
1.1.1.5   root      762: // NVRAM を初期化する
                    763: bool
                    764: Luna88kPROMEmuDevice::InitNVRAM()
1.1       root      765: {
1.1.1.7   root      766:        nvram->ClearAll();
                    767: 
                    768:        nvram->WriteString(0x0004, "<nv>");
                    769:        nvram->WriteString(0x0020, "boot_device");
                    770:        nvram->WriteString(0x0030, "sd");
                    771:        nvram->WriteString(0x0040, "boot_spec");
                    772:        nvram->WriteString(0x0050, "0");
                    773:        nvram->WriteString(0x0060, "boot_unit");
                    774:        nvram->WriteString(0x0070, "0");
                    775:        nvram->WriteString(0x0080, "boot_partition");
                    776:        nvram->WriteString(0x0090, "0");
                    777:        nvram->WriteString(0x00a0, "boot_filename");
                    778:        nvram->WriteString(0x00b0, "vmunix");
                    779:        nvram->WriteString(0x00c0, "main_mem_check");
                    780:        nvram->WriteString(0x00d0, "1");
                    781:        nvram->WriteString(0x00e0, "3port_mem_check");
                    782:        nvram->WriteString(0x00f0, "1");
                    783: 
                    784:        // チェックサム再計算
                    785:        WriteNVRAMCsum();
                    786: 
                    787:        return true;
1.1.1.5   root      788: }
1.1       root      789: 
1.1.1.5   root      790: // NVRAM のブート設定を bootinfo に取得する。
                    791: void
                    792: Luna88kPROMEmuDevice::GetNVRAM(bootinfo_t& bootinfo)
                    793: {
1.1.1.7   root      794:        // dkunit (装置番号) はたぶん boot_unit (0..)
                    795:        // dkpart (パーティション) は boot_partition (0..)
                    796:        // dkfile (ファイル名) は boot_filename
                    797:        // sd 以外のデバイスは未対応
                    798:        bootinfo.dkunit = nvram->Peek(0x0070) - '0';
                    799:        bootinfo.dkpart = nvram->Peek(0x0090) - '0';
                    800:        bootinfo.dkfile = nvram->PeekString(0x00b0);
                    801:        putmsg(1, "%s unit=%d", __func__, bootinfo.dkunit);
                    802:        putmsg(1, "%s part=%c", __func__, bootinfo.dkpart + 'a');
                    803:        putmsg(1, "%s file=|%s|", __func__, bootinfo.dkfile.c_str());
1.1       root      804: }
1.1.1.8 ! root      805: 
        !           806: // コールバック関数 (C のグローバル関数)
        !           807: bool
        !           808: luna88k_fline_callback(m88kcpu *cpu, void *arg)
        !           809: {
        !           810:        Luna88kPROMEmuDevice *dev = (Luna88kPROMEmuDevice *)arg;
        !           811:        return dev->FLineCallback(cpu);
        !           812: }
        !           813: 
        !           814: // コールバック関数 (こっちが実体)
        !           815: bool
        !           816: Luna88kPROMEmuDevice::FLineCallback(m88kcpu *cpu)
        !           817: {
        !           818:        // 111111_DDDDDSSSSS_000001_00nnnnnnnn
        !           819:        //
        !           820:        // 引数は rS1 から順番に格納。
        !           821:        // m68k 的なバイト値やワード値の場合は下位詰めしてあるが、不要な上位
        !           822:        // ビットの処置はゲストコードよりホストコードで行うほうが楽なので、
        !           823:        // すべてこちらで責任持って処理すること。
        !           824:        // 戻り値がある DOS call では戻り値は rD に格納。
        !           825: 
        !           826:        uint32 D   = (cpu->opX >> 21) & 0x1f;
        !           827:        uint32 S1  = (cpu->opX >> 16) & 0x1f;
        !           828:        uint32 num =  cpu->opX        & 0xff;
        !           829: 
        !           830:        switch (num) {
        !           831:         case 0x00:     // _EXIT
        !           832:                break;
        !           833: 
        !           834:         case 0x01:     // _GETCHAR
        !           835:                cpu->r[D] = getchar();
        !           836:                break;
        !           837: 
        !           838:         case 0x02:     // _PUTCHAR
        !           839:                putchar(cpu->r[S1++] & 0xffff);
        !           840:                break;
        !           841: 
        !           842:         default:
        !           843:                putlog(0, "未実装 DOS call #$%02x", num);
        !           844:                cpu->r[D] = 0xffffffff;
        !           845:                break;
        !           846:        }
        !           847: 
        !           848:        // 存在しないコール番号、未実装コールも含めて処理済みとする。
        !           849:        return true;
        !           850: }

unix.superglobalmegacorp.com

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