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