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

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.7 ! root        7: // LUNA シリーズの ROM エミュレーション共通部分
1.1.1.2   root        8: 
                      9: //             IODevice
                     10: //                |
1.1.1.7 ! root       11: //     +----------+---------------------+
        !            12: //     v                                v
        !            13: // ROMDevice                 LunaPROMEmuDeivce (ROM エミュレーションの共通部分)
        !            14: //     |                                |
        !            15: //     |                   +------------+----------------+
        !            16: //     v                   v                             v
        !            17: // PROMDevice      Luna1PROMEmuDevice          Luna88kPROMEmuDevice
        !            18: // (実ROM)         (LUNA-I エミュレーション)   (LUNA88K エミュレーション)
1.1.1.2   root       19: 
                     20: #include "romemu_luna.h"
1.1       root       21: #include "bitmap.h"
                     22: #include "bt454.h"
                     23: #include "mainapp.h"
                     24: #include "mk48t02.h"
                     25: #include "ram.h"
                     26: #include "sio.h"
                     27: #include "spc.h"
1.1.1.7 ! root       28: #include "ufs.h"
1.1       root       29: 
                     30: // コンストラクタ
                     31: LunaPROMEmuDevice::LunaPROMEmuDevice()
                     32: {
1.1.1.6   root       33:        logname = "prom";
                     34:        devname = "PROM";
1.1       root       35: }
                     36: 
                     37: // デストラクタ
                     38: LunaPROMEmuDevice::~LunaPROMEmuDevice()
                     39: {
                     40: }
                     41: 
                     42: bool
                     43: LunaPROMEmuDevice::Init()
                     44: {
                     45:        // 都度都度 dynamic_cast は面倒なので、ここで一度代入しとく
                     46:        nvram = dynamic_cast<MK48T02Device*>(gRTC.get());
                     47: 
                     48:        return true;
                     49: }
                     50: 
                     51: void
                     52: LunaPROMEmuDevice::ResetHard()
                     53: {
1.1.1.2   root       54:        is_closed = false;
1.1       root       55: }
                     56: 
                     57: // アドレスデコーダ
                     58: inline uint64
                     59: LunaPROMEmuDevice::Decoder(uint32 addr) const
                     60: {
1.1.1.2   root       61:        // 折り返しなし
1.1       root       62:        return addr - baseaddr;
                     63: }
                     64: 
                     65: uint64
1.1.1.2   root       66: LunaPROMEmuDevice::Read8(uint32 addr)
                     67: {
                     68:        uint64 offset = Decoder(addr);
                     69: 
                     70:        // 謎の IO 空間はロングワードアクセスのみ
                     71:        return romdata[offset & (devlen - 1)];
                     72: }
                     73: 
                     74: uint64
                     75: LunaPROMEmuDevice::Read16(uint32 addr)
                     76: {
                     77:        uint64 offset = Decoder(addr);
                     78: 
                     79:        // 謎の IO 空間はロングワードアクセスのみ
                     80:        return be16toh(*(uint16 *)&romdata[offset & (devlen - 1)]);
                     81: }
                     82: 
                     83: uint64
1.1       root       84: LunaPROMEmuDevice::Read32(uint32 addr)
                     85: {
                     86:        uint64 offset = Decoder(addr);
                     87: 
                     88:        // ロングワードアクセスでだけ謎の I/O 空間が見える
1.1.1.2   root       89:        if (!is_closed) {
1.1       root       90:                switch (offset) {
1.1.1.2   root       91:                 case ROMIO_INIT - baseaddr:
                     92:                        return ROM_Init();
1.1       root       93: 
1.1.1.2   root       94:                 case ROMIO_KEYIN - baseaddr:
1.1.1.7 ! root       95:                        ROM_Keyin();
        !            96:                        return 0;
1.1       root       97: 
1.1.1.2   root       98:                 case ROMIO_CLOSE - baseaddr:
1.1.1.7 ! root       99:                        ROM_Close();
        !           100:                        return 0;
1.1       root      101: 
1.1.1.6   root      102:                 case ROMIO_ENTRY - baseaddr:
1.1.1.7 ! root      103:                        return ROM_Entry();
1.1.1.6   root      104: 
1.1       root      105:                 default:
                    106:                        break;
                    107:                }
                    108:        }
1.1.1.2   root      109:        return be32toh(*(uint32 *)&romdata[offset & (devlen - 1)]);
                    110: }
                    111: 
                    112: uint64
                    113: LunaPROMEmuDevice::Write8(uint32 addr, uint32 data)
                    114: {
                    115:        return 0;
                    116: }
                    117: 
                    118: uint64
                    119: LunaPROMEmuDevice::Write16(uint32 addr, uint32 data)
                    120: {
                    121:        return 0;
                    122: }
                    123: 
                    124: uint64
                    125: LunaPROMEmuDevice::Write32(uint32 addr, uint32 data)
                    126: {
                    127:        return 0;
                    128: }
                    129: 
                    130: uint64
                    131: LunaPROMEmuDevice::Peek8(uint32 addr)
                    132: {
                    133:        uint64 offset = Decoder(addr);
                    134: 
                    135:        return romdata[offset & (devlen - 1)];
1.1       root      136: }
                    137: 
