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

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

unix.superglobalmegacorp.com

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