|
|
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
12: // |
13: // +-- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
14: // | |
15: // | +-- PROMDevice (LUNA* の PROM)
16: // | +-- IPLROM1Device (X680x0 の IPLROM 後半)
17: // | +-- IPLROM2Device (X680x0 の IPLROM 前半)
18: // | +-- CGROMDevice (X680x0 の CGROM)
19: // | |
20: // | | +-------------------+
21: // | +--| LunaPROMEmuDevice | (LUNA PROM エミュレーションの共通部分)
22: // | +-------------------+
23: // | |
1.1.1.14! root 24: // | +-- Luna1PROMEmuDevice (LUNA-I の PROM エミュレーション)
! 25: // | +-- Luna88kPROMEmuDevice (LUNA-88K の PROM エミュレーション)
1.1.1.10 root 26: // |
27: // +-- PROM0Device (LUNA* のブートページ切り替え用プロキシ)
28: // +-- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ)
1.1.1.2 root 29:
30: #include "romemu_luna.h"
1.1.1.14! root 31: #include "bt45x.h"
1.1.1.9 root 32: #include "lunafb.h"
1.1 root 33: #include "mainapp.h"
1.1.1.14! root 34: #include "mainram.h"
1.1 root 35: #include "mk48t02.h"
1.1.1.13 root 36: #include "mpu.h"
1.1.1.14! root 37: #include "pio.h"
1.1.1.13 root 38: #include "prom.h"
1.1 root 39: #include "sio.h"
40: #include "spc.h"
1.1.1.7 root 41: #include "ufs.h"
1.1 root 42:
43: // コンストラクタ
44: LunaPROMEmuDevice::LunaPROMEmuDevice()
1.1.1.14! root 45: : inherited(OBJ_PROM)
1.1 root 46: {
1.1.1.10 root 47: // LUNA では ROM への書き込みは何も起きない
48: write_op = 0;
1.1 root 49: }
50:
51: // デストラクタ
52: LunaPROMEmuDevice::~LunaPROMEmuDevice()
53: {
54: }
55:
1.1.1.14! root 56: // 初期化
1.1 root 57: bool
58: LunaPROMEmuDevice::Init()
59: {
1.1.1.14! root 60: if (inherited::Init() == false) {
! 61: return false;
! 62: }
! 63:
! 64: bt45x = GetBT45xDevice();
! 65: lunafb = GetLunafbDevice();
! 66: mainram = GetMainRAMDevice();
! 67: nvram = GetMK48T02Device();
! 68: sio = GetSIODevice();
! 69: spc = GetSPCDevice();
1.1 root 70:
71: return true;
72: }
73:
1.1.1.2 root 74: uint64
1.1 root 75: LunaPROMEmuDevice::Read32(uint32 addr)
76: {
1.1.1.10 root 77: // ROM からのロングワードアクセスでだけ謎の I/O 空間が見える。
78: // addr をマスクする前に評価すること。
1.1.1.14! root 79: if ((mpu->GetPaddr() & 0xff000000) == baseaddr) {
1.1.1.9 root 80: switch (addr) {
81: case ROMIO_INIT:
1.1.1.2 root 82: return ROM_Init();
1.1 root 83:
1.1.1.9 root 84: case ROMIO_KEYIN:
1.1.1.7 root 85: ROM_Keyin();
86: return 0;
1.1 root 87:
1.1.1.9 root 88: case ROMIO_CLOSE:
1.1.1.7 root 89: ROM_Close();
90: return 0;
1.1 root 91:
1.1.1.9 root 92: case ROMIO_ENTRY:
1.1.1.7 root 93: return ROM_Entry();
1.1.1.6 root 94:
1.1 root 95: default:
96: break;
97: }
98: }
1.1.1.2 root 99:
1.1.1.10 root 100: return inherited::Read32(addr);
1.1 root 101: }
102:
1.1.1.7 root 103: // デバイスの初期化の共通部分。(継承クラスの ROM_Init() から呼ぶ)
104: void
105: LunaPROMEmuDevice::InitDevice()
1.1 root 106: {
1.1.1.14! root 107: auto pio1 = GetPIO1Device();
! 108:
1.1 root 109: // 初期パレット
1.1.1.4 root 110: // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。
1.1.1.14! root 111: uint8 val = 0xff;
! 112: bt45x->Write(0, 0); // select palette
1.1.1.4 root 113: for (int i = 0; i < 16; i++) {
1.1.1.14! root 114: bt45x->Write(1, val); // R
! 115: bt45x->Write(1, val); // G
! 116: bt45x->Write(1, val); // B
! 117: val ^= 0xff;
1.1.1.4 root 118: }
1.1 root 119:
120: // SCSI
121: // BDID の書き込みによってホストデバイスがバスにアタッチされる構造なので。
1.1.1.14! root 122: spc->Write(SPC::BDID, 7);
1.1 root 123:
1.1.1.7 root 124: // キーボード(chB)を初期化
1.1.1.14! root 125: sio->Write(3, 0x01); // CR1
! 126: sio->Write(3, 0x10); // RX Int(all char)
! 127: sio->Write(3, 0x04); // CR4
! 128: sio->Write(3, 0x44); // Stop 1bit
! 129: sio->Write(3, 0x03); // CR3
! 130: sio->Write(3, 0xc1); // RX Enable, 8bit
! 131: sio->Write(3, 0x05); // CR5
! 132: sio->Write(3, 0x68); // TX Enable, 8bit
1.1.1.12 root 133:
134: // LED を(明示的に)オフ、マウスサンプリングをオフ
1.1.1.14! root 135: sio->Write(2, 0x00);
! 136: sio->Write(2, 0x01);
! 137: sio->Write(2, 0x20);
! 138:
! 139: // 電源オフをキャンセル。
! 140: // 実 PROM では、リセット後に PIO のモードセットを行っている。
! 141: // モードセットを行うと PortC のビットが %0 になる = 電源オフなので、
! 142: // 即座にこれをキャンセルしている。
! 143: // ROMEmu ではモードセットを行っていないが、キャンセルだけ発行しておく。
! 144: pio1->Write(3, 0x09);
1.1.1.7 root 145: }
1.1.1.2 root 146:
1.1.1.7 root 147: // スクリーンを初期化
148: void
1.1.1.13 root 149: LunaPROMEmuDevice::InitScreen()
1.1.1.7 root 150: {
1.1.1.14! root 151: lunafb->EmuInitScreen();
1.1.1.13 root 152:
153: screen_w = 80;
154: screen_h = 32;
155: cursor_x = 0;
156: cursor_y = 0;
157:
158: // 表示範囲はざっくりセンタリングする
159: origin_px = (1280 - screen_w * 12) / 2;
160: origin_py = (1024 - screen_h * 24) / 2;
161: // 横は 48ドット境界から始めておく。
162: // こうすると1(,2)文字目の24ビットが必ずワード境界から始まるため。
163: // 今となっては任意の場所から文字が描画できるようになったので揃える
164: // 必要はなくなったが、依然このほうがアクセス効率はいいので。
165: origin_px = (origin_px / 48) * 48;
166:
1.1.1.2 root 167: inputbuf.clear();
168: inputpos = 0;
169: is_shift = false;
1.1.1.3 root 170: mousecnt = 0;
1.1.1.13 root 171: }
1.1 root 172:
1.1.1.13 root 173: // タイトルを出力
174: void
175: LunaPROMEmuDevice::PrintTitle(const char *machine_name)
176: {
177: Print("NONO %d.%d.%d Emulated ROM Monitor for %s\n\n",
1.1.1.7 root 178: NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, machine_name);
1.1.1.13 root 179: }
180:
181: // 1文字出力
182: void
183: LunaPROMEmuDevice::Putc(uint ch)
184: {
185: uint px = origin_px + cursor_x * 12;
186: uint py = origin_py + cursor_y * 24;
187:
188: // カーソル位置の反転を元に戻す
1.1.1.14! root 189: lunafb->EmuPutc(px, py, ' ', ROP::INV2);
1.1.1.13 root 190:
191: if (ch == LF) {
192: put_LF:
193: cursor_x = 0;
194: if (cursor_y < screen_h - 1) {
195: cursor_y++;
196: } else {
197: // 上スクロールして..
1.1.1.14! root 198: lunafb->EmuScrollY(origin_py, origin_py + 24, (screen_h - 1) * 24);
1.1.1.13 root 199: // 最終行を消す
1.1.1.14! root 200: lunafb->EmuFill(0, py, 1280, 24, 0);
1.1.1.13 root 201: }
202: } else if (ch == LEFT) {
203: if (cursor_x > 0) {
204: cursor_x--;
205: } else {
206: cursor_y--;
207: cursor_x = screen_w - 1;
208: }
209: } else if (ch == RIGHT) {
210: if (cursor_x < screen_w - 1) {
211: cursor_x++;
212: } else {
213: cursor_y++;
214: cursor_x = 0;
215: }
216: } else {
217: if (cursor_x < screen_w - 1) {
1.1.1.14! root 218: lunafb->EmuPutc(px, py, ch);
1.1.1.13 root 219: cursor_x++;
220: } else {
1.1.1.14! root 221: lunafb->EmuPutc(px, py, ch);
1.1.1.13 root 222: goto put_LF;
223: }
224: }
225:
226: // カーソル位置を再計算して描画 (文字を反転)
227: px = origin_px + cursor_x * 12;
228: py = origin_py + cursor_y * 24;
1.1.1.14! root 229: lunafb->EmuPutc(px, py, ' ', ROP::INV2);
1.1.1.13 root 230: }
231:
232: // 文字列 s を出力
233: void
234: LunaPROMEmuDevice::Print(const std::string& s)
235: {
236: for (auto *p = s.c_str(); *p; p++) {
237: Putc(*p);
238: }
239: }
240:
241: // 文字列 fmt... を出力
242: void
243: LunaPROMEmuDevice::Print(const char *fmt, ...)
244: {
245: char buf[1024];
246: va_list ap;
247:
248: va_start(ap, fmt);
249: vsnprintf(buf, sizeof(buf), fmt, ap);
250: va_end(ap);
251:
252: for (char *p = buf; *p; p++) {
253: Putc(*p);
254: }
1.1 root 255: }
256:
1.1.1.7 root 257: // ROM 処理のクローズ
258: void
1.1.1.2 root 259: LunaPROMEmuDevice::ROM_Close()
1.1 root 260: {
1.1.1.11 root 261: // SIO をリセットしておく。
262: // SIO のバッファにデータが残っていると、NetBSD のブートローダが
263: // 起動してこないようだ。リセットして RXEN を落としておけば大丈夫ぽい。
1.1.1.14! root 264: sio->ResetHard(false);
1.1 root 265: }
266:
1.1.1.2 root 267: // ROM プロンプトのキー入力。
1.1.1.7 root 268: // ゲストコードの割り込みハンドラから呼ばれて、キー入力で行を構成し、
269: // あるいは行が完成すればコマンドを実行する。
270: // 実行結果により画面を更新したりメンバ変数を更新する。
271: void
1.1.1.2 root 272: LunaPROMEmuDevice::ROM_Keyin()
1.1 root 273: {
1.1.1.14! root 274: int asciicode = Getc();
! 275:
! 276: if (asciicode != -1) {
! 277: ProcessChar(asciicode);
! 278: }
! 279: }
! 280:
! 281: // キー入力。
! 282: // 押されているキーの ASCII コードを返す。
! 283: // キー入力が無いときは -1 を返す。
! 284: int
! 285: LunaPROMEmuDevice::Getc()
! 286: {
! 287: // コントロールレジスタポインタを確実に 0 にするため読み捨てる
! 288: sio->Read(3);
! 289:
! 290: uint8 sr0 = sio->Read(3);
! 291: if ((sr0 & MPSCC::SR0_RXAVAIL) == 0) {
! 292: return -1;
! 293: }
! 294:
! 295: uint32 lunakey = sio->Read(2);
1.1 root 296:
1.1.1.3 root 297: // マウス入力の 2, 3バイト目は無視
298: if (mousecnt > 0) {
299: mousecnt--;
1.1.1.14! root 300: return -1;
1.1.1.3 root 301: }
302:
1.1.1.2 root 303: // SHIFT キーだけ状態を持つので先に処理
304: if (lunakey == 0x0c || lunakey == 0x0d) { // 左右SHIFT押下
305: is_shift = true;
1.1.1.14! root 306: return -1;
1.1.1.2 root 307: }
308: if (lunakey == 0x8c || lunakey == 0x8d) { // 左右SHIFT開放
1.1 root 309: is_shift = false;
1.1.1.14! root 310: return -1;
1.1.1.2 root 311: }
1.1.1.3 root 312: // マウスデータの1バイト目なら、後続2バイトをスキップ
313: if ((lunakey & 0xf8) == 0x80) {
314: mousecnt = 2;
1.1.1.14! root 315: return -1;
1.1.1.3 root 316: }
317: // キー開放は無視してよい
1.1.1.2 root 318: if ((lunakey & 0x80)) {
1.1.1.14! root 319: return -1;
1.1.1.2 root 320: }
1.1 root 321:
1.1.1.9 root 322: // キーコードから文字を取得
1.1.1.14! root 323: int asciicode;
1.1.1.9 root 324: if (is_shift) {
325: asciicode = lunakey2shifttable[lunakey];
326: } else {
327: asciicode = lunakey2asciitable[lunakey];
328: }
1.1.1.14! root 329: if (asciicode == 0) {
! 330: return -1;
1.1.1.9 root 331: }
1.1.1.14! root 332:
! 333: return asciicode;
1.1.1.9 root 334: }
335:
336: // キー入力ハンドラ (キー入力割り込みによって呼ばれる)。
337: // 引数 asciicode は概ね ASCII コード (ただし 0x1c..0x1f が上下左右)。
338: void
1.1.1.14! root 339: LunaPROMEmuDevice::ProcessChar(char asciicode)
1.1.1.9 root 340: {
1.1.1.14! root 341: // LUNA-I の場合、
1.1.1.9 root 342: // 実機 PROM にはカーソル左右移動の機能はなく、カーソルは常に行末にいる。
343: // そのためかどうか Delete も BackSpace と同じく1文字前を消す動作をして
344: // いる。カーソル位置に文字はないので、Delete をそうするのはまあ分からん
345: // でもない。
346: // 一方、エミュレーション ROM では、カーソルの左右移動をサポートしてみた
347: // ため Delete を「カーソル位置の文字を消す」にすることは出来るが、それは
348: // それで実機と乖離が広がるので、どうしたもんか。
349:
350: switch (asciicode) {
351: case BS:
352: if (inputbuf.empty() == false && inputpos != 0) {
353: inputbuf.erase(--inputpos, 1);
1.1.1.13 root 354: Putc(LEFT);
355: for (int i = inputpos; i < inputbuf.size(); i++) {
356: Putc(inputbuf[i]);
357: }
358: Putc(' ');
359: for (int i = 0; i < 1 + inputbuf.size() - inputpos; i++) {
360: Putc(LEFT);
361: }
1.1 root 362: }
1.1.1.2 root 363: break;
1.1.1.9 root 364:
365: case LF:
1.1.1.2 root 366: // 改行
1.1.1.13 root 367: Putc(asciicode);
368: prompt_y = cursor_y;
1.1.1.9 root 369: // コマンド実行
1.1.1.7 root 370: Command();
1.1.1.9 root 371: // プロンプトを更新
372: ClearPrompt();
1.1.1.2 root 373: break;
1.1.1.9 root 374:
375: case LEFT:
1.1.1.2 root 376: if (inputpos > 0) {
377: inputpos--;
1.1.1.13 root 378: Putc(LEFT);
1.1 root 379: }
1.1.1.2 root 380: break;
1.1.1.9 root 381: case RIGHT:
1.1.1.2 root 382: if (inputpos < inputbuf.length()) {
1.1 root 383: inputpos++;
1.1.1.13 root 384: Putc(RIGHT);
1.1 root 385: }
386: break;
1.1.1.9 root 387:
388: case UP:
389: case DOWN:
390: case 0: // キー割り当てなし、これは来ないはずだが一応
391: return;
392:
393: default: // 通常文字のはず
1.1.1.2 root 394: inputbuf.insert(inputbuf.begin() + inputpos, asciicode);
1.1.1.13 root 395: for (int i = inputpos; i < inputbuf.size(); i++) {
396: Putc(inputbuf[i]);
397: }
398: for (int i = 0; i < inputbuf.size() - inputpos - 1; i++) {
399: Putc(LEFT);
400: }
1.1.1.2 root 401: inputpos++;
402: break;
1.1 root 403: }
1.1.1.2 root 404: }
1.1 root 405:
1.1.1.9 root 406: // 入力バッファを初期化する。
407: void
408: LunaPROMEmuDevice::ClearPrompt()
409: {
1.1.1.13 root 410: prompt_y = cursor_y;
1.1.1.9 root 411: // 入力行をクリア
412: inputbuf.clear();
413: inputpos = 0;
414:
1.1.1.13 root 415: Print(prompt);
1.1.1.9 root 416: }
417:
418: // NVRAM のチェックサムを返す
419: uint8
420: LunaPROMEmuDevice::CalcNVRAMCsum() const
421: {
422: uint8 eor = 0;
423: for (uint32 addr = 0x20; addr < 0x560; addr++) {
424: eor ^= nvram->Peek(addr);
425: }
426: return eor;
427: }
428:
429: // NVRAM のチェックサムを計算して書き込む
430: void
431: LunaPROMEmuDevice::WriteNVRAMCsum()
432: {
433: uint8 eor = CalcNVRAMCsum();
434:
435: nvram->Write(0x001c, eor);
436: nvram->Write(0x001d, eor);
437: nvram->Write(0x001e, eor);
438: }
439:
440: // NVRAM のマジックとチェックサムを照合する
441: bool
442: LunaPROMEmuDevice::VerifyNVRAM() const
443: {
444: if (nvram->PeekString(0x0004) != "<nv>") {
445: return false;
446: }
447:
448: uint8 eor = CalcNVRAMCsum();
449: for (uint32 addr = 0x1c; addr < 0x1f; addr++) {
450: if (nvram->Peek(addr) != eor) {
451: return false;
452: }
453: }
454: return true;
1.1 root 455: }
456:
1.1.1.10 root 457: // -X オプションで指定されたホストファイルをロードする。
1.1 root 458: // ロードできればエントリポイントを返す。
1.1.1.10 root 459: // exec_file が指定されている時に呼ぶこと。
1.1 root 460: uint32
461: LunaPROMEmuDevice::LoadHostFile()
462: {
1.1.1.10 root 463: assert(gMainApp.exec_file);
1.1 root 464:
1.1.1.14! root 465: LoadInfo info(gMainApp.exec_file);
! 466: if (mainram->LoadFromFile(&info)) {
! 467: Print("Host program loaded. Entry point = $%08x\n", info.entry);
! 468: return info.entry;
1.1 root 469: } else {
1.1.1.13 root 470: Print("** Couldn't load specified host program.\n");
1.1.1.14! root 471: return 0;
1.1 root 472: }
473: }
474:
1.1.1.7 root 475: // bootinfo に従ってゲストから起動先をロードする。
1.1 root 476: // 成功すればエントリポイントを返す。
1.1.1.14! root 477: // 失敗ならをエラーメッセージを errmsg にセットして (uint32)-1 を返す。
1.1 root 478: uint32
1.1.1.7 root 479: LunaPROMEmuDevice::LoadGuestFile(const bootinfo_t& bootinfo)
1.1 root 480: {
1.1.1.7 root 481: const int& dkpart = bootinfo.dkpart;
482: const int& dkunit = bootinfo.dkunit;
483: const std::string& dkfile = bootinfo.dkfile;
1.1 root 484:
485: // ユニット (今は SCSI ID=6 決め打ち)
486: int id = 6;
1.1.1.14! root 487: SCSITarget *target = spc->GetTarget(id);
1.1 root 488: if (target == NULL) {
489: errmsg = "No bootable disks";
490: putmsg(0, "%s", errmsg.c_str());
1.1.1.14! root 491: return -1;
1.1 root 492: }
1.1.1.3 root 493: if (target->GetDevType() != SCSI::DevType::HD) {
1.1 root 494: errmsg = "No bootable disks";
495: putmsg(0, "%s", errmsg.c_str());
1.1.1.14! root 496: return -1;
1.1 root 497: }
498:
1.1.1.10 root 499: SCSIDisk *hd = dynamic_cast<SCSIDisk*>(target);
1.1 root 500: putmsg(2, "%s SCSIHD[%d] found", __func__, id);
501:
502: // +0 セクタ目(512byte)に Sun disklabel
503: scd_dk_label dk;
1.1.1.10 root 504: if (hd->Peek(&dk, 0, sizeof(dk)) == false) {
1.1 root 505: putmsg(0, "SCSIHD[%d] ReadSector failed", id);
506: errmsg = string_format("dk%d Read disklabel failed.", dkunit);
1.1.1.14! root 507: return -1;
1.1 root 508: }
509:
510: // +$1fc の MAGIC をチェック
511: uint32 magic = be16toh(dk.magic);
512: if (magic != scd_dk_label::DKL_MAGIC) {
513: putmsg(0, "SCSIHD[%d] Bad magic 0x%04x (!= 0x%x)",
514: id, magic, scd_dk_label::DKL_MAGIC);
515: errmsg = string_format("dk%d Bad disklabel magic.", dkunit);
1.1.1.14! root 516: return -1;
1.1 root 517: }
518:
519: // チェックサム照合は手抜きで省略
520:
521: // 指定パーティションの開始位置とサイズ
522: if (loglevel >= 2) {
523: // デバッグ用に全部表示
524: for (int i = 0; i < 8; i++) {
1.1.1.7 root 525: putmsgn("%s partition %c: { start=%8u size=%8u }", __func__,
1.1 root 526: 'a' + i,
527: be32toh(dk.map[i].blkno),
528: be32toh(dk.map[i].nblk));
529: }
530: }
531: uint32 part_start = be32toh(dk.map[dkpart].blkno);
532: uint32 part_size = be32toh(dk.map[dkpart].nblk);
533: putmsg(1, "%s partition=%c, start=%u size=%u", __func__,
534: dkpart + 'a', part_start, part_size);
535:
536: // ファイルシステムをオープン (マウントっぽいイメージ)
537: Filesys fsys(this);
1.1.1.7 root 538: if (fsys.Mount(hd, part_start, part_size) == false) {
539: errmsg = string_format("dk%d,%c Open ffs failed: %s",
540: dkunit, dkpart + 'a', fsys.errstr.c_str());
541: putmsg(0, "%s: %s", __func__, errmsg.c_str());
1.1.1.14! root 542: return -1;
1.1 root 543: }
544:
1.1.1.7 root 545: // ファイルを探してオープンする
546: inodefile f(this);
547: if (fsys.OpenFile(f, dkfile) == false) {
548: errmsg = string_format("dk%d,%c,%s open failed: %s",
549: dkunit, dkpart + 'a', dkfile.c_str(), fsys.errstr.c_str());
550: putmsg(0, "%s: %s", __func__, errmsg.c_str());
1.1.1.14! root 551: return -1;
1.1 root 552: }
1.1.1.7 root 553:
1.1 root 554: // ファイル本体を読み込み
1.1.1.7 root 555: fsys.ReadData(f);
1.1 root 556:
557: // ロード
558: std::string name = string_format("SCSIHD %d,%c:%s",
1.1.1.7 root 559: id, dkpart + 'a', dkfile.c_str());
1.1.1.14! root 560: LoadInfo info(name.c_str(), f.data.data(), f.data.size());
! 561: if (mainram->LoadFromData(&info) == false) {
! 562: errmsg = string_format("dk%d,%c,%s load failed",
! 563: dkunit, dkpart + 'a', dkfile.c_str());
! 564: putmsg(0, "%s: %s", __func__, errmsg.c_str());
! 565: return -1;
! 566: }
! 567:
! 568: if (info.entry == -1) {
1.1.1.7 root 569: errmsg = string_format("dk%d,%c,%s not executable",
570: dkunit, dkpart + 'a', dkfile.c_str());
1.1.1.14! root 571: putmsg(0, "%s: %s", __func__, errmsg.c_str());
! 572: return -1;
1.1 root 573: }
574:
1.1.1.14! root 575: return info.entry;
1.1 root 576: }
577:
1.1.1.7 root 578: // キーコードから文字への変換
579: /*static*/ const uint8
580: LunaPROMEmuDevice::lunakey2asciitable[] = {
1.1.1.9 root 581: 0, 0, 0, 0, 0, 0, 0, 0,
582: 0, 0, 0, 0, 0, 0, 0, 0,
583: 0, BS, LF, 0, ' ', 0, 0, 0,
584: 0, 0, 0, 0, UP,LEFT,RIGHT,DOWN,
1.1.1.7 root 585: 0, 0, '1', '2', '3', '4', '5', '6',
586: '7', '8', '9', '0', '-', '^', '\\', 0,
587: 0, 0, 'q', 'w', 'e', 'r', 't', 'y',
588: 'u', 'i', 'o', 'p', '@', '[', 0, 0,
589: 0, 0, 'a', 's', 'd', 'f', 'g', 'h',
590: 'j', 'k', 'l', ';', ':', ']', 0, 0,
591: 0, 0, 'z', 'x', 'c', 'v', 'b', 'n',
592: 'm', ',', '.', '/', 0, 0, 0, 0,
1.1.1.13 root 593: 0, '+', '-', '7', '8', '9', '4', '5',
594: '6', '1', '2', '3', '0', '.', LF, 0,
595: 0, 0, 0, 0, 0, 0, 0, 0,
596: 0, 0, 0, 0, '*', '/', '=', ',',
1.1.1.7 root 597: };
598: /*static*/ const uint8
599: LunaPROMEmuDevice::lunakey2shifttable[] = {
1.1.1.9 root 600: 0, 0, 0, 0, 0, 0, 0, 0,
601: 0, 0, 0, 0, 0, 0, 0, 0,
602: 0, BS, LF, 0, ' ', 0, 0, 0,
603: 0, 0, 0, 0, UP,LEFT,RIGHT,DOWN,
604: 0, 0, '!', '\"','#', '$', '%', '&',
605: '\'','(', ')', ' ', '=', '~', '|', 0, // XXX SHIFT+'0'は?
1.1.1.7 root 606: 0, 0, 'Q', 'W', 'E', 'R', 'T', 'Y',
607: 'U', 'I', 'O', 'P', '`', '{', 0, 0,
608: 0, 0, 'A', 'S', 'D', 'F', 'G', 'H',
609: 'J', 'K', 'L', '+', '*', '}', 0, 0,
610: 0, 0, 'Z', 'X', 'C', 'V', 'B', 'N',
611: 'M', '<', '>', '?', '_', 0, 0, 0,
1.1.1.13 root 612: 0, '+', '-', '7', '8', '9', '4', '5',
613: '6', '1', '2', '3', '0', '.', LF, 0,
614: 0, 0, 0, 0, 0, 0, 0, 0,
615: 0, 0, 0, 0, '*', '/', '=', ',',
1.1.1.7 root 616: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.