1.1.1.7 ! root      138: // デバイスの初期化の共通部分。(継承クラスの ROM_Init() から呼ぶ)
        !           139: void
        !           140: LunaPROMEmuDevice::InitDevice()
1.1       root      141: {
                    142:        // 初期パレット
1.1.1.4   root      143:        // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。
                    144:        uint8 val = 0xf0;
1.1.1.7 ! root      145:        gBT454->Write(0, 0);    // select palette
1.1.1.4   root      146:        for (int i = 0; i < 16; i++) {
1.1.1.7 ! root      147:                gBT454->Write(1, val);  // R
        !           148:                gBT454->Write(1, val);  // G
        !           149:                gBT454->Write(1, val);  // B
1.1.1.4   root      150:                val ^= 0xf0;
                    151:        }
1.1       root      152: 
                    153:        // SCSI
                    154:        // BDID の書き込みによってホストデバイスがバスにアタッチされる構造なので。
1.1.1.7 ! root      155:        gSPC->Write(SPC::BDID, 7);
1.1       root      156: 
1.1.1.7 ! root      157:        // キーボード(chB)を初期化
        !           158:        gSIO->Write(3, 0x01);           // CR1
        !           159:        gSIO->Write(3, 0x10);           //    RX Int(all char)
        !           160:        gSIO->Write(3, 0x03);           // CR3
        !           161:        gSIO->Write(3, 0xc1);           //    RX Enable, 8bit
        !           162:        gSIO->Write(3, 0x04);           // CR4
        !           163:        gSIO->Write(3, 0x44);           //    Stop 1bit
        !           164:        gSIO->Write(3, 0x05);           // CR5
        !           165:        gSIO->Write(3, 0x68);           //    TX Enable, 8bit
        !           166: }
1.1.1.2   root      167: 
1.1.1.7 ! root      168: // スクリーンを初期化
        !           169: void
        !           170: LunaPROMEmuDevice::InitScreen(const char *machine_name)
        !           171: {
1.1       root      172:        text.Init(80, 32);
                    173:        gBitmap->EmuConsoleOpen(&text);
1.1.1.2   root      174:        inputbuf.clear();
                    175:        inputpos = 0;
                    176:        is_shift = false;
1.1.1.3   root      177:        mousecnt = 0;
1.1       root      178: 
1.1.1.7 ! root      179:        text.Print(0, 0, "NONO %d.%d.%d Emulated ROM Monitor for %s",
        !           180:                NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, machine_name);
1.1       root      181:        text.Locate(0, 2);
                    182: }
                    183: 
1.1.1.7 ! root      184: // ROM 処理のクローズ
        !           185: void
1.1.1.2   root      186: LunaPROMEmuDevice::ROM_Close()
1.1       root      187: {
                    188:        // ここでバックドアに蓋をする
1.1.1.2   root      189:        is_closed = true;
1.1       root      190: 
1.1.1.7 ! root      191:        // SIO からキーの Break 入力を取り除いておく。
        !           192:        // コマンド入力によってここへ来る時は、キーの Make で呼ばれるため
        !           193:        // Break はまだ取り出されておらず SIO のバッファに残っている。
        !           194:        // コマンド入力によらずここに来た場合でも空読みして問題ないだろう。
        !           195:        (void)gSIO->Read(2);
        !           196: 
1.1       root      197:        // コンソールクローズ
                    198:        gBitmap->EmuConsoleClose();
                    199: }
                    200: 
1.1.1.2   root      201: // ROM プロンプトのキー入力。
1.1.1.7 ! root      202: // ゲストコードの割り込みハンドラから呼ばれて、キー入力で行を構成し、
        !           203: // あるいは行が完成すればコマンドを実行する。
        !           204: // 実行結果により画面を更新したりメンバ変数を更新する。
        !           205: void
