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