--- nono/vm/human68k.cpp 2026/04/29 17:04:28 1.1.1.1 +++ nono/vm/human68k.cpp 2026/04/29 17:05:11 1.1.1.9 @@ -1,22 +1,12 @@ // // nono -// Copyright (C) 2017 Y.Sugahara (moveccr) -// -// human68k .r .x .z console emulator +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "human68k.h" -#include "mpu.h" -#include "m68030bus.h" -#include "m68030core.h" -#include "bus.h" -#include "iodevstream.h" -#include "scheduler.h" -#include "vm.h" -#include -#include -#include -#include +// +// Human68k .r .x .z console emulator +// // メモリマップ // @@ -30,29 +20,43 @@ // 0002'0000 ロードアドレス // 00bf'ffff RAM_END +#include "human68k.h" +#include "autofd.h" +#include "iodevstream.h" +#include "mainapp.h" +#include "m68030bus.h" +#include "m68030core.h" +#include "mpu680x0.h" +#include "scheduler.h" +#include +#include +#include + static bool human68k_fline_callback(m68kcpu *cpu, void *arg); +// グローバル参照用 +Human68k *gHuman68k; + // コンストラクタ -Human68k::Human68k(const char *file, const char *arg) +Human68k::Human68k() + : inherited("Human68k") { - logname = "human68k"; - devname = "Human68k"; - - assert(file); - human68k_file = file; - human68k_arg = arg; + assert(gMainApp.exec_file); + human68k_file = gMainApp.exec_file; + human68k_arg = gMainApp.exec_arg; Files[0].fd = 0; - Files[0].filename = strdup("|stdin"); + Files[0].filename = "|stdin"; Files[1].fd = 1; - Files[1].filename = strdup("|stdout"); + Files[1].filename = "|stdout"; Files[2].fd = 2; - Files[2].filename = strdup("|stderr"); + Files[2].filename = "|stderr"; } // デストラクタ Human68k::~Human68k() { + gHuman68k = NULL; } bool @@ -65,28 +69,28 @@ Human68k::Init() // ショートカット用 ram = gRAM; // Fライン命令をこちらで処理する - gMPU->SetFLineCallback(human68k_fline_callback, this); + gMPU680x0->SetFLineCallback(human68k_fline_callback, this); // ワークを用意 (どこでやるか) // $CBC.B MPU 種別 (3:68030) gRAM->Write8(0x0cbc, 3); // $CBD.B FPU 有無 (0xff:あり) - if (gMPU->HaveFPU()) { + if (gMPU680x0->HaveFPU()) { gRAM->Write8(0x0cbd, 0xff); } - putmsg(1, "arg=%s", human68k_arg); + putmsg(1, "arg=%s", human68k_arg.c_str()); // 実行ファイルオープン - int file_fd = open(human68k_file, O_RDONLY); + autofd file_fd = open(human68k_file, O_RDONLY); if (file_fd == -1) { - warn("open %s", human68k_file); + warn("Human68k executable \"%s\" open failed", human68k_file); return false; } struct stat st; if (fstat(file_fd, &st) != 0) { - warn("fstat %s", human68k_file); + warn("Human68k executable \"%s\" fstat failed", human68k_file); return false; } uint32 file_size; @@ -96,7 +100,7 @@ Human68k::Init() // mmap file = (uint8 *)mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, file_fd, 0); if (file == MAP_FAILED) { - warn("mmap"); + warn("Human68k executable \"%s\" mmap failed", human68k_file); return false; } @@ -108,24 +112,31 @@ Human68k::Init() } else if (isext(human68k_file, ".z")) { r = LoadZ(file, file_size); } else { - if (file[0] == 0x48 && file[1] == 0x55) { - r = LoadX(file, file_size); - } else if (file[0] == 0x60 && file[1] == 0x1a) { - r = LoadZ(file, file_size); - } else { - warnx("Invalid file extension"); - return false; + // ELF .o のロードを試行する + r = LoadELF(file, file_size); + if (!r) { + if (file[0] == 0x48 && file[1] == 0x55) { + r = LoadX(file, file_size); + } else if (file[0] == 0x60 && file[1] == 0x1a) { + r = LoadZ(file, file_size); + } else { + warnx("Human68k executable \"%s\" cannot identify file type", + human68k_file); + munmap(file, file_size); + return false; + } } } if (!r) { - warnx("Invalid file format"); + warnx("Human68k executable \"%s\" invalid file format", human68k_file); + munmap(file, file_size); return false; } munmap(file, file_size); - close(file_fd); uint32 last_addr = load_addr + load_size + bss_size; + int ram_size = ram->GetSize(); IODeviceStream ds(ram); boot_addr = 0x200; @@ -149,6 +160,7 @@ Human68k::Init() break; } } + // XXX: 255文字以上のときどうなるか調べること // PSP (process entry) を書き込む。 // instructiontest.x はコマンドラインを指定するだけで動くようだ @@ -267,7 +279,6 @@ Human68k::LoadX(uint8 *file, uint size) return true; } - bool Human68k::LoadZ(uint8 *file, uint size) { @@ -295,10 +306,29 @@ Human68k::LoadZ(uint8 *file, uint size) return true; } +// なぜか m68k ELF .o が読める +bool +Human68k::LoadELF(uint8 *file, uint size) +{ + uint32 r; + + r = gRAM->LoadFile(human68k_file, file, size); + if (r == 0) { + return false; + } + + // XXX LoadFile は実際のセクションサイズを今は返さないので size は適当 + load_addr = r; + load_size = size; + exec_addr = r; + text_size = size; + return true; +} + bool Human68k::LoadMem(uint32 addr, uint8 *src, uint size) { - if (addr + size > ram_size) { + if (addr + size >= gRAM->GetSize()) { errx(EXIT_FAILURE, "file too large"); } @@ -326,6 +356,13 @@ Human68k::isext(const char *file, const } +// 仮想マシンの中から終了させる +void +Human68k::RequestExit(int code) +{ + gScheduler->Terminate(); +} + // fileaddr: Human68k ファイル名のゲストVA // atr: Human68k atr // mode: unix open mode @@ -335,7 +372,7 @@ Human68k::OpenFile(uint32 fileaddr, uint { // XXX: unix host only - int32 fileno; + int32 fileno {}; Human68k::File *f = NULL; // 開いているエントリを検索して Human fileno を取得 @@ -358,7 +395,9 @@ Human68k::OpenFile(uint32 fileaddr, uint for (int i = 0; i < countof(filename) - 3; i++) { uint8 c = ds.Read8(); - if (c == 0) break; + if (c == 0) { + break; + } if (c < 32 || c >= 127 || c == 0x5c) { p += sprintf(p, "%02X", c); } else { @@ -375,7 +414,7 @@ Human68k::OpenFile(uint32 fileaddr, uint } f->fd = fd; - f->filename = strdup(filename); + f->filename = filename; return fileno; } @@ -391,13 +430,13 @@ Human68k::CloseFile(int32 fileno) return -1; } f = &Files[fileno]; - putmsg(1, "CloseFile: %d %s", fileno, f->filename); + putmsg(1, "CloseFile: %d %s", fileno, f->filename.c_str()); if (f->fd > 2) { // stdin/out/err は閉じない close(f->fd); } f->fd = -1; - free(f->filename); + f->filename.clear(); return 0; } @@ -420,14 +459,12 @@ Human68k::WriteFile(int32 fileno, uint32 } IODeviceStream ds(ram, dataaddr); - uint8 *buf = new uint8[size]; + std::unique_ptr buf(new uint8[size]); for (int i = 0; i < size; i++) { buf[i] = ds.Read8(); } - int32 rv = write(f->fd, buf, size); - - delete[] buf; + int32 rv = write(f->fd, buf.get(), size); return rv; } @@ -449,7 +486,7 @@ Human68k::FputsFile(int32 fileno, uint32 IODeviceStream ds(ram, dataaddr); int size = 1024; - uint8 buf[size]; + std::vector buf(size); bool eof = false; do { @@ -463,7 +500,7 @@ Human68k::FputsFile(int32 fileno, uint32 len++; } if (len > 0) { - write(f->fd, buf, len); + write(f->fd, &buf[0], len); } } while (!eof); } @@ -498,7 +535,7 @@ Human68k::IOCS(m68kcpu *cpu) // MPU 状態の取得 RegD(0) = ((250) << 16) // 25.0MHz - | ((gMPU->HaveFPU() ? 1 : 0) << 15) // FPU + | ((gMPU680x0->HaveFPU() ? 1 : 0) << 15) // FPU | ((0) << 14) // MMU | ((3) << 0); // MPU Type break; @@ -525,7 +562,8 @@ Human68k::IOCS(m68kcpu *cpu) default: printf("Unimplemented IOCS $%02x\n", RegD(0) & 0xff); - exit(1); + RequestExit(1); + break; } } @@ -548,7 +586,8 @@ Human68k::FLineOp(m68kcpu *cpu) case 0xff00: // EXIT putmsg(1, "DOS EXIT"); - exit(0); + RequestExit(0); + break; case 0xff09: // PRINT { @@ -556,7 +595,9 @@ Human68k::FLineOp(m68kcpu *cpu) uint32 dataptr = m68030_read_32(cpu, RegA(7)); do { int c = m68030_read_8(cpu, dataptr++); - if (c == 0) break; + if (c == 0) { + break; + } printf("%c", c); } while (1); RegD(0) = 0; @@ -604,7 +645,7 @@ Human68k::FLineOp(m68kcpu *cpu) vecaddr += 0xd000; RegD(0) = m68030_read_32(cpu, vecaddr); m68030_write_32(cpu, vecaddr, addr); - } + } break; } @@ -715,7 +756,8 @@ Human68k::FLineOp(m68kcpu *cpu) { uint32 data = m68030_read_16(cpu, RegA(7)); putmsg(1, "DOS EXIT2(%d)", data); - exit(data); + RequestExit(data); + break; } case 0xffac: // GETFCB @@ -782,7 +824,8 @@ Human68k::FLineOp(m68kcpu *cpu) default: printf("Unimplemented DOSCALL $%02x at $%08X\n", RegIR, RegPPC); - exit(1); + RequestExit(1); + break; } return true; }