1.1.1.2   root      206: LunaPROMEmuDevice::ROM_Keyin()
1.1       root      207: {
1.1.1.7 ! root      208:        uint32 lunakey = gSIO->Read(2);
1.1       root      209: 
1.1.1.3   root      210:        // マウス入力の 2, 3バイト目は無視
                    211:        if (mousecnt > 0) {
                    212:                mousecnt--;
1.1.1.7 ! root      213:                return;
1.1.1.3   root      214:        }
                    215: 
1.1.1.2   root      216:        // SHIFT キーだけ状態を持つので先に処理
                    217:        if (lunakey == 0x0c || lunakey == 0x0d) {       // 左右SHIFT押下
                    218:                is_shift = true;
1.1.1.7 ! root      219:                return;
1.1.1.2   root      220:        }
                    221:        if (lunakey == 0x8c || lunakey == 0x8d) {       // 左右SHIFT開放
1.1       root      222:                is_shift = false;
1.1.1.7 ! root      223:                return;
1.1.1.2   root      224:        }
1.1.1.3   root      225:        // マウスデータの1バイト目なら、後続2バイトをスキップ
                    226:        if ((lunakey & 0xf8) == 0x80) {
                    227:                mousecnt = 2;
1.1.1.7 ! root      228:                return;
1.1.1.3   root      229:        }
                    230:        // キー開放は無視してよい
1.1.1.2   root      231:        if ((lunakey & 0x80)) {
1.1.1.7 ! root      232:                return;
1.1.1.2   root      233:        }
1.1       root      234: 
1.1.1.2   root      235:        switch (lunakey) {
                    236:         case 0x11:             // BS
                    237:                if (inputpos > 0) {
                    238:                        inputbuf.erase(--inputpos);
1.1       root      239:                }
1.1.1.2   root      240:                break;
                    241:         case 0x12:             // Enter
                    242:         {
                    243:                // 現在位置のカーソルを消去
                    244:                uint16 *rawbuf = text.GetRawBuf();
                    245:                int curx = prompt.length() + inputpos;
                    246:                rawbuf[text.GetY() * text.GetCol() + curx] &= ~TA::On;
                    247:                // 改行
                    248:                text.Putc('\n');
                    249:                // コマンド処理。
1.1.1.7 ! root      250:                Command();
1.1.1.2   root      251:                inputbuf.clear();
                    252:                inputpos = 0;
                    253:                break;
                    254:         }
                    255:         case 0x1d:             // ←
                    256:                if (inputpos > 0) {
                    257:                        inputpos--;
1.1       root      258:                }
1.1.1.2   root      259:                break;
                    260:         case 0x1e:             // →
                    261:                if (inputpos < inputbuf.length()) {
1.1       root      262:                        inputpos++;
                    263:                }
                    264:                break;
1.1.1.2   root      265:         default:               // 通常文字
                    266:         {
                    267:                char asciicode;
                    268:                if (is_shift) {
                    269:                        asciicode = lunakey2shifttable[lunakey];
                    270:                } else {
                    271:                        asciicode = lunakey2asciitable[lunakey];
                    272:                }
                    273:                if (asciicode == 0) {
                    274:                        // 割り当てなし
1.1.1.7 ! root      275:                        return;
1.1.1.2   root      276:                }
                    277:                inputbuf.insert(inputbuf.begin() + inputpos, asciicode);
                    278:                inputpos++;
                    279:                break;
                    280:         }
1.1       root      281:        }
1.1.1.2   root      282:        putmsg(2, "inputbuf=%zd|%s|", inputbuf.length(), inputbuf.c_str());
                    283:        ConsoleUpdate();
                    284: }
1.1       root      285: 
1.1.1.2   root      286: // 画面を更新
                    287: void
                    288: LunaPROMEmuDevice::ConsoleUpdate()
                    289: {
1.1       root      290:        // 入力行全体を都度更新 (面倒なので行をはみ出さないようにする)
                    291:        std::string buf = prompt + inputbuf;
                    292:        text.Print(0, text.GetY(), "%-79s", buf.c_str());
                    293:        // カーソルを描画 (生バッファを触って属性を立てる)
                    294:        uint16 *rawbuf = text.GetRawBuf();
                    295:        int curx = prompt.length() + inputpos;
                    296:        rawbuf[text.GetY() * text.GetCol() + curx] |= TA::On;
                    297:        // 画面更新
                    298:        gBitmap->EmuConsoleUpdate();
                    299: }
                    300: 
                    301: // -A オプションで指定されたホストファイルをロードする。
                    302: // ロードできればエントリポイントを返す。
                    303: // host_file が指定されている時に呼ぶこと。
                    304: uint32
                    305: LunaPROMEmuDevice::LoadHostFile()
                    306: {
                    307:        assert(gMainApp.host_file);
                    308: 
1.1.1.7 ! root      309:        uint32 entry = gRAM->LoadFile(gMainApp.host_file);
1.1       root      310:        if (entry) {
                    311:                text.Print("Host program loaded.  Entry point = $%08x\n",
                    312:                        entry);
                    313:        } else {
                    314:                text.Print("** Couldn't load specified host program.\n");
                    315:        }
                    316:        return entry;
                    317: }
                    318: 
