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