Annotation of nono/vm/romemu_luna.cpp, revision 1.1.1.17

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.13  root        7: //
1.1.1.7   root        8: // LUNA シリーズの ROM エミュレーション共通部分
1.1.1.10  root        9: //
1.1.1.13  root       10: 
1.1.1.10  root       11: // IODevice
1.1.1.16  root       12: //  |
                     13: //  +- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
                     14: //  |   +- PROMDevice    (LUNA* の PROM)
                     15: //  |   +- IPLROM1Device (X680x0 の IPLROM 後半)
                     16: //  |   +- IPLROM2Device (X680x0 の IPLROM 前半)
                     17: //  |   +- CGROMDevice   (X680x0 の CGROM)
                     18: //  |   |
                     19: //  |   +- ROMEmuDevice
                     20: //  |       |
                     21: //  |       | +-------------------+
                     22: //  |       +-| LunaPROMEmuDevice | (LUNA PROM エミュレーションの共通部分)
                     23: //  |       | +-------------------+
                     24: //  |       |   |
                     25: //  |       |   +- Luna1PROMEmuDevice   (LUNA-I の PROM エミュレーション)
                     26: //  |       |   +- Luna88kPROMEmuDevice (LUNA-88K の PROM エミュレーション)
                     27: //  |       +- NewsROMEmuDevice    (NEWS の ROM エミュレーション)
                     28: //  |       +- ROM30EmuDevice      (X68030 の ROM30 エミュレーション)
                     29: //  |       +- Virt68kROMEmuDevice (virt-m68k の IPLROM 相当の何か)
                     30: //  |
                     31: //  +- PROM0Device   (LUNA* のブートページ切り替え用プロキシ)
                     32: //  +- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ)
1.1.1.2   root       33: 
                     34: #include "romemu_luna.h"
1.1.1.14  root       35: #include "bt45x.h"
1.1.1.15  root       36: #include "builtinrom.h"
1.1.1.16  root       37: #include "lance.h"
1.1.1.9   root       38: #include "lunafb.h"
1.1       root       39: #include "mainapp.h"
1.1.1.14  root       40: #include "mainram.h"
1.1       root       41: #include "mk48t02.h"
1.1.1.13  root       42: #include "mpu.h"
1.1.1.14  root       43: #include "pio.h"
1.1.1.13  root       44: #include "prom.h"
1.1.1.16  root       45: #include "scsidev.h"
1.1       root       46: #include "sio.h"
                     47: #include "spc.h"
1.1.1.7   root       48: #include "ufs.h"
1.1       root       49: 
                     50: // コンストラクタ
                     51: LunaPROMEmuDevice::LunaPROMEmuDevice()
1.1.1.14  root       52:        : inherited(OBJ_PROM)
1.1       root       53: {
1.1.1.10  root       54:        // LUNA では ROM への書き込みは何も起きない
                     55:        write_op = 0;
1.1       root       56: }
                     57: 
                     58: // デストラクタ
                     59: LunaPROMEmuDevice::~LunaPROMEmuDevice()
                     60: {
                     61: }
                     62: 
1.1.1.14  root       63: // 初期化
1.1       root       64: bool
                     65: LunaPROMEmuDevice::Init()
                     66: {
1.1.1.14  root       67:        bt45x = GetBT45xDevice();
1.1.1.16  root       68:        lance = GetLanceDevice();
1.1.1.14  root       69:        lunafb = GetLunafbDevice();
                     70:        mainram = GetMainRAMDevice();
                     71:        nvram = GetMK48T02Device();
                     72:        sio = GetSIODevice();
                     73:        spc = GetSPCDevice();
1.1       root       74: 
                     75:        return true;
                     76: }
                     77: 
1.1.1.16  root       78: // ROMIO から読み出す。
                     79: // ROMIO が応答すべきでなければ (uint64)-1 を返す。
                     80: uint64
                     81: LunaPROMEmuDevice::ReadROMIO(busaddr addr)
1.1       root       82: {
1.1.1.10  root       83:        // ROM からのロングワードアクセスでだけ謎の I/O 空間が見える。
1.1.1.16  root       84:        if ((mpu->GetPPC() & 0xff000000) == baseaddr && addr.GetSize() == 4) {
                     85:                switch (addr.Addr()) {
1.1.1.9   root       86:                 case ROMIO_INIT:
1.1.1.16  root       87:                        ROM_Init();
                     88:                        return 0;
1.1       root       89: 
1.1.1.15  root       90:                 case ROMIO_LOAD:
                     91:                        entrypoint = ROM_Load();
                     92:                        putlog(2, "ROMIO_LOAD entrypoint=$%08x", entrypoint);
                     93:                        return 0;
                     94: 
1.1.1.9   root       95:                 case ROMIO_KEYIN:
1.1.1.15  root       96:                        putlog(2, "ROMIO_KEYIN");
1.1.1.7   root       97:                        ROM_Keyin();
                     98:                        return 0;
1.1       root       99: 
1.1.1.9   root      100:                 case ROMIO_CLOSE:
1.1.1.15  root      101:                        putlog(2, "ROMIO_CLOSE");
1.1.1.7   root      102:                        ROM_Close();
                    103:                        return 0;
1.1       root      104: 
1.1.1.9   root      105:                 case ROMIO_ENTRY:
1.1.1.15  root      106:                 {
                    107:                        uint32 rv = ROM_Entry();
                    108:                        putlog(2, "ROMIO_ENTRY entrypoint=$%08x", rv);
                    109:                        return rv;
                    110:                 }
                    111: 
                    112:                 case ROMIO_AP1:
                    113:                        ROM_AP1();
                    114:                        return 0;
                    115: 
                    116:                 case ROMIO_AP2:
                    117:                        ROM_AP2();
                    118:                        return 0;
                    119: 
                    120:                 case ROMIO_CLKCNT:
                    121:                        return clkcnt;
1.1.1.6   root      122: 
1.1       root      123:                 default:
                    124:                        break;
                    125:                }
                    126:        }
1.1.1.2   root      127: 
1.1.1.16  root      128:        return (uint64)-1;
1.1       root      129: }
                    130: 