1.1.1.7 ! root      319: // bootinfo に従ってゲストから起動先をロードする。
1.1       root      320: // 成功すればエントリポイントを返す。
                    321: // 失敗ならをエラーメッセージを errmsg にセットして 0 を返す。
                    322: uint32
1.1.1.7 ! root      323: LunaPROMEmuDevice::LoadGuestFile(const bootinfo_t& bootinfo)
1.1       root      324: {
1.1.1.7 ! root      325:        const int& dkpart = bootinfo.dkpart;
        !           326:        const int& dkunit = bootinfo.dkunit;
        !           327:        const std::string& dkfile = bootinfo.dkfile;
1.1       root      328: 
                    329:        // ユニット (今は SCSI ID=6 決め打ち)
                    330:        int id = 6;
                    331:        SCSITarget *target = gSPC->GetTarget(id);
                    332:        if (target == NULL) {
                    333:                errmsg = "No bootable disks";
                    334:                putmsg(0, "%s", errmsg.c_str());
                    335:                return 0;
                    336:        }
1.1.1.3   root      337:        if (target->GetDevType() != SCSI::DevType::HD) {
1.1       root      338:                errmsg = "No bootable disks";
                    339:                putmsg(0, "%s", errmsg.c_str());
                    340:                return 0;
                    341:        }
                    342: 
                    343:        SCSIHD *hd = dynamic_cast<SCSIHD*>(target);
                    344:        putmsg(2, "%s SCSIHD[%d] found", __func__, id);
                    345: 
                    346:        // +0 セクタ目(512byte)に Sun disklabel
                    347:        scd_dk_label dk;
                    348:        if (hd->PeekImage(&dk, 0, sizeof(dk)) == false) {
                    349:                putmsg(0, "SCSIHD[%d] ReadSector failed", id);
                    350:                errmsg = string_format("dk%d Read disklabel failed.", dkunit);
                    351:                return 0;
                    352:        }
                    353: 
                    354:        // +$1fc の MAGIC をチェック
                    355:        uint32 magic = be16toh(dk.magic);
                    356:        if (magic != scd_dk_label::DKL_MAGIC) {
                    357:                putmsg(0, "SCSIHD[%d] Bad magic 0x%04x (!= 0x%x)",
                    358:                        id, magic, scd_dk_label::DKL_MAGIC);
                    359:                errmsg = string_format("dk%d Bad disklabel magic.", dkunit);
                    360:                return 0;
                    361:        }
                    362: 
                    363:        // チェックサム照合は手抜きで省略
                    364: 
                    365:        // 指定パーティションの開始位置とサイズ
                    366:        if (loglevel >= 2) {
                    367:                // デバッグ用に全部表示
                    368:                for (int i = 0; i < 8; i++) {
1.1.1.7 ! root      369:                        putmsgn("%s partition %c: { start=%8u size=%8u }", __func__,
1.1       root      370:                                'a' + i,
                    371:                                be32toh(dk.map[i].blkno),
                    372:                                be32toh(dk.map[i].nblk));
                    373:                }
                    374:        }
                    375:        uint32 part_start = be32toh(dk.map[dkpart].blkno);
                    376:        uint32 part_size  = be32toh(dk.map[dkpart].nblk);
                    377:        putmsg(1, "%s partition=%c, start=%u size=%u", __func__,
                    378:                dkpart + 'a', part_start, part_size);
                    379: 
                    380:        // ファイルシステムをオープン (マウントっぽいイメージ)
                    381:        Filesys fsys(this);
1.1.1.7 ! root      382:        if (fsys.Mount(hd, part_start, part_size) == false) {
        !           383:                errmsg = string_format("dk%d,%c Open ffs failed: %s",
        !           384:                        dkunit, dkpart + 'a', fsys.errstr.c_str());
        !           385:                putmsg(0, "%s: %s", __func__, errmsg.c_str());
1.1       root      386:                return 0;
                    387:        }
                    388: 
1.1.1.7 ! root      389:        // ファイルを探してオープンする
        !           390:        inodefile f(this);
        !           391:        if (fsys.OpenFile(f, dkfile) == false) {
        !           392:                errmsg = string_format("dk%d,%c,%s open failed: %s",
        !           393:                        dkunit, dkpart + 'a', dkfile.c_str(), fsys.errstr.c_str());
        !           394:                putmsg(0, "%s: %s", __func__, errmsg.c_str());
1.1       root      395:                return 0;
                    396:        }
1.1.1.7 ! root      397: 
1.1       root      398:        // ファイル本体を読み込み
1.1.1.7 ! root      399:        fsys.ReadData(f);
1.1       root      400: 
                    401:        // ロード
                    402:        uint32 entry;
                    403:        std::string name = string_format("SCSIHD %d,%c:%s",
1.1.1.7 ! root      404:                id, dkpart + 'a', dkfile.c_str());
        !           405:        entry = gRAM->LoadFile(name.c_str(), f.data.data(), f.data.size());
        !           406:        if (entry == 0) {
        !           407:                errmsg = string_format("dk%d,%c,%s not executable",
        !           408:                        dkunit, dkpart + 'a', dkfile.c_str());
1.1       root      409:        }
                    410: 
1.1.1.7 ! root      411:        return entry;
1.1       root      412: }
                    413: 
