--- nono/vm/msxdos.cpp 2026/04/29 17:05:17 1.1 +++ nono/vm/msxdos.cpp 2026/04/29 17:05:29 1.1.1.4 @@ -59,25 +59,25 @@ MSXDOSDevice::Init() // MemoryStreamBE ms(imagebuf.get()); ms.SetOffset(0); - ms.Write32(0x00002000); // +00: リセットベクタ SP - ms.Write32(0x41000402); // +04: リセットベクタ PC + ms.Write4(0x00002000); // +00: リセットベクタ SP + ms.Write4(0x41000402); // +04: リセットベクタ PC // 全ベクタを RTE に向ける for (int i = 8; i < 0x400; i += 4) { - ms.Write32(0x41000000); + ms.Write4(0x41000000); } ms.SetOffset(0x400); //all_handler: - ms.Write16(0x4e73); // rte + ms.Write2(0x4e73); // rte // ここからリセット時に実行する命令 - ms.Write16(0x41f9); // lea.l $49000000,a0 - ms.Write32(0x49000000); - ms.Write16(0x117c); // move.b #$b6,3(a0) ; SetMode - ms.Write32(0x00b60003); - ms.Write16(0x117c); // move.b #$0f,3(a0) ; XPRESET <- %1 - ms.Write32(0x000f0003); - ms.Write16(0x117c); // move.b #$0e,3(a0) ; XPRESET <- %0 - ms.Write32(0x000e0003); - ms.Write32(0x4e722700); //@:stop #0x2700 - ms.Write16(0x60fa); // bra @b + ms.Write2(0x41f9); // lea.l $49000000,a0 + ms.Write4(0x49000000); + ms.Write2(0x117c); // move.b #$b6,3(a0) ; SetMode + ms.Write4(0x00b60003); + ms.Write2(0x117c); // move.b #$0f,3(a0) ; XPRESET <- %1 + ms.Write4(0x000f0003); + ms.Write2(0x117c); // move.b #$0e,3(a0) ; XPRESET <- %0 + ms.Write4(0x000e0003); + ms.Write4(0x4e722700); //@:stop #0x2700 + ms.Write2(0x60fa); // bra @b // // SubRAM に XP 用ファームウェアを書き込む。 @@ -92,118 +92,108 @@ MSXDOSDevice::Init() const uint16 _msg_trap = 0x7050; // リセットベクタ - xs.SetAddr(0x0000); - xs.Write8(0xc3); // 0000: JP _rominit - xs.Write16LE(_rominit); - xs.Write16(0x0000); // 0003: 00,00 - xs.Write8(0xc3); // 0005: JP _doscall - xs.Write16LE(_doscall); + xs.SetOffset(0x0000); + xs.Write1(0xc3); // 0000: JP _rominit + xs.Write2LE(_rominit); + xs.Write2(0x0000); // 0003: 00,00 + xs.Write1(0xc3); // 0005: JP _doscall + xs.Write2LE(_doscall); // ここから ROM。 // CP/M は 0005H の飛び先がワークの先頭らしく、ここより前を // SP として使っているらしいので、先頭に DOSCALL ハンドラを用意。 // DOSCALL ハンドラ。 - xs.SetAddr(_doscall); - xs.Write8(0x79); // 7000: LD A,C - xs.Write8(0xb7); // 7001: OR A - xs.Write8(0xca); // 7002: JP Z,_term + 2 - xs.Write16LE(_term + 2); - xs.Write16(0xedff); // 7005: SYSCALL - xs.Write8(0xc9); // 7007: RET + xs.SetOffset(_doscall); + xs.Write1(0x79); // 7000: LD A,C + xs.Write1(0xb7); // 7001: OR A + xs.Write1(0xca); // 7002: JP Z,_term + 2 + xs.Write2LE(_term + 2); + xs.Write2(0xedff); // 7005: SYSCALL + xs.Write1(0xc9); // 7007: RET // TERM - xs.SetAddr(_term); - xs.Write16(0x0e00); // 7010: LD C,00H - xs.Write16(0xedff); // 7012: SYSCALL - xs.Write8(0x76); // 7014: HALT - xs.Write8(0x18fd); // 7015: JR 7014H ; 念のため + xs.SetOffset(_term); + xs.Write2(0x0e00); // 7010: LD C,00H + xs.Write2(0xedff); // 7012: SYSCALL + xs.Write1(0x76); // 7014: HALT + xs.Write2(0x18fd); // 7015: JR 7014H ; 念のため // トラップハンドラ。メッセージを出して終了。 - xs.SetAddr(_trap_handler); - xs.Write8(0x11); // 7020: LD DE,msg_trap - xs.Write16LE(_msg_trap); - xs.Write16(0x0e09); // 7023: LD C,09H - xs.Write16(0xedff); // 7025: SYSCALL - xs.Write8(0xc3); // 7026: JP _term - xs.Write16LE(_term); + xs.SetOffset(_trap_handler); + xs.Write1(0x11); // 7020: LD DE,msg_trap + xs.Write2LE(_msg_trap); + xs.Write2(0x0e09); // 7023: LD C,09H + xs.Write2(0xedff); // 7025: SYSCALL + xs.Write1(0xc3); // 7026: JP _term + xs.Write2LE(_term); // XP 側の初期化ルーチン。 // 0000H 番地をトラップハンドラに向け変えて、 // 0100H にジャンプ。戻ってきたら終了。 - xs.SetAddr(_rominit); - xs.Write16(0x3e3c); // 7030: LD A,3CH - xs.Write16(0xed39); // 7032: OUT0 (36H),A - xs.Write8(0x36); - xs.Write8(0x21); // 7035: LD HL,_trap_handler - xs.Write16LE(_trap_handler); - xs.Write8(0x22); // 7038: LD (0001H),HL - xs.Write16LE(0x0001); - xs.Write8(0xcd); // 703b: CALL 0100H - xs.Write16LE(0x0100); - xs.Write8(0xc3); // 703e: JP _term - xs.Write16LE(_term); + xs.SetOffset(_rominit); + xs.Write2(0x3e3c); // 7030: LD A,3CH + xs.Write2(0xed39); // 7032: OUT0 (36H),A + xs.Write1(0x36); + xs.Write1(0x21); // 7035: LD HL,_trap_handler + xs.Write2LE(_trap_handler); + xs.Write1(0x22); // 7038: LD (0001H),HL + xs.Write2LE(0x0001); + xs.Write1(0xcd); // 703b: CALL 0100H + xs.Write2LE(0x0100); + xs.Write1(0xc3); // 703e: JP _term + xs.Write2LE(_term); // msg_trap - xs.SetAddr(_msg_trap); + xs.SetOffset(_msg_trap); xs.WriteString("trap occured!\x0d\x0a$"); // 実行ファイルオープン - const char *exec_file = gMainApp.exec_file; - data_t src = LoadBinary(exec_file); - if (src.data == NULL) { + std::vector src; + if (LoadBinary(gMainApp.exec_file, src) == false) { return false; } // コピー - if (src.size >= 0x7000 - 0x100) { - src.size = 0x7000 - 0x100; + xs.SetOffset(0x100); + for (auto s : src) { + xs.Write1(s); } - xs.SetAddr(0x100); - for (int i = 0; i < src.size; i++) { - xs.Write8(src.data[i]); - } - - delete[] src.data; return true; } -// filename を data_t にロードする。 -// 成功すれば data_t を埋めて返す。 -// その場合 data_t.data は new[] してあるので呼び出し側で delete[] すること。 -// 失敗すればエラーメッセージを表示し、data_t.data = NULL を返す。 +// filename で示されるファイルをロードする。 +// 成功すれば data に格納して true を返す。 +// 失敗すればエラーメッセージを表示し、false を返す。 // サポートしているのは // o z80-asm の出力する .z80 形式 // o MSX-DOS の .COM 形式 (生バイナリ) -MSXDOSDevice::data_t -MSXDOSDevice::LoadBinary(const char *filename) +bool +MSXDOSDevice::LoadBinary(const char *filename, std::vector& dst) { struct stat st; - data_t dl; + size_t dlsize; char header[10]; autofd fd; int r; - dl.data = NULL; - dl.size = 0; - fd = open(filename, O_RDONLY); if (fd < 0) { warn("\"%s\" open failed", filename); - return dl; + return false; } r = fstat(fd, &st); if (r < 0) { warn("\"%s\" fstat failed", filename); - return dl; + return false; } r = read(fd, header, sizeof(header)); if (r < 0) { warn("\"%s\" read(header) failed", filename); - return dl; + return false; } if (r < sizeof(header)) { warnx("\"%s\" read(header): %d: too short", filename, r); @@ -211,48 +201,42 @@ MSXDOSDevice::LoadBinary(const char *fil if (strncmp(header, "Z80ASM\x1a\x0a", 8) == 0) { // .z80 形式。先頭 10 バイトがヘッダ。 - dl.size = st.st_size - 10; + dlsize = st.st_size - 10; } else { // そうでなければ今の所 .COM 形式。ヘッダなしの生バイナリ。 - dl.size = st.st_size; + dlsize = st.st_size; if (lseek(fd, 0, SEEK_SET) < 0) { warn("\"%s\" lseek(0) failed", filename); - return dl; + return false; } } - try { - dl.data = new uint8 [dl.size]; - } catch (...) { - dl.data = NULL; - warnx("Could not allocate memory %d", dl.size); - return dl; + // サイズ制限 + if (dlsize >= 0x7000 - 0x100) { + errno = EFBIG; + warn("%s", filename); + return false; } - r = read(fd, dl.data, dl.size); + dst.resize(dlsize); + r = read(fd, dst.data(), dst.size()); if (r < 0) { warn("\%s\" read failed", filename); - goto abort; + return false; } - if (r < dl.size) { + if (r < dlsize) { warn("\%s\" read: %d: too short", filename, r); - goto abort; + return false; } - return dl; - - abort: - delete[] dl.data; - dl.data = NULL; - dl.size = 0; - return dl; + return true; } // コールバック入口のグローバル関数 void msxdos_callback(void *arg) { - auto msxdosdev = (MSXDOSDevice *)arg; + auto *msxdosdev = reinterpret_cast(arg); msxdosdev->Syscall(); } @@ -263,7 +247,7 @@ MSXDOSDevice::Syscall() switch (xp->reg.c) { case 0x00: // _TERM putmsg(1, "DOS _TERM"); - Human68k::RequestExit(0); + Human68kDevice::RequestExit(0); break; case 0x02: // _PUTC @@ -275,7 +259,7 @@ MSXDOSDevice::Syscall() { uint16 de = xp->reg.GetDE(); uint8 ch; - for (; (ch = xp->Read8(de)) != '$'; de++) { + for (; (ch = xp->Read1(de)) != '$'; de++) { putchar(ch); } fflush(stdout);