1.1.1.16  root      131: // ROMIO に書き込む。
                    132: // 反応すれば true を返す。そうでなければ false を返す。
                    133: bool
                    134: LunaPROMEmuDevice::WriteROMIO(busaddr addr, uint32 data)
1.1       root      135: {
1.1.1.15  root      136:        // ROM からのロングワードアクセスでだけ謎の I/O 空間が見える。
1.1.1.16  root      137:        if ((mpu->GetPPC() & 0xff000000) == baseaddr && addr.GetSize() == 4) {
                    138:                switch (addr.Addr()) {
1.1.1.15  root      139:                 case ROMIO_CLKCNT:
                    140:                        clkcnt = data;
1.1.1.16  root      141:                        return true;
1.1.1.15  root      142:                 default:
                    143:                        break;
                    144:                }
                    145:        }
                    146: 
1.1.1.16  root      147:        return false;
1.1.1.15  root      148: }
1.1.1.14  root      149: 
1.1.1.15  root      150: // ROM 処理の初期化。
1.1.1.16  root      151: void
1.1.1.15  root      152: LunaPROMEmuDevice::ROM_Init()
                    153: {
1.1       root      154:        // 初期パレット
1.1.1.15  root      155:        InitPalette();
1.1       root      156: 
                    157:        // SCSI
                    158:        // BDID の書き込みによってホストデバイスがバスにアタッチされる構造なので。
1.1.1.16  root      159:        spc->WritePort(SPC::BDID, 7);
                    160: 
                    161:        // LANCE。
                    162:        lance->WritePort(0, 0x00);      // RAP=CSR0
                    163:        lance->WritePort(1, AM7990::CSR0_STOP);
1.1       root      164: 
1.1.1.7   root      165:        // キーボード(chB)を初期化
1.1.1.16  root      166:        sio->WritePort(3, 0x01);        // CR1
                    167:        sio->WritePort(3, 0x10);        //    RX Int(all char)
                    168:        sio->WritePort(3, 0x04);        // CR4
                    169:        sio->WritePort(3, 0x44);        //    Stop 1bit
                    170:        sio->WritePort(3, 0x03);        // CR3
                    171:        sio->WritePort(3, 0xc1);        //    RX Enable, 8bit
                    172:        sio->WritePort(3, 0x05);        // CR5
                    173:        sio->WritePort(3, 0x68);        //    TX Enable, 8bit
1.1.1.12  root      174: 
                    175:        // LED を(明示的に)オフ、マウスサンプリングをオフ
1.1.1.16  root      176:        sio->WritePort(2, 0x00);
                    177:        sio->WritePort(2, 0x01);
                    178:        sio->WritePort(2, 0x20);
1.1.1.14  root      179: 
                    180:        // 電源オフをキャンセル。
                    181:        // 実 PROM では、リセット後に PIO のモードセットを行っている。
                    182:        // モードセットを行うと PortC のビットが %0 になる = 電源オフなので、
                    183:        // 即座にこれをキャンセルしている。
                    184:        // ROMEmu ではモードセットを行っていないが、キャンセルだけ発行しておく。
1.1.1.15  root      185:        auto pio1 = GetPIO1Device();
1.1.1.16  root      186:        pio1->WritePort(3, 0x09);
1.1.1.15  root      187: 
                    188:        // 機種別の初期化
                    189:        ROM_InitMD();
                    190: 
                    191:        // スクリーンを初期化
                    192:        InitScreen();
                    193: }
                    194: 
                    195: // 起動時の実行ファイル読み込み処理を行う。
                    196: // 次段実行ファイルの読み込みに成功すれば execute を true にして、
                    197: // エントリポイントを返す。
                    198: // そうでなければ -1 を返す。
                    199: uint32
                    200: LunaPROMEmuDevice::ROM_Load()
                    201: {
                    202:        uint32 entry;
                    203: 
                    204:        entry = -1;
                    205:        execute = false;
                    206: 
                    207:        // 表示環境が整ったところで NVRAM を照合
                    208:        if (VerifyNVRAM()) {
                    209:                // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、
                    210:                // これを真似する。
                    211:                auto pio0 = GetPIO0Device();
                    212:                if (pio0->IsDIPSW11Up()) {
                    213:                        entry = LoadFile("");
1.1.1.16  root      214:                        if (entry != -1) {
                    215:                                execute = true;
                    216:                                return entry;
                    217:                        }
1.1.1.15  root      218:                }
                    219:        } else {
                    220:                // LUNA-88K の PROM 1.20 は初期化するかどうか確認してくるけど、
                    221:                // とりあえず。
                    222:                InitNVRAM();
                    223:                errmsg = "NVRAM Initialized.";
                    224:                // NVRAM をクリアしたら DIPSW によらずプロンプトに降りる
                    225:        }
                    226: 
1.1.1.16  root      227:        PrintTitle();
                    228:        if (errmsg.empty() == false) {
                    229:                Print("** %s\n\n", errmsg.c_str());
1.1.1.15  root      230:        }
1.1.1.16  root      231:        ClearPrompt();
1.1.1.15  root      232: 
                    233:        return entry;
                    234: }
                    235: 
                    236: // 実行ファイルに処理を移すならそのエントリポイントを返す。
                    237: // そうでなければ -1 を返す。
                    238: uint32
                    239: LunaPROMEmuDevice::ROM_Entry()
                    240: {
                    241:        if (execute == false) {
                    242:                return -1;
                    243:        }
                    244:        return entrypoint;
                    245: }
                    246: 
                    247: // パレットを初期化
                    248: void
                    249: LunaPROMEmuDevice::InitPalette()
                    250: {
                    251:        // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。
                    252:        uint8 val = 0xff;
1.1.1.16  root      253:        bt45x->WritePort(0, 0); // select palette
1.1.1.15  root      254:        for (int i = 0; i < 16; i++) {
1.1.1.16  root      255:                bt45x->WritePort(1, val);       // R
                    256:                bt45x->WritePort(1, val);       // G
                    257:                bt45x->WritePort(1, val);       // B
1.1.1.15  root      258:                val ^= 0xff;
                    259:        }
1.1.1.7   root      260: }
1.1.1.2   root      261: 
1.1.1.7   root      262: // スクリーンを初期化
                    263: void
