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