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