1.1.1.13  root      264: LunaPROMEmuDevice::InitScreen()
1.1.1.7   root      265: {
1.1.1.14  root      266:        lunafb->EmuInitScreen();
1.1.1.13  root      267: 
                    268:        screen_w = 80;
                    269:        screen_h = 32;
                    270:        cursor_x = 0;
                    271:        cursor_y = 0;
1.1.1.15  root      272:        cursor_on = true;
1.1.1.13  root      273: 
                    274:        // 表示範囲はざっくりセンタリングする
                    275:        origin_px = (1280 - screen_w * 12) / 2;
                    276:        origin_py = (1024 - screen_h * 24) / 2;
                    277:        // 横は 48ドット境界から始めておく。
                    278:        // こうすると1(,2)文字目の24ビットが必ずワード境界から始まるため。
                    279:        // 今となっては任意の場所から文字が描画できるようになったので揃える
                    280:        // 必要はなくなったが、依然このほうがアクセス効率はいいので。
                    281:        origin_px = (origin_px / 48) * 48;
                    282: 
1.1.1.15  root      283:        cursor_on = true;
                    284: 
1.1.1.2   root      285:        inputbuf.clear();
                    286:        inputpos = 0;
                    287:        is_shift = false;
1.1.1.3   root      288:        mousecnt = 0;
1.1.1.13  root      289: }
1.1       root      290: 
1.1.1.13  root      291: // タイトルを出力
                    292: void
1.1.1.15  root      293: LunaPROMEmuDevice::PrintTitle()
1.1.1.13  root      294: {
1.1.1.16  root      295:        Print("NONO %u.%u.%u Emulated ROM Monitor for %s\n\n",
1.1.1.7   root      296:                NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, machine_name);
1.1.1.13  root      297: }
                    298: 
                    299: // 1文字出力
                    300: void
                    301: LunaPROMEmuDevice::Putc(uint ch)
                    302: {
                    303:        uint px = origin_px + cursor_x * 12;
                    304:        uint py = origin_py + cursor_y * 24;
                    305: 
1.1.1.15  root      306:        if (cursor_on) {
                    307:                // カーソル位置の反転を元に戻す
                    308:                lunafb->EmuPutc(px, py, ' ', ROP::INV2);
                    309:        }
                    310: 
                    311:        // いくつかの制御コードを勝手に使う。
                    312:        switch (ch) {
                    313:         case 0x0f:     // SI
                    314:                bold = true;
                    315:                break;
                    316:         case 0x0e:     // SO
                    317:                bold = false;
                    318:                break;
                    319: 
                    320:         case 0x10:
                    321:         case 0x11:
                    322:         case 0x12:
                    323:         case 0x13:
                    324:                // カラーコード変更
                    325:                lunafb->SetBMSEL(ch - 0x10);
                    326:                break;
                    327: 
                    328:         case CR:
                    329:                break;
1.1.1.13  root      330: 
1.1.1.15  root      331:         case LF:
                    332:         put_LF:
1.1.1.13  root      333:                cursor_x = 0;
                    334:                if (cursor_y < screen_h - 1) {
                    335:                        cursor_y++;
                    336:                } else {
                    337:                        // 上スクロールして..
1.1.1.14  root      338:                        lunafb->EmuScrollY(origin_py, origin_py + 24, (screen_h - 1) * 24);
1.1.1.13  root      339:                        // 最終行を消す
1.1.1.14  root      340:                        lunafb->EmuFill(0, py, 1280, 24, 0);
1.1.1.13  root      341:                }
1.1.1.15  root      342:                break;
                    343: 
                    344:         case LEFT:
1.1.1.13  root      345:                if (cursor_x > 0) {
                    346:                        cursor_x--;
                    347:                } else {
                    348:                        cursor_y--;
                    349:                        cursor_x = screen_w - 1;
                    350:                }
1.1.1.15  root      351:                break;
                    352: 
                    353:         case RIGHT:
1.1.1.13  root      354:                if (cursor_x < screen_w - 1) {
                    355:                        cursor_x++;
                    356:                } else {
                    357:                        cursor_y++;
                    358:                        cursor_x = 0;
                    359:                }
1.1.1.15  root      360:                break;
                    361: 
                    362:         default:
                    363:                if (ch < 0x80) {
1.1.1.14  root      364:                        lunafb->EmuPutc(px, py, ch);
1.1.1.15  root      365:                        if (bold) {
                    366:                                for (int i = 1; i < 2; i++) {
                    367:                                        lunafb->EmuPutc(px + i, py, ch, ROP::OR1);
                    368:                                }
                    369:                        }
1.1.1.13  root      370:                } else {
1.1.1.15  root      371:                        lunafb->EmuPutc(px, py, ' ');
                    372:                        lunafb->EmuPutc(px, py + 10, ch);
                    373:                        if (bold) {
                    374:                                for (int i = 1; i < 2; i++) {
                    375:                                        lunafb->EmuPutc(px + i, py + 10, ch, ROP::OR1);
                    376:                                }
                    377:                        }
                    378:                }
                    379:                cursor_x++;
                    380:                if (cursor_x >= screen_w) {
1.1.1.13  root      381:                        goto put_LF;
                    382:                }
1.1.1.15  root      383:                break;
1.1.1.13  root      384:        }
                    385: 
1.1.1.15  root      386:        if (cursor_on) {
                    387:                // カーソル位置を再計算して描画 (文字を反転)
                    388:                px = origin_px + cursor_x * 12;
                    389:                py = origin_py + cursor_y * 24;
                    390:                lunafb->EmuPutc(px, py, ' ', ROP::INV2);
                    391:        }
1.1.1.13  root      392: }
                    393: 
                    394: // 文字列 s を出力
                    395: void
                    396: LunaPROMEmuDevice::Print(const std::string& s)
                    397: {
                    398:        for (auto *p = s.c_str(); *p; p++) {
                    399:                Putc(*p);
                    400:        }
                    401: }
                    402: 
                    403: // 文字列 fmt... を出力
                    404: void
                    405: LunaPROMEmuDevice::Print(const char *fmt, ...)
                    406: {
                    407:        char buf[1024];
                    408:        va_list ap;
                    409: 
                    410:        va_start(ap, fmt);
                    411:        vsnprintf(buf, sizeof(buf), fmt, ap);
                    412:        va_end(ap);
                    413: 
                    414:        for (char *p = buf; *p; p++) {
                    415:                Putc(*p);
                    416:        }
1.1       root      417: }
                    418: 
