|
|
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.11! root 7: //
1.1.1.2 root 8: // LUNA88K の ROM エミュレーション
1.1.1.8 root 9: //
1.1.1.11! root 10:
1.1.1.8 root 11: // IODevice
12: // |
13: // +-- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
14: // | |
15: // | +-- PROMDevice (LUNA* の PROM)
16: // | +-- IPLROM1Device (X680x0 の IPLROM 後半)
17: // | +-- IPLROM2Device (X680x0 の IPLROM 前半)
18: // | +-- CGROMDevice (X680x0 の CGROM)
19: // | +-- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分)
20: // | |
21: // | +-- Luna1PROMEmuDevice (LUNA1 の PROM エミュレーション)
22: // | |
23: // | | +----------------------+
24: // | +--| Luna88kPROMEmuDevice | (LUNA88K の PROM エミュレーション)
25: // | +----------------------+
26: // |
27: // +-- PROM0Device (LUNA* のブートページ切り替え用プロキシ)
28: // +-- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ)
1.1.1.2 root 29:
30: #include "romemu_luna88k.h"
1.1.1.11! root 31: #include "interrupt.h"
1.1.1.5 root 32: #include "iodevstream.h"
1.1 root 33: #include "mainapp.h"
34: #include "memorystream.h"
1.1.1.7 root 35: #include "mk48t02.h"
1.1.1.8 root 36: #include "mpu88xx0.h"
1.1.1.5 root 37: #include "pio.h"
1.1 root 38: #include "ram.h"
39:
1.1.1.8 root 40: static bool luna88k_fline_callback(m88kcpu *cpu, void *arg);
41:
42: // m88k の命令コードを少し読みやすく書きたい。
43: // 必要なものは適宜足すこと。
44: enum class OPr {
45: r0, r1, r2, r3, r4, r5, r6, r7,
46: r8, r9, r10, r11, r12, r13, r14, r15,
47: r16, r17, r18, r19, r20, r21, r22, r23,
48: r24, r25, r26, r27, r28, r29, r30, r31,
49: };
50: #define r0 OPr::r0
51: #define r1 OPr::r1
52: #define r2 OPr::r2
53: #define r3 OPr::r3
54: #define r4 OPr::r4
55: #define r5 OPr::r5
56: #define r6 OPr::r6
57: #define r7 OPr::r7
58: #define r8 OPr::r8
59: #define r9 OPr::r9
60: #define r10 OPr::r10
61: enum OPm5 {
62: eq0 = 0x02,
63: ne0 = 0x0d,
64: };
65: enum OPcr {
66: psr = 0x01,
67: };
68:
1.1.1.11! root 69: #define USC __unused static constexpr
! 70:
! 71: USC uint32 OP3(uint32 base, uint32 rd, uint32 rs1, uint32 rs2) {
1.1.1.8 root 72: return (base) | (rd << 21) | (rs1 << 16) | rs2;
73: }
1.1.1.11! root 74: USC uint32 OP4(uint32 base, uint32 rd, uint32 rs1,
1.1.1.8 root 75: uint32 w, uint32 o) {
76: return (base) | (rd << 21) | (rs1 << 16) | (w << 5) | o;
77: }
78:
1.1.1.11! root 79: USC uint32 OP_addu(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8 root 80: return OP3(0x60000000, (uint32)rd, (uint32)rs1, imm);
81: }
1.1.1.11! root 82: USC uint32 OP_addu(OPr rd, OPr rs1, OPr rs2) {
! 83: return OP3(0xf4006000, (uint32)rd, (uint32)rs1, (uint32)rs2);
1.1.1.8 root 84: }
1.1.1.11! root 85: USC uint32 OP_bcnd(OPm5 m5, OPr rs1, uint32 d16) {
! 86: return OP3(0xe8000000, (uint32)m5, (uint32)rs1, d16 & 0xffff);
1.1.1.8 root 87: }
1.1.1.11! root 88: USC uint32 OP_bsr(uint32 d26) {
! 89: return (0xc8000000 | (d26 & 0x03ffffff));
! 90: }
! 91: USC uint32 OP_clr(OPr rd, OPr rs1, uint32 w, uint32 o) {
1.1.1.8 root 92: return OP4(0xf0008000, (uint32)rd, (uint32)rs1, w, o);
93: }
1.1.1.11! root 94: USC uint32 OP_jmp(OPr rs2) {
1.1.1.8 root 95: return OP3(0xf400c000, 0, 0, (uint32)rs2);
96: }
1.1.1.11! root 97: USC uint32 OP_ld(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8 root 98: return OP3(0x14000000, (uint32)rd, (uint32)rs1, imm);
99: }
1.1.1.11! root 100: USC uint32 OP_ldcr(OPr rd, uint32 crs) {
1.1.1.8 root 101: return OP4(0x80004000, (uint32)rd, 0, crs, 0);
102: }
1.1.1.11! root 103: USC uint32 __unused OP_or(OPr rd, OPr rs1, OPr rs2) {
1.1.1.8 root 104: return OP3(0xf4005800, (uint32)rd, (uint32)rs1, (uint32)rs2);
105: }
1.1.1.11! root 106: USC uint32 OP_or(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8 root 107: return OP3(0x58000000, (uint32)rd, (uint32)rs1, imm);
108: }
1.1.1.11! root 109: USC uint32 OP_or_u(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8 root 110: return OP3(0x5c000000, (uint32)rd, (uint32)rs1, imm);
111: }
1.1.1.11! root 112: USC uint32 OP_rte() {
1.1.1.8 root 113: return 0xf400fc00;
114: }
1.1.1.11! root 115: USC uint32 OP_st(OPr rd, OPr rs1, OPr rs2) {
1.1.1.8 root 116: return OP3(0xf4002400, (uint32)rd, (uint32)rs1, (uint32)rs2);
117: }
1.1.1.11! root 118: USC uint32 OP_stcr(OPr rs1, uint32 crd) {
1.1.1.8 root 119: return OP4(0x80008000, 0, (uint32)rs1, crd, (uint32)rs1);
120: }
1.1.1.11! root 121: USC uint32 OP_doscall(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8 root 122: return OP3(0xfc000400, (uint32)rd, (uint32)rs1, imm);
123: }
124: #define DOS_GETCHAR (1)
125: #define DOS_PUTCHAR (2)
126:
127:
1.1 root 128: // コンストラクタ
129: Luna88kPROMEmuDevice::Luna88kPROMEmuDevice()
130: {
131: devaddr = baseaddr;
1.1.1.5 root 132:
133: // ROM の特定アドレスを読み出す人がいるかも知れないので、
134: // サイズは実 ROM と同じにしておく。LUNA-I からの類推。
1.1.1.2 root 135: devlen = 256 * 1024;
1.1.1.8 root 136: imagebuf.reset(new uint8 [devlen]);
137: memset(&imagebuf[0], 0, devlen);
138: mem = &imagebuf[0];
139:
140: mask = devlen - 1;
1.1.1.2 root 141:
1.1.1.5 root 142: // プロンプトを初期化。
1.1.1.7 root 143: prompt = default_prompt;
1.1 root 144: }
145:
146: // デストラクタ
147: Luna88kPROMEmuDevice::~Luna88kPROMEmuDevice()
148: {
149: }
150:
151: bool
152: Luna88kPROMEmuDevice::Init()
153: {
1.1.1.5 root 154: // 親クラス
155: if (inherited::Init() == false) {
156: return false;
157: }
158:
1.1.1.8 root 159: // DOS call エミュレーションのコールバックを登録
160: gMPU88xx0->SetFLineCallback(luna88k_fline_callback, this);
161:
162: MemoryStreamBE ms(imagebuf.get());
1.1 root 163:
1.1.1.6 root 164: // リセット時のブートページには ROM (これ) が見えている。
165: // ROMIO_INIT へのアクセスでブートページを RAM に切り替えて、同時に RAM の
166: // 0番地付近のベクタも作り直す。そのため、ここのベクタ1 以降 ($41000008〜)
167: // をベクタとして参照することはないので、ベクタ0 の命令列がそのまま使い潰
168: // してよい。というか2ワードでは 0番地から ROM まで飛べないので使わないと
169: // 面倒くさい。一体どういう設計してんだ…。
170:
1.1.1.8 root 171: // ここからややアセンブラっぽいインデント
172:
173: // _START:
174: // ここは 0番地。ここから _ROM_START へジャンプ
175: ms.Write32(OP_or_u (r6, r0, 0x4100));
176: ms.Write32(OP_or (r6, r6, 0x000c));
177: ms.Write32(OP_jmp (r6));
178:
179: // _ROM_START: (ここは ROM)
180: // RAM に切り替え
181: ms.Write32(OP_st (r0, r6, r0));
182:
1.1.1.11! root 183: // 元の PSR を r10 に保存し、r9 に割り込み許可の値を作る
1.1.1.8 root 184: ms.Write32(OP_ldcr (r10, psr));
1.1.1.11! root 185: ms.Write32(OP_clr (r9, r10, 2, 0)); // clear IND,SFRZ
1.1.1.8 root 186:
187: ms.Write32(OP_or_u (r3, r0, ROMIO_BASE >> 16));
188: ms.Write32(OP_or (r3, r3, ROMIO_BASE & 0xfff));
189: // ROMIO_INIT を読み出す
190: ms.Write32(OP_ld (r2, r3, (ROMIO_INIT - ROMIO_BASE)));
191: // 起動先があれば GO
1.1.1.11! root 192: ms.Write32(OP_bcnd (ne0, r2, 7)); // 7 = _go
1.1.1.8 root 193:
194: // _prompt:
195: // 疑似 STOP でキー入力を待つ
1.1.1.11! root 196: ms.Write32(OP_stcr (r9, psr)); // 割り込み許可
1.1.1.8 root 197: ms.Write32(OP_bsr (1)); // 1 = _stop
198: // この時点で r1 = _stop
199:
200: // _stop:
201: ms.Write32(OP_jmp (r1));
202:
203: // _back:
1.1.1.11! root 204: // 割り込み禁止に戻す
! 205: ms.Write32(OP_stcr (r10, psr));
! 206:
1.1.1.8 root 207: ms.Write32(OP_ld (r2, r3, (ROMIO_ENTRY - ROMIO_BASE)));
208: // 起動先がなければループ
1.1.1.11! root 209: ms.Write32(OP_bcnd (eq0, r2, -5)); // -5 = _prompt
1.1.1.8 root 210:
211: // _go:
212: // 起動先があれば後始末して
213: ms.Write32(OP_ld (r0, r3, (ROMIO_CLOSE - ROMIO_BASE)));
214: // ジャンプ
215: ms.Write32(OP_jmp (r2));
1.1.1.5 root 216:
217: // ここから割り込みハンドラ。割り込みは SIO のみ許可にしてある。
218: // キーボード割り込みが上がったら KEYIN をコールして _back に戻る。
1.1.1.11! root 219: ms.SetOffset(0x200);
1.1.1.8 root 220: ms.Write32(OP_ld (r0, r3, (ROMIO_KEYIN - ROMIO_BASE)));
221: // 戻ったところの jmp を抜ける
222: ms.Write32(OP_addu (r1, r1, 0x04));
223: ms.Write32(OP_rte ());
224:
225: // ROM GETC エミュレータ
1.1.1.11! root 226: ms.SetOffset(0x300);
1.1.1.8 root 227: ms.Write32(OP_doscall(r2, r0, DOS_GETCHAR));
228: ms.Write32(OP_jmp (r1));
229:
230: // ROM PUTC エミュレータ
231: // 表示する文字は r3 に置かれている。
1.1.1.11! root 232: ms.SetOffset(0x400);
1.1.1.8 root 233: ms.Write32(OP_doscall(r0, r3, DOS_PUTCHAR));
234: ms.Write32(OP_jmp (r1));
235:
236:
237: // 変なインデントここまで
1.1 root 238:
239: return true;
240: }
241:
1.1.1.5 root 242: // 起動時の処理を行う。
243: // 次段実行ファイルの読み込みに成功すればそのエントリポイントを返す。
244: // そうでなければ 0 を返すので、プロンプトに処理を移すこと。
245: uint32
246: Luna88kPROMEmuDevice::ROM_Init()
1.1 root 247: {
1.1.1.11! root 248: IODeviceStream rs(gRAM);
1.1.1.5 root 249: uint32 entry;
1.1 root 250:
1.1.1.11! root 251: b_entrypoint = 0;
! 252:
1.1.1.5 root 253: // デバイスの初期化 (親クラス)
254: InitDevice();
1.1.1.6 root 255:
1.1.1.5 root 256: // 割り込みマスクで SIO だけ許可
257: gInterrupt->Write32(0x65000000, 0x40000000);
1.1 root 258:
1.1.1.5 root 259: rs.SetAddr(0);
260: // ベクタテーブルを rte で埋めておく
261: for (int i = 0; i < 512 * 2; i++) {
1.1.1.8 root 262: rs.Write32(OP_rte());
1.1.1.5 root 263: }
264: // +$08: 割り込みベクタ
265: rs.Write32(8, 0xc00003fe); // br $00001000
266:
267: // 割り込みトランポリン (0x1000)
268: // ベクタテーブルは各2ワードしかないのに、0 番地付近にあるベクタテーブル
269: // から2ワードでは ROM まで飛べない。一体どういう設計してんだ…。
270: rs.SetAddr(0x1000);
1.1.1.8 root 271: rs.Write32(OP_or_u (r6, r0, 0x4100));
272: rs.Write32(OP_or (r6, r6, 0x0200));
273: rs.Write32(OP_jmp (r6));
1.1.1.2 root 274:
1.1.1.5 root 275: // ROM の機能テーブル
1.1.1.8 root 276: // 0x00001100 ?
277: // 0x00001104 ?
278: // 0x00001108 ?
279: // 0x0000110c GETC() のアドレス
280: // 0x00001110 PUTC(c) のアドレス
1.1.1.5 root 281: // 0x00001114 ビットマッププレーンの有効状態が入っている。
282: // bit0: plane0 有効
283: // bit1..7: plane1..7 有効
284: rs.SetAddr(0x110c);
1.1.1.8 root 285: rs.Write32(0x41000300);
286: rs.Write32(0x41000400);
287: rs.Write32(0x00000001);
1.1.1.5 root 288:
289: // スクリーンを初期化
1.1.1.11! root 290: InitScreen();
1.1.1.5 root 291:
292: entry = 0;
293:
294: // 表示環境が整ったところで NVRAM を照合
295: if (VerifyNVRAM() == false) {
1.1.1.7 root 296: // PROM 1.20 は初期化するかどうか確認してくるけど、とりあえず。
1.1.1.5 root 297: InitNVRAM();
1.1.1.11! root 298: errmsg = "NVRAM Initialized.";
1.1.1.5 root 299: // NVRAM をクリアしたら DIPSW によらずプロンプトに降りる
300: goto done;
301: }
302:
1.1.1.10 root 303: // -X file
304: // DIPSW の状態に関わらず、ファイルをロードし実行する。
305: // --load-only file
306: // DIPSW の状態に関わらず、ファイルをロードし、プロンプトで止まる。
307: if (gMainApp.exec_file) {
308: // ホストのファイルを読み込んでエントリポイントアドレスを
309: // この Read アクセスの読み出し値として返す。
310: // エラーがあればエラーメッセージは呼び出し先側で表示してある。
311: b_entrypoint = LoadHostFile();
312: if (gMainApp.load_and_exec) {
313: entry = b_entrypoint;
314: }
315: } else {
316: // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、
317: // これを真似する。
1.1.1.11! root 318: if (gPIO0->IsDIPSW11Up()) {
1.1.1.5 root 319: // NVRAM の設定に従ってブート先を探す。
320: errmsg.clear();
321:
322: bootinfo_t bootinfo;
323: GetNVRAM(bootinfo);
324: entry = LoadGuestFile(bootinfo);
325: }
326: }
327:
328: done:
329: if (entry == 0) {
1.1.1.11! root 330: PrintTitle("LUNA88K");
! 331: if (errmsg.empty() == false) {
! 332: Print("** %s\n\n", errmsg.c_str());
! 333: }
1.1.1.7 root 334: ClearPrompt();
1.1.1.5 root 335: }
336:
337: return entry;
338: }
339:
340: // ROM 処理。エントリポイントを返す。
341: uint32
342: Luna88kPROMEmuDevice::ROM_Entry()
343: {
344: if (b_entrypoint != 0) {
345: return b_entrypoint;
1.1.1.2 root 346: } else {
1.1.1.5 root 347: return 0;
1.1.1.2 root 348: }
349: }
350:
1.1.1.7 root 351: void
352: Luna88kPROMEmuDevice::GetChar(char asciicode)
353: {
354: if (prompt_idx == 0) {
355: // 行入力モード (画面更新もしてある)
356: inherited::GetChar(asciicode);
357: } else {
358: // 0 以外ならノンブロッキングモード
359:
360: // 入力されたキーを表示
361: if (' ' <= asciicode && asciicode < 0x7f) {
1.1.1.11! root 362: Putc(asciicode);
1.1.1.7 root 363: }
364:
365: switch (prompt_idx) {
366: case PROMPT_NVRAM_UPDATE:
367: CommandNvramUpdate2(asciicode);
368: break;
369:
370: case PROMPT_NVRAM_NEW:
371: CommandNvramNew2(asciicode);
372: break;
373:
374: case PROMPT_NVRAM_INIT:
375: CommandNvramInit2(asciicode);
376: break;
377: }
378:
379: // プロンプトを戻す
380: prompt = default_prompt;
381: prompt_idx = 0;
1.1.1.11! root 382: prompt_y = cursor_y;
! 383: ClearPrompt();
1.1.1.7 root 384: }
385: }
386:
1.1.1.5 root 387: // 入力コマンド処理 (入力行が揃ったところで呼ばれる)。
388: //
389: // b 現在のパラメータで起動
390: // b ... パラメータを指定して起動
391: // nvram 全パラメータを表示
392: // nvram [<name>] name のみ表示?
393: // nvram <name> <val> 値を設定
394: // nvram - <name> 削除
395: // nvram-- NVRAM 初期化
396:
397: void
398: Luna88kPROMEmuDevice::Command()
1.1.1.2 root 399: {
1.1.1.5 root 400: std::vector<char> buf(inputbuf.length() + 1);
401: std::vector<std::string> arg;
1.1.1.2 root 402:
1.1.1.5 root 403: // 1ワードごとに分解
404: strcpy(&buf[0], inputbuf.c_str());
405: char *p = &buf[0];
1.1.1.6 root 406: for (char *ap; (ap = strsep(&p, " ")) != NULL; ) {
407: if (*ap != '\0') {
408: arg.push_back(std::string(ap));
1.1.1.5 root 409: }
410: }
411: if (loglevel >= 1) {
412: for (int i = 0; i < arg.size(); i++) {
413: putmsgn("arg[%d]=|%s|", i, arg[i].c_str());
414: }
415: }
1.1.1.2 root 416:
1.1.1.5 root 417: // 空行
418: if (arg.size() == 0) {
419: return;
420: }
421:
422: // 1ワード目がコマンド
423: if (arg[0] == "h") {
1.1.1.7 root 424: CommandH(arg);
1.1.1.5 root 425: return;
426: }
427: if (arg[0] == "b") {
428: CommandB(arg);
429: return;
430: }
431: if (arg[0] == "nvram") {
432: CommandNvram(arg);
433: return;
1.1.1.2 root 434: }
1.1.1.5 root 435:
1.1.1.11! root 436: Print("** Unknown command: %s\n", arg[0].c_str());
1.1.1.2 root 437: }
438:
1.1.1.7 root 439: // "h" コマンド
440: // 引数なしなら、全体のヘルプメッセージ。
441: // 引数ありなら、個別のヘルプメッセージ。
442: void
443: Luna88kPROMEmuDevice::CommandH(const std::vector<std::string>& arg)
444: {
445: if (arg.size() < 2) {
446: // ヘルプメッセージ
447: mainhelp:
1.1.1.11! root 448: Print(
1.1.1.7 root 449: " *** Help Message ***\n"
450: " b : load and execute program\n"
451: " h : show this message\n"
452: " nvram : show/set nvram parameters\n"
453: );
454: return;
455: }
456:
457: const std::string& key = arg[1];
458: if (key == "nvram") {
1.1.1.11! root 459: Print(
1.1.1.7 root 460: " *** Help Message ***\n"
461: " nvram [<symbol>] : show\n"
462: " nvram <symbol> <value> : set\n"
463: " nvram - <symbol> : delete\n"
464: " nvram -- : initialize\n"
465: );
466: return;
467: } else {
468: goto mainhelp;
469: }
470: }
471:
1.1.1.5 root 472: // "b" コマンド
473: // 引数なしなら NVRAM の情報に従ってプログラムをロードして実行。
474: // 引数ありのほうは未実装。
475: void
476: Luna88kPROMEmuDevice::CommandB(const std::vector<std::string>& arg)
1.1 root 477: {
1.1.1.5 root 478: errmsg.clear();
1.1 root 479:
1.1.1.5 root 480: // XXX とりあえず boot を起動するだけ
481: bootinfo_t bootinfo;
482: GetNVRAM(bootinfo);
483: b_entrypoint = LoadGuestFile(bootinfo);
484: if (b_entrypoint == 0) {
1.1.1.11! root 485: Print("** %s\n", errmsg.c_str());
1.1 root 486: }
1.1.1.5 root 487: }
1.1 root 488:
1.1.1.5 root 489: // "bh" コマンド (勝手に拡張)
1.1.1.8 root 490: // -X オプションで指定されたホストプログラムをロードして実行。
1.1.1.5 root 491: void
492: Luna88kPROMEmuDevice::CommandBH()
493: {
494: // 指定されてたら読み込む
1.1.1.8 root 495: if (gMainApp.exec_file == NULL) {
1.1.1.11! root 496: Print("** Cannot loaded; host program is not specified.\n");
1.1.1.5 root 497: return;
1.1.1.2 root 498: }
1.1.1.5 root 499: b_entrypoint = LoadHostFile();
1.1.1.2 root 500: }
501:
1.1.1.7 root 502: // "nvram" コマンド
503: // nvram .. 全表示
504: // nvram <key> .. 表示
505: // nvram <key> <val> .. 追加/更新
506: // nvram - <key> .. 削除
507: // nvram -- .. 初期化
1.1.1.5 root 508: void
509: Luna88kPROMEmuDevice::CommandNvram(const std::vector<std::string>& arg)
1.1.1.2 root 510: {
1.1.1.7 root 511: switch (arg.size()) {
512: case 1:
513: // 引数なし
514: CommandNvramShowAll();
515: break;
516: case 2:
517: // 引数1つ
518: if (arg[1] == "--") {
519: CommandNvramInit();
520: } else {
521: CommandNvramShow(arg);
522: }
523: break;
524: case 3:
525: // 引数2つ
526: if (arg[1] == "-") {
527: CommandNvramDelete(arg);
528: } else {
529: CommandNvramUpdate(arg);
530: }
531: break;
532: default:
1.1.1.11! root 533: Print("** Syntax error\n");
1.1.1.7 root 534: }
535: }
536:
537: // NVRAM は 32バイトを1エントリとする。
538: // [0] はヘッダに相当し、フォーマットは別記。
539: // [1] 以降が key (16バイト)、val(16バイト) の並び。こんな感じ。
540: //
541: // 00000020 62 6f 6f 74 5f 64 65 76 69 63 65 00 00 00 00 00 |boot_device.....|
542: // 00000030 73 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |sd..............|
543: //
544: // key, val とも '\0' で終端もしくは16文字で終端のようだ。
545: // val に17文字を設定しようとすると怒られる。
546: // key が "" ならこのエントリは空きで val は無視、
547: // 空きエントリは無視して次へ (FAT のディレクトリエントリみたいな感じ)。
548: // val が "" は有効。
549: //
550: // オフセット 0x540 から始まるエントリが最後で、これ以上追加しようとすると
551: // "nvram set error: no area" (PROM 1.20) と言われる。
552: // LUNA88K にはないが LUNA-I では 0x560 にぽつんと ENADDR があったので、
553: // その辺りとの互換性だろうか。
554:
555: // NVRAM 全項目表示
556: void
557: Luna88kPROMEmuDevice::CommandNvramShowAll()
558: {
559: putmsg(1, "nvram ShowAll");
560: for (uint32 offset = 0x20; offset < 0x560; offset += 0x20) {
561: std::string key = nvram->PeekString(offset);
562: if (key.empty()) {
563: continue;
564: }
565: std::string val = nvram->PeekString(offset + 16);
1.1.1.11! root 566: Print("%-15s : %s\n", key.c_str(), val.c_str());
1.1.1.7 root 567: }
568: }
569:
570: // NVRAM 指定項目を表示
571: void
572: Luna88kPROMEmuDevice::CommandNvramShow(const std::vector<std::string>& arg)
573: {
574: assert(arg.size() >= 2);
575: const std::string& key = arg[1];
576:
577: putmsg(1, "nvram Show |%s|", key.c_str());
578: uint32 offset = FindNVRAM(key);
579: if (offset > 0) {
580: std::string val = nvram->PeekString(offset + 16);
1.1.1.11! root 581: Print("%-15s : %s\n", key.c_str(), val.c_str());
1.1.1.7 root 582: } else {
1.1.1.11! root 583: Print("** Not found\n");
1.1.1.7 root 584: }
585: }
586:
587: // NVRAM 項目を追加/更新
588: void
589: Luna88kPROMEmuDevice::CommandNvramUpdate(const std::vector<std::string>& arg)
590: {
591: // キーがあれば更新、なければ追加。
592: // いずれも事前にプロンプトで確認する。
593:
594: assert(arg.size() >= 3);
595: nvram_key = arg[1];
596: nvram_val = arg[2];
597: putmsg(1, "nvram Update |%s|%s|", nvram_key.c_str(), nvram_val.c_str());
598:
599: if (nvram_key.size() > 16) {
1.1.1.11! root 600: Print("** Key too long\n");
1.1.1.7 root 601: return;
602: }
603: if (nvram_val.size() > 16) {
1.1.1.11! root 604: Print("** Val too long\n");
1.1.1.7 root 605: return;
606: }
607:
608: nvram_offset = FindNVRAM(nvram_key);
609: if (nvram_offset > 0) {
610: // キーがすでにあれば更新。
611: // Update2() に申し送りするのは nvram_offset と nvram_val のみでいい。
612:
613: std::string oldval = nvram->PeekString(nvram_offset + 16);
614: prompt = string_format("Update %s : \"%s\" -> \"%s\" (Y/[N]):",
615: nvram_key.c_str(), oldval.c_str(), nvram_val.c_str());
616: prompt_idx = PROMPT_NVRAM_UPDATE;
617: } else {
618: // キーがなければ追加
619: // New2() に申し送りするのは nvram_offset, nvram_key, nvram_val の3つ。
620:
621: // 先に空き領域をチェックしている
622: nvram_offset = FindNVRAM("");
623: if (nvram_offset == 0) {
1.1.1.11! root 624: Print("** No area available\n");
1.1.1.7 root 625: return;
626: }
627:
628: prompt = string_format("Set new %s : \"%s\" (Y/[N]):",
629: nvram_key.c_str(), nvram_val.c_str());
630: prompt_idx = PROMPT_NVRAM_NEW;
631: }
632:
633: // 入力待ちの状態で戻る
634: // (prompt_idx != 0 なのでキー入力後に指定の関数へ飛んで続きを実行する)
635: }
636:
637: // NVRAM 項目を更新 (キー入力後)
638: void
639: Luna88kPROMEmuDevice::CommandNvramUpdate2(char asciicode)
640: {
641: assert(prompt_idx == PROMPT_NVRAM_UPDATE);
642: assert(nvram_offset > 0);
643: assert(nvram_val.size() <= 16);
644:
1.1.1.11! root 645: Putc('\n');
1.1.1.7 root 646:
647: if (asciicode != 'y' && asciicode != 'Y') {
1.1.1.11! root 648: Print("** Not updated\n");
1.1.1.7 root 649: return;
650: }
651:
652: if (nvram->WriteString(nvram_offset + 16, nvram_val) == false) {
1.1.1.11! root 653: Print("** Write error\n");
1.1.1.7 root 654: return;
655: }
656: WriteNVRAMCsum();
657:
1.1.1.11! root 658: Print("Updated\n");
1.1.1.7 root 659: }
660:
661: // NVRAM 項目を追加 (キー入力後)
662: void
663: Luna88kPROMEmuDevice::CommandNvramNew2(char asciicode)
664: {
665: assert(prompt_idx == PROMPT_NVRAM_NEW);
666: assert(nvram_offset > 0);
667: assert(!nvram_key.empty());
668: assert(nvram_key.size() <= 16);
669: assert(nvram_val.size() <= 16);
670:
1.1.1.11! root 671: Putc('\n');
1.1.1.7 root 672:
673: if (asciicode != 'y' && asciicode != 'Y') {
1.1.1.11! root 674: Print("** Not added\n");
1.1.1.7 root 675: return;
676: }
677:
678: if (nvram->WriteString(nvram_offset, nvram_key) == false
679: || nvram->WriteString(nvram_offset + 16, nvram_val) == false) {
1.1.1.11! root 680: Print("** Write error\n");
1.1.1.7 root 681: return;
682: }
683: WriteNVRAMCsum();
684:
1.1.1.11! root 685: Print("Added\n");
1.1.1.2 root 686: }
687:
1.1.1.7 root 688: // NVRAM 項目削除
689: //
690: // 削除する時は確認がないらしい… (PROM 1.20)
691: // 成功しても何も言わないらしい… (PROM 1.20)
692: // 追加削除に比べてなんか雑じゃない?
693: void
694: Luna88kPROMEmuDevice::CommandNvramDelete(const std::vector<std::string>& arg)
695: {
696: assert(arg.size() >= 3);
697: assert(arg[1] == "-");
698: const std::string& key = arg[2];
699: putmsg(1, "nvram Delete |%s|", key.c_str());
700:
701: if (key.size() > 16) {
1.1.1.11! root 702: Print("** key too long\n");
1.1.1.7 root 703: return;
704: }
705:
706: uint32 offset = FindNVRAM(key);
707: if (offset == 0) {
1.1.1.11! root 708: Print("** Not found\n");
1.1.1.7 root 709: return;
710: }
711:
712: // キーを消せば削除になる (値のほうは消してないようだ)
713: nvram->WriteString(offset, "");
714: WriteNVRAMCsum();
715: }
716:
717: // NVRAM から key を探してそのエントリのオフセットを返す。
718: // key == "" なら空きエントリを探す。
719: // 見付からなければ 0 を返す (オフセット 0 はパラメータには使わないため)
720: uint32
721: Luna88kPROMEmuDevice::FindNVRAM(const std::string& key) const
1.1.1.2 root 722: {
1.1.1.7 root 723: for (uint32 offset = 0x20; offset < 0x560; offset += 0x20) {
724: std::string k = nvram->PeekString(offset);
725: if (k == key) {
726: return offset;
727: }
728: // XXX 同じキーが複数あったらどうなるか
729: }
1.1.1.2 root 730: return 0;
731: }
732:
1.1.1.7 root 733: // NVRAM 初期化
1.1.1.5 root 734: void
1.1.1.7 root 735: Luna88kPROMEmuDevice::CommandNvramInit()
1.1.1.2 root 736: {
1.1.1.7 root 737: putmsg(1, "nvram Init");
738:
739: prompt = "Initialize (Y/[N]):";
740: prompt_idx = PROMPT_NVRAM_INIT;
741:
742: // 入力待ちの状態で戻る
1.1.1.2 root 743: }
744:
1.1.1.7 root 745: // NVRAM 初期化 (キー入力後)
746: void
747: Luna88kPROMEmuDevice::CommandNvramInit2(char asciicode)
1.1.1.2 root 748: {
1.1.1.7 root 749: assert(prompt_idx == PROMPT_NVRAM_INIT);
750:
1.1.1.11! root 751: Putc('\n');
1.1.1.7 root 752:
753: if (asciicode != 'y' && asciicode != 'Y') {
1.1.1.11! root 754: Print("** Not initialized\n");
1.1.1.7 root 755: return;
756: }
757:
758: InitNVRAM();
1.1.1.11! root 759: Print("** Initialized\n");
1.1 root 760: }
761:
1.1.1.5 root 762: // NVRAM を初期化する
763: bool
764: Luna88kPROMEmuDevice::InitNVRAM()
1.1 root 765: {
1.1.1.7 root 766: nvram->ClearAll();
767:
768: nvram->WriteString(0x0004, "<nv>");
769: nvram->WriteString(0x0020, "boot_device");
770: nvram->WriteString(0x0030, "sd");
771: nvram->WriteString(0x0040, "boot_spec");
772: nvram->WriteString(0x0050, "0");
773: nvram->WriteString(0x0060, "boot_unit");
774: nvram->WriteString(0x0070, "0");
775: nvram->WriteString(0x0080, "boot_partition");
776: nvram->WriteString(0x0090, "0");
777: nvram->WriteString(0x00a0, "boot_filename");
778: nvram->WriteString(0x00b0, "vmunix");
779: nvram->WriteString(0x00c0, "main_mem_check");
780: nvram->WriteString(0x00d0, "1");
781: nvram->WriteString(0x00e0, "3port_mem_check");
782: nvram->WriteString(0x00f0, "1");
783:
784: // チェックサム再計算
785: WriteNVRAMCsum();
786:
787: return true;
1.1.1.5 root 788: }
1.1 root 789:
1.1.1.5 root 790: // NVRAM のブート設定を bootinfo に取得する。
791: void
792: Luna88kPROMEmuDevice::GetNVRAM(bootinfo_t& bootinfo)
793: {
1.1.1.7 root 794: // dkunit (装置番号) はたぶん boot_unit (0..)
795: // dkpart (パーティション) は boot_partition (0..)
796: // dkfile (ファイル名) は boot_filename
797: // sd 以外のデバイスは未対応
798: bootinfo.dkunit = nvram->Peek(0x0070) - '0';
799: bootinfo.dkpart = nvram->Peek(0x0090) - '0';
800: bootinfo.dkfile = nvram->PeekString(0x00b0);
801: putmsg(1, "%s unit=%d", __func__, bootinfo.dkunit);
802: putmsg(1, "%s part=%c", __func__, bootinfo.dkpart + 'a');
803: putmsg(1, "%s file=|%s|", __func__, bootinfo.dkfile.c_str());
1.1 root 804: }
1.1.1.8 root 805:
806: // コールバック関数 (C のグローバル関数)
807: bool
808: luna88k_fline_callback(m88kcpu *cpu, void *arg)
809: {
810: Luna88kPROMEmuDevice *dev = (Luna88kPROMEmuDevice *)arg;
811: return dev->FLineCallback(cpu);
812: }
813:
814: // コールバック関数 (こっちが実体)
815: bool
816: Luna88kPROMEmuDevice::FLineCallback(m88kcpu *cpu)
817: {
818: // 111111_DDDDDSSSSS_000001_00nnnnnnnn
819: //
820: // 引数は rS1 から順番に格納。
821: // m68k 的なバイト値やワード値の場合は下位詰めしてあるが、不要な上位
822: // ビットの処置はゲストコードよりホストコードで行うほうが楽なので、
823: // すべてこちらで責任持って処理すること。
824: // 戻り値がある DOS call では戻り値は rD に格納。
825:
826: uint32 D = (cpu->opX >> 21) & 0x1f;
827: uint32 S1 = (cpu->opX >> 16) & 0x1f;
828: uint32 num = cpu->opX & 0xff;
829:
830: switch (num) {
831: case 0x00: // _EXIT
832: break;
833:
834: case 0x01: // _GETCHAR
835: cpu->r[D] = getchar();
836: break;
837:
838: case 0x02: // _PUTCHAR
1.1.1.11! root 839: Putc(cpu->r[S1++] & 0xff);
1.1.1.8 root 840: break;
841:
842: default:
843: putlog(0, "未実装 DOS call #$%02x", num);
844: cpu->r[D] = 0xffffffff;
845: break;
846: }
847:
848: // 存在しないコール番号、未実装コールも含めて処理済みとする。
849: return true;
850: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.