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

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

unix.superglobalmegacorp.com

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