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