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

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

unix.superglobalmegacorp.com

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