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

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 エミュレーション
                      8: 
                      9: //             IODevice
                     10: //                |
1.1.1.5   root       11: //     +----------+---------------------+
                     12: //     v                                v
                     13: // ROMDevice                 LunaPROMEmuDeivce (ROM エミュレーションの共通部分)
                     14: //     |                                |
                     15: //     |                   +------------+----------------+
                     16: //     v                   v                             v
                     17: // PROMDevice      Luna1PROMEmuDevice          Luna88kPROMEmuDevice
                     18: // (実ROM)         (LUNA-I エミュレーション)   (LUNA88K エミュレーション)
1.1.1.2   root       19: 
                     20: #include "romemu_luna88k.h"
1.1.1.5   root       21: #include "bitmap.h"
                     22: #include "iodevstream.h"
1.1       root       23: #include "mainapp.h"
                     24: #include "memorystream.h"
1.1.1.5   root       25: #include "pio.h"
1.1       root       26: #include "ram.h"
1.1.1.5   root       27: #include "sysctlr.h"
1.1       root       28: 
                     29: // コンストラクタ
                     30: Luna88kPROMEmuDevice::Luna88kPROMEmuDevice()
                     31: {
                     32:        devaddr = baseaddr;
1.1.1.5   root       33: 
                     34:        // ROM の特定アドレスを読み出す人がいるかも知れないので、
                     35:        // サイズは実 ROM と同じにしておく。LUNA-I からの類推。
1.1.1.2   root       36:        devlen = 256 * 1024;
1.1.1.5   root       37:        romdata.reset(new uint8 [devlen]);
1.1.1.2   root       38: 
1.1.1.5   root       39:        // プロンプトを初期化。
                     40:        // 本物は "O>" というプロンプトでよく分からんけど、こっちは nono の
                     41:        // 頭文字ということにしておく。
                     42:        prompt = "N>";
1.1       root       43: }
                     44: 
                     45: // デストラクタ
                     46: Luna88kPROMEmuDevice::~Luna88kPROMEmuDevice()
                     47: {
                     48: }
                     49: 
                     50: bool
                     51: Luna88kPROMEmuDevice::Init()
                     52: {
1.1.1.5   root       53:        // 親クラス
                     54:        if (inherited::Init() == false) {
                     55:                return false;
                     56:        }
                     57: 
1.1.1.2   root       58:        MemoryStreamBE ms(romdata.get());
1.1       root       59: 
1.1.1.6 ! root       60:        // リセット時のブートページには ROM (これ) が見えている。
        !            61:        // ROMIO_INIT へのアクセスでブートページを RAM に切り替えて、同時に RAM の
        !            62:        // 0番地付近のベクタも作り直す。そのため、ここのベクタ1 以降 ($41000008〜)
        !            63:        // をベクタとして参照することはないので、ベクタ0 の命令列がそのまま使い潰
        !            64:        // してよい。というか2ワードでは 0番地から ROM まで飛べないので使わないと
        !            65:        // 面倒くさい。一体どういう設計してんだ…。
        !            66: 
        !            67:                                                                        //      ; _ROM_START へジャンプ (ここは0番地)
        !            68:        ms.Write32(0x5cc04100);                 //  or.u        r6, r0, #0x4100
        !            69:        ms.Write32(0x58c6000c);                 //      or              r6, r6, #0x000c
        !            70:        ms.Write32(0xf400c006);                 //      jmp             r6
1.1.1.5   root       71: 
1.1.1.6 ! root       72:                                                                        // _ROM_START: (ここは ROM)
1.1.1.5   root       73:                                                                        //      ; 元の PSR を r10 に保存しつつ
                     74:                                                                        //      ; 割り込み許可
                     75:        ms.Write32(0x81404020);                 //      ldcr    r10, psr
                     76:        ms.Write32(0xf04a8040);                 //      clr             r2, r10, 2<1>   ; IND,SFRZ
                     77:        ms.Write32(0x80028022);                 //      stcr    r2, psr
                     78:                                                                        //      ; r3 <- ROMIO_BASE
                     79:        ms.Write32(0x5c600000 |                 //      or.u    r3, r0, #ROMIO_BASE.Hi
                     80:                (ROMIO_BASE >> 16));            //
                     81:        ms.Write32(0x58630000 |                 //      or              r3, r0, #ROMIO_BASE.Lo
                     82:                (ROMIO_BASE & 0xffff));         //
                     83:                                                                        //      ; ROMIO_INIT を読み出す
                     84:        ms.Write32(0x14430000);                 //      ld              r2, r3, #+INIT
                     85:                                                                        //      ; 起動先があれば GO
                     86:        ms.Write32(0xe9a20005);                 //      bcnd    ne0, r2, _go
                     87:                                                                        // _prompt:
                     88:                                                                        //      ; 疑似 STOP でキー入力を待つ
                     89:        ms.Write32(0xc8000001);                 //      bsr             _stop
                     90:                                                                        //      ; この時点で r1 = _stop
                     91:                                                                        // _stop:
                     92:        ms.Write32(0xf400c001);                 //      jmp             r1
                     93:                                                                        // _back:
                     94:        ms.Write32(0x14430000 |                 //      ld              r2, r3, #+ENTRY
                     95:                (ROMIO_ENTRY - ROMIO_BASE));//
                     96:                                                                        //      ; 起動先がなければループ
                     97:        ms.Write32(0xe842fffd);                 //      bcnd    eq0, r2, _prompt
                     98:                                                                        //      ; 起動先があれば後始末して
                     99:        ms.Write32(0x14030000 |                 // _go:
                    100:                (ROMIO_CLOSE - ROMIO_BASE));//  ld              r0, r3, #+CLOSE
                    101:                                                                        //      ; 割り込み禁止に戻す
                    102:        ms.Write32(0x800a802a);                 //      stcr    r10, psr
                    103:                                                                        //      ; ジャンプ
                    104:        ms.Write32(0xf400c002);                 //      jmp             r2
                    105: 
                    106:        // ここから割り込みハンドラ。割り込みは SIO のみ許可にしてある。
                    107:        // キーボード割り込みが上がったら KEYIN をコールして _back に戻る。
                    108:        ms.SetPtr(&romdata[0x200]);
                    109:        ms.Write32(0x14030000 |                 //      ld              r0, r3, #+KEYIN
                    110:                (ROMIO_KEYIN - ROMIO_BASE));//
                    111:                                                                        //      ; 戻ったところの jmp を抜ける
                    112:        ms.Write32(0x60210004);                 //      addu    r1, r1, #4
                    113:        ms.Write32(0xf400fc00);                 //      rte
1.1       root      114: 
                    115:        return true;
                    116: }
                    117: 