1.1.1.7 ! root      414: // キーコードから文字への変換
        !           415: /*static*/ const uint8
        !           416: LunaPROMEmuDevice::lunakey2asciitable[] = {
        !           417:         0, 0, 0, 0, 0, 0, 0, 0,
        !           418:         0, 0, 0, 0, 0, 0, 0, 0,
        !           419:         0, 0, 0, 0, ' ', 0, 0, 0,
        !           420:         0, 0, 0, 0, 0, 0, 0, 0,
        !           421:         0,   0,  '1', '2', '3', '4', '5', '6',
        !           422:        '7', '8', '9', '0', '-', '^', '\\', 0,
        !           423:         0,   0,  'q', 'w', 'e', 'r', 't', 'y',
        !           424:        'u', 'i', 'o', 'p', '@', '[',  0,   0,
        !           425:         0,   0,  'a', 's', 'd', 'f', 'g', 'h',
        !           426:        'j', 'k', 'l', ';', ':', ']',  0,   0,
        !           427:         0,   0,  'z', 'x', 'c', 'v', 'b', 'n',
        !           428:        'm', ',', '.', '/',  0,   0,   0,   0,
        !           429:         0, 0, 0, 0, 0, 0, 0, 0,        // XXX テンキー
        !           430:         0, 0, 0, 0, 0, 0, 0, 0,
        !           431:         0, 0, 0, 0, 0, 0, 0, 0,
        !           432:         0, 0, 0, 0, 0, 0, 0, 0,
        !           433: };
        !           434: /*static*/ const uint8
        !           435: LunaPROMEmuDevice::lunakey2shifttable[] = {
        !           436:         0, 0, 0, 0, 0, 0, 0, 0,
        !           437:         0, 0, 0, 0, 0, 0, 0, 0,
        !           438:         0, 0, 0, 0, ' ', 0, 0, 0,
        !           439:         0, 0, 0, 0, 0, 0, 0, 0,
        !           440:         0,   0,  '1', '2', '3', '4', '5', '6',
        !           441:        '7', '8', '9', '0', '=', '~', '|',  0,
        !           442:         0,   0,  'Q', 'W', 'E', 'R', 'T', 'Y',
        !           443:        'U', 'I', 'O', 'P', '`', '{',  0,   0,
        !           444:         0,   0,  'A', 'S', 'D', 'F', 'G', 'H',
        !           445:        'J', 'K', 'L', '+', '*', '}',  0,   0,
        !           446:         0,   0,  'Z', 'X', 'C', 'V', 'B', 'N',
        !           447:        'M', '<', '>', '?', '_',  0,   0,   0,
        !           448:         0, 0, 0, 0, 0, 0, 0, 0,        // XXX テンキー
        !           449:         0, 0, 0, 0, 0, 0, 0, 0,
        !           450:         0, 0, 0, 0, 0, 0, 0, 0,
        !           451:         0, 0, 0, 0, 0, 0, 0, 0,
        !           452: };

unix.superglobalmegacorp.com

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