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

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

unix.superglobalmegacorp.com

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