1.1.1.6 ! root      118: void
        !           119: Luna88kPROMEmuDevice::ResetHard()
        !           120: {
        !           121:        inherited::ResetHard();
        !           122: 
        !           123:        b_entrypoint = 0;
        !           124: }
        !           125: 
1.1.1.5   root      126: // 起動時の処理を行う。
                    127: // 次段実行ファイルの読み込みに成功すればそのエントリポイントを返す。
                    128: // そうでなければ 0 を返すので、プロンプトに処理を移すこと。
                    129: uint32
                    130: Luna88kPROMEmuDevice::ROM_Init()
1.1       root      131: {
1.1.1.5   root      132:        IODeviceStream rs(gRAM.get());
                    133:        uint32 entry;
1.1       root      134: 
1.1.1.5   root      135:        // デバイスの初期化 (親クラス)
                    136:        InitDevice();
1.1.1.6 ! root      137: 
1.1.1.5   root      138:        // 割り込みマスクで SIO だけ許可
                    139:        gInterrupt->Write32(0x65000000, 0x40000000);
1.1       root      140: 
1.1.1.5   root      141:        rs.SetAddr(0);
                    142:        // ベクタテーブルを rte で埋めておく
                    143:        for (int i = 0; i < 512 * 2; i++) {
                    144:                rs.Write32(0xf400fc00 /* rte */);
                    145:        }
                    146:        // +$08: 割り込みベクタ
                    147:        rs.Write32(8, 0xc00003fe);              // br   $00001000
                    148: 
                    149:        // 割り込みトランポリン (0x1000)
                    150:        // ベクタテーブルは各2ワードしかないのに、0 番地付近にあるベクタテーブル
                    151:        // から2ワードでは ROM まで飛べない。一体どういう設計してんだ…。
                    152:        rs.SetAddr(0x1000);
                    153:        rs.Write32(0x5cc04100);                 // or.u r6, r0, #0x4100
                    154:        rs.Write32(0x58c60200);                 // or   r6, r6, #0x0200
                    155:        rs.Write32(0xf400c006);                 // jmp  r6
1.1.1.2   root      156: 
1.1.1.5   root      157:        // ROM の機能テーブル
                    158:        // 0x00001100 からあるようだ
                    159:        // 0x0000110c GETC()
                    160:        // 0x00001110 PUTC(c)
                    161:        // 0x00001114 ビットマッププレーンの有効状態が入っている。
                    162:        //  bit0: plane0 有効
                    163:        //  bit1..7: plane1..7 有効
                    164:        rs.SetAddr(0x110c);
                    165:        rs.Write32(0x00001300);
                    166:        rs.Write32(0x00001400);
                    167:        rs.Write32(0x00000001);
                    168: 
                    169:        // ROM GETC エミュレータ
                    170:        rs.SetAddr(0x1300);
                    171:        rs.Write32(0xfc000c00);                 // internal inst getc
                    172:        rs.Write32(0xf400c001);                 // jmp r1
1.1.1.2   root      173: 
1.1.1.5   root      174:        // ROM PUTC エミュレータ
                    175:        rs.SetAddr(0x1400);
                    176:        rs.Write32(0xfc001000);                 // internal inst putc
                    177:        rs.Write32(0xf400c001);                 // jmp r1
                    178: 
                    179:        // スクリーンを初期化
                    180:        InitScreen("LUNA88K");
                    181: 
                    182:        entry = 0;
                    183: 
                    184:        // 表示環境が整ったところで NVRAM を照合
                    185:        if (VerifyNVRAM() == false) {
                    186:                InitNVRAM();
                    187:                text.Print("** NVRAM Initialized.\n");
                    188:                text.Print("\n");
                    189:                // NVRAM をクリアしたら DIPSW によらずプロンプトに降りる
                    190:                goto done;
                    191:        }
                    192: 
                    193:        // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、
                    194:        // これを真似する。
                    195:        if ((gPIO0->GetDIPSW1() & 1)) {
                    196:                if (gMainApp.host_file) {
                    197:                        // ホストのファイルを読み込んでエントリポイントアドレスを
                    198:                        // この Read アクセスの読み出し値として返す。
                    199:                        // エラーがあればエラーメッセージは呼び出し先側で表示してある。
                    200:                        entry = LoadHostFile();
                    201:                } else {
                    202:                        // NVRAM の設定に従ってブート先を探す。
                    203:                        errmsg.clear();
                    204: 
                    205:                        bootinfo_t bootinfo;
                    206:                        GetNVRAM(bootinfo);
                    207:                        entry = LoadGuestFile(bootinfo);
                    208:                        if (entry == 0) {
                    209:                                text.Print("** %s\n", errmsg.c_str());
                    210:                        }
                    211:                }
                    212:        }
                    213: 
                    214:        // ここまでタイトルなどを Print してはいるが、実際の画面更新は
                    215:        // ConsoleUpdate() を呼ぶまで行われないことを利用(悪用?)して、
                    216:        // ここでエラーなくブートプログラムに制御を渡せる場合には何も表示せずに
                    217:        // ゲストに処理を移す。意図して或いは意図せずプロンプトに降りる場合だけ
                    218:        // ConsoleUpdate を呼ぶことでタイトルを含めて画面を表示する。
                    219:  done:
                    220:        if (entry == 0) {
                    221:                ConsoleUpdate();
                    222:        }
                    223: 
                    224:        return entry;
                    225: }
                    226: 
                    227: // ROM 処理。エントリポイントを返す。
                    228: uint32
                    229: Luna88kPROMEmuDevice::ROM_Entry()
                    230: {
                    231:        if (b_entrypoint != 0) {
                    232:                return b_entrypoint;
1.1.1.2   root      233:        } else {
1.1.1.5   root      234:                return 0;
1.1.1.2   root      235:        }
                    236: }
                    237: 