1.1.1.7   root      419: // ROM 処理のクローズ
                    420: void
1.1.1.2   root      421: LunaPROMEmuDevice::ROM_Close()
1.1       root      422: {
1.1.1.11  root      423:        // SIO をリセットしておく。
                    424:        // SIO のバッファにデータが残っていると、NetBSD のブートローダが
                    425:        // 起動してこないようだ。リセットして RXEN を落としておけば大丈夫ぽい。
1.1.1.14  root      426:        sio->ResetHard(false);
1.1.1.15  root      427: 
                    428:        // 実行ファイルにジャンプ後、NMI でプロンプトにもう一度戻ってこれるので
                    429:        // その時のためにエントリポイント等も初期化しておく。
                    430:        entrypoint = -1;
                    431:        execute = false;
1.1       root      432: }
                    433: 
1.1.1.2   root      434: // ROM プロンプトのキー入力。
1.1.1.7   root      435: // ゲストコードの割り込みハンドラから呼ばれて、キー入力で行を構成し、
                    436: // あるいは行が完成すればコマンドを実行する。
                    437: // 実行結果により画面を更新したりメンバ変数を更新する。
                    438: void
1.1.1.2   root      439: LunaPROMEmuDevice::ROM_Keyin()
1.1       root      440: {
1.1.1.14  root      441:        int asciicode = Getc();
                    442: 
1.1.1.15  root      443:        if (cursor_on && asciicode != -1) {
1.1.1.14  root      444:                ProcessChar(asciicode);
                    445:        }
                    446: }
                    447: 
                    448: // キー入力。
                    449: // 押されているキーの ASCII コードを返す。
                    450: // キー入力が無いときは -1 を返す。
                    451: int
                    452: LunaPROMEmuDevice::Getc()
                    453: {
                    454:        // コントロールレジスタポインタを確実に 0 にするため読み捨てる
1.1.1.16  root      455:        sio->ReadPort(3);
1.1.1.14  root      456: 
1.1.1.16  root      457:        uint8 sr0 = sio->ReadPort(3);
1.1.1.14  root      458:        if ((sr0 & MPSCC::SR0_RXAVAIL) == 0) {
                    459:                return -1;
                    460:        }
                    461: 
1.1.1.16  root      462:        uint32 lunakey = sio->ReadPort(2);
1.1       root      463: 
1.1.1.3   root      464:        // マウス入力の 2, 3バイト目は無視
                    465:        if (mousecnt > 0) {
                    466:                mousecnt--;
1.1.1.14  root      467:                return -1;
1.1.1.3   root      468:        }
                    469: 
1.1.1.2   root      470:        // SHIFT キーだけ状態を持つので先に処理
                    471:        if (lunakey == 0x0c || lunakey == 0x0d) {       // 左右SHIFT押下
                    472:                is_shift = true;
1.1.1.14  root      473:                return -1;
1.1.1.2   root      474:        }
                    475:        if (lunakey == 0x8c || lunakey == 0x8d) {       // 左右SHIFT開放
1.1       root      476:                is_shift = false;
1.1.1.14  root      477:                return -1;
1.1.1.2   root      478:        }
1.1.1.3   root      479:        // マウスデータの1バイト目なら、後続2バイトをスキップ
                    480:        if ((lunakey & 0xf8) == 0x80) {
                    481:                mousecnt = 2;
1.1.1.14  root      482:                return -1;
1.1.1.3   root      483:        }
                    484:        // キー開放は無視してよい
1.1.1.2   root      485:        if ((lunakey & 0x80)) {
1.1.1.14  root      486:                return -1;
1.1.1.2   root      487:        }
1.1       root      488: 
1.1.1.9   root      489:        // キーコードから文字を取得
1.1.1.14  root      490:        int asciicode;
1.1.1.9   root      491:        if (is_shift) {
                    492:                asciicode = lunakey2shifttable[lunakey];
                    493:        } else {
                    494:                asciicode = lunakey2asciitable[lunakey];
                    495:        }
1.1.1.14  root      496:        if (asciicode == 0) {
                    497:                return -1;
1.1.1.9   root      498:        }
1.1.1.14  root      499: 
                    500:        return asciicode;
1.1.1.9   root      501: }
                    502: 
                    503: // キー入力ハンドラ (キー入力割り込みによって呼ばれる)。
                    504: // 引数 asciicode は概ね ASCII コード (ただし 0x1c..0x1f が上下左右)。
                    505: void
