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

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

unix.superglobalmegacorp.com

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