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