1.1.1.5   root      238: // 入力コマンド処理 (入力行が揃ったところで呼ばれる)。
                    239: //
                    240: // b                                   現在のパラメータで起動
                    241: // b ...                               パラメータを指定して起動
                    242: // nvram                               全パラメータを表示
                    243: // nvram [<name>]              name のみ表示?
                    244: // nvram <name> <val>  値を設定
                    245: // nvram - <name>              削除
                    246: // nvram--                             NVRAM 初期化
                    247: 
                    248: void
                    249: Luna88kPROMEmuDevice::Command()
1.1.1.2   root      250: {
1.1.1.5   root      251:        std::vector<char> buf(inputbuf.length() + 1);
                    252:        std::vector<std::string> arg;
1.1.1.2   root      253: 
1.1.1.5   root      254:        // 1ワードごとに分解
                    255:        strcpy(&buf[0], inputbuf.c_str());
                    256:        char *p = &buf[0];
1.1.1.6 ! root      257:        for (char *ap; (ap = strsep(&p, " ")) != NULL; ) {
        !           258:                if (*ap != '\0') {
        !           259:                        arg.push_back(std::string(ap));
1.1.1.5   root      260:                }
                    261:        }
                    262:        if (loglevel >= 1) {
                    263:                for (int i = 0; i < arg.size(); i++) {
                    264:                        putmsgn("arg[%d]=|%s|", i, arg[i].c_str());
                    265:                }
                    266:        }
1.1.1.2   root      267: 
1.1.1.5   root      268:        // 空行
                    269:        if (arg.size() == 0) {
                    270:                return;
                    271:        }
                    272: 
                    273:        // 1ワード目がコマンド
                    274:        if (arg[0] == "h") {
                    275:                // ヘルプメッセージ
                    276:                text.Print(
                    277: "         *** Help Message ***\n"
                    278: "  b      : load and execute program\n"
                    279: "  h      : show this message\n"
                    280: #if 0
                    281: "  nvram  : show/set nvram parameters\n"
                    282: #endif
                    283:                );
                    284:                return;
                    285:        }
                    286:        if (arg[0] == "b") {
                    287:                CommandB(arg);
                    288:                return;
                    289:        }
                    290: #if 0
                    291:        if (arg[0] == "nvram") {
                    292:                CommandNvram(arg);
                    293:                return;
1.1.1.2   root      294:        }
1.1.1.5   root      295: #endif
                    296: 
                    297:        text.Print("** Unknown command: %s\n", arg[0].c_str());
1.1.1.2   root      298: }
                    299: 