1.1.1.14  root      506: LunaPROMEmuDevice::ProcessChar(char asciicode)
1.1.1.9   root      507: {
1.1.1.14  root      508:        // LUNA-I の場合、
1.1.1.9   root      509:        // 実機 PROM にはカーソル左右移動の機能はなく、カーソルは常に行末にいる。
                    510:        // そのためかどうか Delete も BackSpace と同じく1文字前を消す動作をして
                    511:        // いる。カーソル位置に文字はないので、Delete をそうするのはまあ分からん
                    512:        // でもない。
                    513:        // 一方、エミュレーション ROM では、カーソルの左右移動をサポートしてみた
                    514:        // ため Delete を「カーソル位置の文字を消す」にすることは出来るが、それは
                    515:        // それで実機と乖離が広がるので、どうしたもんか。
                    516: 
                    517:        switch (asciicode) {
                    518:         case BS:
                    519:                if (inputbuf.empty() == false && inputpos != 0) {
                    520:                        inputbuf.erase(--inputpos, 1);
1.1.1.13  root      521:                        Putc(LEFT);
                    522:                        for (int i = inputpos; i < inputbuf.size(); i++) {
                    523:                                Putc(inputbuf[i]);
                    524:                        }
                    525:                        Putc(' ');
                    526:                        for (int i = 0; i < 1 + inputbuf.size() - inputpos; i++) {
                    527:                                Putc(LEFT);
                    528:                        }
1.1       root      529:                }
1.1.1.2   root      530:                break;
1.1.1.9   root      531: 
                    532:         case LF:
1.1.1.2   root      533:                // 改行
1.1.1.13  root      534:                Putc(asciicode);
                    535:                prompt_y = cursor_y;
1.1.1.9   root      536:                // コマンド実行
1.1.1.7   root      537:                Command();
1.1.1.9   root      538:                // プロンプトを更新
                    539:                ClearPrompt();
1.1.1.2   root      540:                break;
1.1.1.9   root      541: 
                    542:         case LEFT:
1.1.1.2   root      543:                if (inputpos > 0) {
                    544:                        inputpos--;
1.1.1.13  root      545:                        Putc(LEFT);
1.1       root      546:                }
1.1.1.2   root      547:                break;
1.1.1.9   root      548:         case RIGHT:
1.1.1.2   root      549:                if (inputpos < inputbuf.length()) {
1.1       root      550:                        inputpos++;
1.1.1.13  root      551:                        Putc(RIGHT);
1.1       root      552:                }
                    553:                break;
1.1.1.9   root      554: 
                    555:         case UP:
                    556:         case DOWN:
                    557:         case 0:        // キー割り当てなし、これは来ないはずだが一応
                    558:                return;
                    559: 
                    560:         default:       // 通常文字のはず
1.1.1.2   root      561:                inputbuf.insert(inputbuf.begin() + inputpos, asciicode);
1.1.1.13  root      562:                for (int i = inputpos; i < inputbuf.size(); i++) {
                    563:                        Putc(inputbuf[i]);
                    564:                }
                    565:                for (int i = 0; i < inputbuf.size() - inputpos - 1; i++) {
                    566:                        Putc(LEFT);
                    567:                }
1.1.1.2   root      568:                inputpos++;
                    569:                break;
1.1       root      570:        }
1.1.1.2   root      571: }
1.1       root      572: 
1.1.1.9   root      573: // 入力バッファを初期化する。
                    574: void
                    575: LunaPROMEmuDevice::ClearPrompt()
                    576: {
1.1.1.13  root      577:        prompt_y = cursor_y;
1.1.1.9   root      578:        // 入力行をクリア
                    579:        inputbuf.clear();
                    580:        inputpos = 0;
                    581: 
1.1.1.13  root      582:        Print(prompt);
1.1.1.9   root      583: }
                    584: 
                    585: // NVRAM のチェックサムを返す
                    586: uint8
                    587: LunaPROMEmuDevice::CalcNVRAMCsum() const
                    588: {
                    589:        uint8 eor = 0;
                    590:        for (uint32 addr = 0x20; addr < 0x560; addr++) {
1.1.1.16  root      591:                eor ^= nvram->PeekPort(addr);
1.1.1.9   root      592:        }
                    593:        return eor;
                    594: }
                    595: 
                    596: // NVRAM のチェックサムを計算して書き込む
                    597: void
                    598: LunaPROMEmuDevice::WriteNVRAMCsum()
                    599: {
                    600:        uint8 eor = CalcNVRAMCsum();
                    601: 
1.1.1.16  root      602:        nvram->WritePort(0x001c, eor);
                    603:        nvram->WritePort(0x001d, eor);
                    604:        nvram->WritePort(0x001e, eor);
1.1.1.9   root      605: }
                    606: 
                    607: // NVRAM のマジックとチェックサムを照合する
                    608: bool
                    609: LunaPROMEmuDevice::VerifyNVRAM() const
                    610: {
                    611:        if (nvram->PeekString(0x0004) != "<nv>") {
                    612:                return false;
                    613:        }
                    614: 
                    615:        uint8 eor = CalcNVRAMCsum();
                    616:        for (uint32 addr = 0x1c; addr < 0x1f; addr++) {
1.1.1.16  root      617:                if (nvram->PeekPort(addr) != eor) {
1.1.1.9   root      618:                        return false;
                    619:                }
                    620:        }
                    621:        return true;
1.1       root      622: }
                    623: 
