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