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

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

unix.superglobalmegacorp.com

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