1.1.1.15  root      624: static const uint8 __unused test0[] = {
                    625:        0x12, 0x0f, 0x4e, 0x4f, 0x4e, 0x4f, 0x0e, 0x1e, 0x13, 0x00,
                    626: };
                    627: static const uint8 __unused test1[] = {
                    628:        0xcd, 0xd5, 0xcc, 0xd4, 0xc9, 0xad, 0xd2, 0xc9, 0xd3, 0xc3,
                    629:        0x20, 0xd7, 0xcf, 0xd2, 0xcb, 0xd3, 0xd4, 0xc1, 0xd4, 0xc9,
                    630:        0xcf, 0xce, 0x20, 0x11, 0x0f, 0x4c, 0x55, 0x4e, 0x41, 0x2d,
                    631:        0x38, 0x38, 0x4b, 0x00, 0xaa, 0x12, 0x43, 0x58, 0xc2, 0x00,
                    632: };
                    633: static const uint8 __unused test2[] = {
                    634:        0xc8, 0xcf, 0xcc, 0xcf, 0xce, 0xc9, 0xc3, 0x20, 0xd7, 0xcf,
                    635:        0xd2, 0xcb, 0xd3, 0xd4, 0xc1, 0xd4, 0xc9, 0xcf, 0xce, 0x20,
                    636:        0x11, 0x0f, 0x4c, 0x55, 0x4e, 0x41, 0x00, 0x21, 0xd8, 0x67,
                    637: };
                    638: static const uint8 __unused test3[] = {
                    639:        0x0e, 0x1e, 0x13, 0xd3, 0xc5, 0xd2, 0xc9, 0xc5, 0xd3, 0x0a,
                    640:        0x00, 0x0f, 0xd0, 0x4f, 0x7e, 0x40, 0x41, 0xcc, 0xdf, 0x09,
                    641: };
                    642: 
1.1.1.10  root      643: // -X オプションで指定されたホストファイルをロードする。
1.1       root      644: // ロードできればエントリポイントを返す。
1.1.1.15  root      645: // 失敗ならエラーメッセージを errmsg にセットして (uint32)-1 を返す。
1.1.1.10  root      646: // exec_file が指定されている時に呼ぶこと。
1.1       root      647: uint32
                    648: LunaPROMEmuDevice::LoadHostFile()
                    649: {
1.1.1.10  root      650:        assert(gMainApp.exec_file);
1.1       root      651: 
1.1.1.14  root      652:        LoadInfo info(gMainApp.exec_file);
1.1.1.15  root      653:        if (mainram->LoadExec(&info)) {
1.1.1.14  root      654:                return info.entry;
1.1       root      655:        } else {
1.1.1.15  root      656:                errmsg = "Couldn't load specified host program.";
                    657:                return -1;
1.1       root      658:        }
                    659: }
                    660: 
1.1.1.7   root      661: // bootinfo に従ってゲストから起動先をロードする。
1.1.1.15  root      662: // ロードできればエントリポイントを返す。
                    663: // 失敗ならエラーメッセージを errmsg にセットして (uint32)-1 を返す。