1.1.1.5   root      300: // "b" コマンド
                    301: // 引数なしなら NVRAM の情報に従ってプログラムをロードして実行。
                    302: // 引数ありのほうは未実装。
                    303: void
                    304: Luna88kPROMEmuDevice::CommandB(const std::vector<std::string>& arg)
1.1       root      305: {
1.1.1.5   root      306:        errmsg.clear();
1.1       root      307: 
1.1.1.5   root      308:        // XXX とりあえず boot を起動するだけ
                    309:        bootinfo_t bootinfo;
                    310:        GetNVRAM(bootinfo);
                    311:        b_entrypoint = LoadGuestFile(bootinfo);
                    312:        if (b_entrypoint == 0) {
                    313:                text.Print("** %s\n", errmsg.c_str());
1.1       root      314:        }
1.1.1.5   root      315: }
1.1       root      316: 
1.1.1.5   root      317: // "bh" コマンド (勝手に拡張)
                    318: // -A オプションで指定されたホストプログラムをロードして実行。
                    319: void
                    320: Luna88kPROMEmuDevice::CommandBH()
                    321: {
                    322:        // 指定されてたら読み込む
                    323:        if (gMainApp.host_file == NULL) {
                    324:                text.Print("** Cannot loaded; host program is not specified.\n");
                    325:                return;
1.1.1.2   root      326:        }
1.1.1.5   root      327:        b_entrypoint = LoadHostFile();
1.1.1.2   root      328: }
                    329: 
1.1.1.5   root      330: void
                    331: Luna88kPROMEmuDevice::CommandNvram(const std::vector<std::string>& arg)
1.1.1.2   root      332: {
1.1.1.5   root      333:        printf("%s\n", __func__);
1.1.1.2   root      334: }
                    335: 
1.1.1.5   root      336: // NVRAM のチェックサムを返す
                    337: uint8
                    338: Luna88kPROMEmuDevice::CalcNVRAMCsum()
1.1.1.2   root      339: {
                    340:        return 0;
                    341: }
                    342: 
1.1.1.5   root      343: // NVRAM のチェックサムを計算して書き込む
                    344: void
                    345: Luna88kPROMEmuDevice::WriteNVRAMCsum()
1.1.1.2   root      346: {
                    347: }
                    348: 
1.1.1.5   root      349: // NVRAM のマジックとチェックサムを照合する
                    350: bool
                    351: Luna88kPROMEmuDevice::VerifyNVRAM()
1.1.1.2   root      352: {
1.1.1.5   root      353:        return true;
1.1       root      354: }
                    355: 
1.1.1.5   root      356: // NVRAM を初期化する
                    357: bool
                    358: Luna88kPROMEmuDevice::InitNVRAM()
1.1       root      359: {
1.1.1.5   root      360:        return false;
                    361: }
1.1       root      362: 
1.1.1.5   root      363: // NVRAM のブート設定を bootinfo に取得する。
                    364: void
                    365: Luna88kPROMEmuDevice::GetNVRAM(bootinfo_t& bootinfo)
                    366: {
                    367:        // XXX NVRAM 未調査につき ID=6 a: boot 固定
                    368:        bootinfo.dkunit = 0;
                    369:        bootinfo.dkpart = 0;
                    370:        bootinfo.dkfile = "boot";
1.1       root      371: }

unix.superglobalmegacorp.com

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