1.1       root      664: uint32
1.1.1.7   root      665: LunaPROMEmuDevice::LoadGuestFile(const bootinfo_t& bootinfo)
1.1       root      666: {
1.1.1.7   root      667:        const int& dkpart = bootinfo.dkpart;
                    668:        const int& dkunit = bootinfo.dkunit;
                    669:        const std::string& dkfile = bootinfo.dkfile;
1.1       root      670: 
                    671:        // ユニット (今は SCSI ID=6 決め打ち)
1.1.1.16  root      672:        uint id = 6;
                    673:        SCSITarget *target = spc->GetSCSI()->GetTarget(id);
1.1       root      674:        if (target == NULL) {
                    675:                errmsg = "No bootable disks";
                    676:                putmsg(0, "%s", errmsg.c_str());
1.1.1.14  root      677:                return -1;
1.1       root      678:        }
1.1.1.3   root      679:        if (target->GetDevType() != SCSI::DevType::HD) {
1.1       root      680:                errmsg = "No bootable disks";
                    681:                putmsg(0, "%s", errmsg.c_str());
1.1.1.14  root      682:                return -1;
1.1       root      683:        }
                    684: 
1.1.1.10  root      685:        SCSIDisk *hd = dynamic_cast<SCSIDisk*>(target);
1.1.1.16  root      686:        putmsg(2, "%s SCSIHD[%u] found", __func__, id);
1.1       root      687: 
                    688:        // +0 セクタ目(512byte)に Sun disklabel
                    689:        scd_dk_label dk;
1.1.1.10  root      690:        if (hd->Peek(&dk, 0, sizeof(dk)) == false) {
1.1.1.16  root      691:                putmsg(0, "SCSIHD[%u] ReadSector failed", id);
                    692:                errmsg = string_format("dk%u Read disklabel failed.", dkunit);
1.1.1.14  root      693:                return -1;
1.1       root      694:        }
                    695: 
                    696:        // +$1fc の MAGIC をチェック
                    697:        uint32 magic = be16toh(dk.magic);
                    698:        if (magic != scd_dk_label::DKL_MAGIC) {
                    699:                putmsg(0, "SCSIHD[%d] Bad magic 0x%04x (!= 0x%x)",
                    700:                        id, magic, scd_dk_label::DKL_MAGIC);
                    701:                errmsg = string_format("dk%d Bad disklabel magic.", dkunit);
1.1.1.14  root      702:                return -1;
1.1       root      703:        }
                    704: 
                    705:        // チェックサム照合は手抜きで省略
                    706: 
                    707:        // 指定パーティションの開始位置とサイズ
                    708:        if (loglevel >= 2) {
                    709:                // デバッグ用に全部表示
                    710:                for (int i = 0; i < 8; i++) {
1.1.1.7   root      711:                        putmsgn("%s partition %c: { start=%8u size=%8u }", __func__,
1.1       root      712:                                'a' + i,
                    713:                                be32toh(dk.map[i].blkno),
                    714:                                be32toh(dk.map[i].nblk));
                    715:                }
                    716:        }
                    717:        uint32 part_start = be32toh(dk.map[dkpart].blkno);
                    718:        uint32 part_size  = be32toh(dk.map[dkpart].nblk);
                    719:        putmsg(1, "%s partition=%c, start=%u size=%u", __func__,
                    720:                dkpart + 'a', part_start, part_size);
                    721: 
                    722:        // ファイルシステムをオープン (マウントっぽいイメージ)
                    723:        Filesys fsys(this);
1.1.1.7   root      724:        if (fsys.Mount(hd, part_start, part_size) == false) {
1.1.1.16  root      725:                errmsg = string_format("dk%u,%c Open ffs failed: %s",
1.1.1.7   root      726:                        dkunit, dkpart + 'a', fsys.errstr.c_str());
                    727:                putmsg(0, "%s: %s", __func__, errmsg.c_str());
1.1.1.14  root      728:                return -1;
1.1       root      729:        }
                    730: 
1.1.1.7   root      731:        // ファイルを探してオープンする
                    732:        inodefile f(this);
                    733:        if (fsys.OpenFile(f, dkfile) == false) {
1.1.1.16  root      734:                errmsg = string_format("dk%u,%c,%s open failed: %s",
1.1.1.7   root      735:                        dkunit, dkpart + 'a', dkfile.c_str(), fsys.errstr.c_str());
                    736:                putmsg(0, "%s: %s", __func__, errmsg.c_str());
1.1.1.14  root      737:                return -1;
1.1       root      738:        }
1.1.1.7   root      739: 
1.1       root      740:        // ファイル本体を読み込み
1.1.1.7   root      741:        fsys.ReadData(f);
1.1       root      742: 
                    743:        // ロード
1.1.1.16  root      744:        std::string name = string_format("SCSIHD %u,%c:%s",
1.1.1.7   root      745:                id, dkpart + 'a', dkfile.c_str());
1.1.1.14  root      746:        LoadInfo info(name.c_str(), f.data.data(), f.data.size());
1.1.1.15  root      747:        if (mainram->LoadExec(&info) == false) {
1.1.1.16  root      748:                errmsg = string_format("dk%u,%c,%s load failed",
1.1.1.14  root      749:                        dkunit, dkpart + 'a', dkfile.c_str());
                    750:                putmsg(0, "%s: %s", __func__, errmsg.c_str());
                    751:                return -1;
                    752:        }
                    753: 
                    754:        if (info.entry == -1) {
1.1.1.16  root      755:                errmsg = string_format("dk%u,%c,%s not executable",
1.1.1.7   root      756:                        dkunit, dkpart + 'a', dkfile.c_str());
1.1.1.14  root      757:                putmsg(0, "%s: %s", __func__, errmsg.c_str());
                    758:                return -1;
1.1       root      759:        }
                    760: 
1.1.1.14  root      761:        return info.entry;
1.1       root      762: }
                    763: 
1.1.1.15  root      764: void
                    765: LunaPROMEmuDevice::ROM_AP1()
                    766: {
                    767:        char buf[100];
                    768:        int n;
                    769: 
                    770:        cursor_on = false;
                    771: 
                    772:        static uint8 ap1pal[] = {
                    773:                0x00, 0x00, 0x00,
                    774:                0x00, 0xf8, 0xf8,
                    775:                0xf8, 0xf8, 0x00,
                    776:                0xf8, 0xf8, 0xf8,
                    777:        };
1.1.1.16  root      778:        bt45x->WritePort(0, 0);
1.1.1.15  root      779:        for (int i = 0; i < countof(ap1pal); i++) {
1.1.1.16  root      780:                bt45x->WritePort(1, ap1pal[i]);
1.1.1.15  root      781:        }
                    782: 
                    783:        Print(std::string((const char *)test0));
                    784:        if (gMainApp.IsLUNA88K()) {
                    785:                Print(std::string((const char *)test1));
                    786:        } else {
                    787:                Print(std::string((const char *)test2));
                    788:        }
                    789:        Print(std::string((const char *)test3));
                    790: 
                    791:        n = strlcpy(buf, (const char *)&Builtin::IPLROM30[0x111e3], sizeof(buf));
                    792:        snprintf(buf + n, sizeof(buf) - n, "%d.%d.%d %s",
                    793:                NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, NONO_DATE);
                    794:        for (int i = 0; buf[i]; i++) {
                    795:                if (buf[i] == '/')
                    796:                        buf[i] = '.';
                    797:        }
                    798:        Print("%s\n", buf);
                    799: 
                    800:        memcpy(buf, &Builtin::IPLROM30[0x111f5], 0x28);
                    801:        memcpy(buf + 0x1e, mpu->GetMPUName(), 7);
                    802:        n = 0x27;
                    803:        n += snprintf(buf + n, sizeof(buf) - n, "%4.1f",
                    804:                (double)mpu->GetClockSpeed() / 1000);
                    805:        strlcpy(buf + n, (const char *)&Builtin::IPLROM30[0x1121f],
                    806:                sizeof(buf) - n);
                    807:        Print(std::string(buf));
                    808: 
                    809:        strlcpy(buf, (const char *)&Builtin::IPLROM30[0x11226], sizeof(buf));
                    810:        if (gMainApp.Has(VMCap::M88K)) {
                    811:                memcpy(buf + 0x1e, mpu->GetMPUName(), 7);
                    812:                memcpy(buf + 0x25, &Builtin::IPLROM30[0x11251], 3);
                    813:        }
                    814:        Print(std::string(buf));
                    815: 
                    816:        strlcpy(buf, (const char *)&Builtin::IPLROM30[0x11254], sizeof(buf));
                    817:        buf[0x0c] = 'e';
                    818:        if (gMainApp.Has(VMCap::M88K)) {
                    819:                memcpy(buf + 0x1e, mpu->GetMPUName(), 7);
                    820:                memcpy(buf + 0x25, &Builtin::IPLROM30[0x1127d], 3);
                    821:                buf[0x22] = 0x32;
                    822:        }
                    823:        Print(std::string(buf));
                    824: 
                    825:        strlcpy(buf, (const char *)&Builtin::IPLROM30[0x11280], sizeof(buf));
                    826:        n = 0x1e;
                    827:        n += snprintf(buf + n, sizeof(buf) - n, "%d", mainram->GetSizeMB());
                    828:        strlcpy(buf + n, (const char *)&Builtin::IPLROM30[0x1129f],
                    829:                sizeof(buf) - n);
                    830:        Print(std::string(buf));
                    831: }
                    832: 
                    833: void
                    834: LunaPROMEmuDevice::ROM_AP2()
                    835: {
                    836:        InitPalette();
                    837:        InitScreen();
                    838: }
                    839: 
1.1.1.7   root      840: // キーコードから文字への変換
                    841: /*static*/ const uint8
                    842: LunaPROMEmuDevice::lunakey2asciitable[] = {
1.1.1.9   root      843:         0,   0,   0,   0,   0,   0,   0,   0,
                    844:         0,   0,   0,   0,   0,   0,   0,   0,
                    845:         0,  BS,  LF,   0, ' ',   0,   0,   0,
                    846:         0,   0,   0,   0,  UP,LEFT,RIGHT,DOWN,
1.1.1.7   root      847:         0,   0,  '1', '2', '3', '4', '5', '6',
                    848:        '7', '8', '9', '0', '-', '^', '\\', 0,
                    849:         0,   0,  'q', 'w', 'e', 'r', 't', 'y',
                    850:        'u', 'i', 'o', 'p', '@', '[',  0,   0,
                    851:         0,   0,  'a', 's', 'd', 'f', 'g', 'h',
                    852:        'j', 'k', 'l', ';', ':', ']',  0,   0,
                    853:         0,   0,  'z', 'x', 'c', 'v', 'b', 'n',
                    854:        'm', ',', '.', '/',  0,   0,   0,   0,
1.1.1.13  root      855:         0,  '+', '-', '7', '8', '9', '4', '5',
                    856:        '6', '1', '2', '3', '0', '.', LF,   0,
                    857:         0,   0,   0,   0,   0,   0,   0,   0,
                    858:         0,   0,   0,   0,  '*', '/', '=', ',',
1.1.1.7   root      859: };
                    860: /*static*/ const uint8
                    861: LunaPROMEmuDevice::lunakey2shifttable[] = {
1.1.1.9   root      862:         0,   0,   0,   0,   0,   0,   0,   0,
                    863:         0,   0,   0,   0,   0,   0,   0,   0,
                    864:         0,  BS,  LF,   0, ' ',   0,   0,   0,
                    865:         0,   0,   0,   0,  UP,LEFT,RIGHT,DOWN,
                    866:         0,   0,  '!', '\"','#', '$', '%', '&',
                    867:        '\'','(', ')', ' ', '=', '~', '|',  0,          // XXX SHIFT+'0'は?
1.1.1.7   root      868:         0,   0,  'Q', 'W', 'E', 'R', 'T', 'Y',
                    869:        'U', 'I', 'O', 'P', '`', '{',  0,   0,
                    870:         0,   0,  'A', 'S', 'D', 'F', 'G', 'H',
                    871:        'J', 'K', 'L', '+', '*', '}',  0,   0,
                    872:         0,   0,  'Z', 'X', 'C', 'V', 'B', 'N',
                    873:        'M', '<', '>', '?', '_',  0,   0,   0,
1.1.1.13  root      874:         0,  '+', '-', '7', '8', '9', '4', '5',
                    875:        '6', '1', '2', '3', '0', '.', LF,   0,
                    876:         0,   0,   0,   0,   0,   0,   0,   0,
                    877:         0,   0,   0,   0,  '*', '/', '=', ',',
1.1.1.7   root      878: };

unix.superglobalmegacorp.com

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