|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2017 Y.Sugahara (moveccr) ! 4: // ! 5: // human68k .r .x .z console emulator ! 6: // ! 7: ! 8: #include "human68k.h" ! 9: #include "mpu.h" ! 10: #include "m68030bus.h" ! 11: #include "m68030core.h" ! 12: #include "bus.h" ! 13: #include "iodevstream.h" ! 14: #include "scheduler.h" ! 15: #include "vm.h" ! 16: #include <err.h> ! 17: #include <fcntl.h> ! 18: #include <sys/stat.h> ! 19: #include <sys/mman.h> ! 20: ! 21: // メモリマップ ! 22: // ! 23: // 0000'0000 ベクタ ! 24: // 0000'0200 Humanエントリポイント ! 25: // 0000'8000 FCBエリア ! 26: // 0000'c000 コマンドライン引数 ! 27: // 0000'e000 環境変数 ! 28: // 0001'ff00 SSP 初期値 ! 29: // 0001'ff00 PSP(プロセスエントリ) ! 30: // 0002'0000 ロードアドレス ! 31: // 00bf'ffff RAM_END ! 32: ! 33: static bool human68k_fline_callback(m68kcpu *cpu, void *arg); ! 34: ! 35: // コンストラクタ ! 36: Human68k::Human68k(const char *file, const char *arg) ! 37: { ! 38: logname = "human68k"; ! 39: devname = "Human68k"; ! 40: ! 41: assert(file); ! 42: human68k_file = file; ! 43: human68k_arg = arg; ! 44: ! 45: Files[0].fd = 0; ! 46: Files[0].filename = strdup("|stdin"); ! 47: Files[1].fd = 1; ! 48: Files[1].filename = strdup("|stdout"); ! 49: Files[2].fd = 2; ! 50: Files[2].filename = strdup("|stderr"); ! 51: } ! 52: ! 53: // デストラクタ ! 54: Human68k::~Human68k() ! 55: { ! 56: } ! 57: ! 58: bool ! 59: Human68k::Init() ! 60: { ! 61: bool r; ! 62: uint32 psp_base; ! 63: uint8 *file; ! 64: ! 65: // ショートカット用 ! 66: ram = gRAM; ! 67: // Fライン命令をこちらで処理する ! 68: gMPU->SetFLineCallback(human68k_fline_callback, this); ! 69: ! 70: // ワークを用意 (どこでやるか) ! 71: // $CBC.B MPU 種別 (3:68030) ! 72: gRAM->Write8(0x0cbc, 3); ! 73: // $CBD.B FPU 有無 (0xff:あり) ! 74: if (gMPU->HaveFPU()) { ! 75: gRAM->Write8(0x0cbd, 0xff); ! 76: } ! 77: ! 78: putmsg(1, "arg=%s", human68k_arg); ! 79: ! 80: // 実行ファイルオープン ! 81: int file_fd = open(human68k_file, O_RDONLY); ! 82: if (file_fd == -1) { ! 83: warn("open %s", human68k_file); ! 84: return false; ! 85: } ! 86: ! 87: struct stat st; ! 88: if (fstat(file_fd, &st) != 0) { ! 89: warn("fstat %s", human68k_file); ! 90: return false; ! 91: } ! 92: uint32 file_size; ! 93: file_size = (uint32)st.st_size; ! 94: putmsg(1, "file_size=%08x", file_size); ! 95: ! 96: // mmap ! 97: file = (uint8 *)mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, file_fd, 0); ! 98: if (file == MAP_FAILED) { ! 99: warn("mmap"); ! 100: return false; ! 101: } ! 102: ! 103: // 拡張子判別 ! 104: if (isext(human68k_file, ".r")) { ! 105: r = LoadR(file, file_size); ! 106: } else if (isext(human68k_file, ".x")) { ! 107: r = LoadX(file, file_size); ! 108: } else if (isext(human68k_file, ".z")) { ! 109: r = LoadZ(file, file_size); ! 110: } else { ! 111: if (file[0] == 0x48 && file[1] == 0x55) { ! 112: r = LoadX(file, file_size); ! 113: } else if (file[0] == 0x60 && file[1] == 0x1a) { ! 114: r = LoadZ(file, file_size); ! 115: } else { ! 116: warnx("Invalid file extension"); ! 117: return false; ! 118: } ! 119: } ! 120: if (!r) { ! 121: warnx("Invalid file format"); ! 122: return false; ! 123: } ! 124: ! 125: munmap(file, file_size); ! 126: close(file_fd); ! 127: ! 128: uint32 last_addr = load_addr + load_size + bss_size; ! 129: ! 130: IODeviceStream ds(ram); ! 131: boot_addr = 0x200; ! 132: ds.Write32(0, ram_size - 4); // 初期 SSP ! 133: ds.Write32(4, boot_addr); ! 134: ! 135: // TRAP #15 ベクタを書き込む。 ! 136: ds.Write32(0xbc, 0x1000); ! 137: // TRAP #15 ハンドラを書き込む。 ! 138: // エミュレータ内部命令 $f300 で処理して RTE するだけ。 ! 139: ds.Write16(0x1000, 0xf600); // .dw $f300 ! 140: ds.Write16(0x1002, 0x4e73); // rte ! 141: ! 142: // コマンドライン文字列を書き込む。LASCII 形式 ! 143: ds.SetAddr(0xc001); ! 144: for (int i = 0; i < 255; i++) { ! 145: uint8 c = human68k_arg[i]; ! 146: ds.Write8(c); ! 147: if (c == '\0') { ! 148: ds.Write8(0xc000, i); ! 149: break; ! 150: } ! 151: } ! 152: ! 153: // PSP (process entry) を書き込む。 ! 154: // instructiontest.x はコマンドラインを指定するだけで動くようだ ! 155: // PSP はロードアドレス-256 の位置でなければならないようだ。 ! 156: psp_base = 0x1ff00; ! 157: ds.SetAddr(psp_base); ! 158: ! 159: ds.Write32(-1); // 1つ前のメモリ管理ポインタ ! 160: ds.Write32(-1); // このメモリを確保したプロセスのメモリ管理ポインタ ! 161: ds.Write32(ram_size - 4 + 1); // このメモリブロックの終わり+1 のアドレス ! 162: ds.Write32(-1); // 次のメモリ管理ポインタ ! 163: ! 164: ds.Write32(psp_base + 0x20, 0xc000); // コマンドライン ! 165: ! 166: ds.SetAddr(boot_addr); ! 167: ds.Write16(0x2c4f); // move.l a7,a6 ! 168: ds.Write16(0x2e7c); // move.l psp_base,a7 ! 169: ds.Write32(psp_base); ! 170: ds.Write16(0x4e66); // move.l a6,usp ! 171: ds.Write16(0x207c); // move.l psp_base,a0 ! 172: ds.Write32(psp_base); ! 173: ds.Write16(0x227c); // move.l last_addr,a1 ! 174: ds.Write32(last_addr); ! 175: ds.Write16(0x247c); // move.l #$c000,a2 ! 176: ds.Write32(0xc000); ! 177: ds.Write16(0x267c); // move.l #$e000,a3 ! 178: ds.Write32(0xe000); ! 179: ds.Write16(0x287c); // move.l exec_addr,a4 ! 180: ds.Write32(exec_addr); ! 181: ds.Write16(0x2c49); // move.l a1,a6 ! 182: ds.Write16(0x46fc); // move.w #$0700,sr ! 183: ds.Write16(0x0700); ! 184: ds.Write16(0x4eb9); // jsr.l exec_addr ! 185: ds.Write32(exec_addr); ! 186: ds.Write16(0xff00); // DOS _EXIT ! 187: ! 188: putmsg(1, "LoadFile complete"); ! 189: return true; ! 190: } ! 191: ! 192: bool ! 193: Human68k::LoadR(uint8 *file, uint size) ! 194: { ! 195: // リロケータブルなのでどこでもいい ! 196: load_addr = default_load_addr; ! 197: load_size = size; ! 198: LoadMem(load_addr, &file[0], load_size); ! 199: ! 200: // R 形式はファイル先頭が実行開始位置 ! 201: exec_addr = load_addr; ! 202: text_size = load_size; ! 203: putmsg(1, "r format"); ! 204: return true; ! 205: } ! 206: ! 207: bool ! 208: Human68k::LoadX(uint8 *file, uint size) ! 209: { ! 210: XFileHeader *hdr = (XFileHeader *)file; ! 211: uint hdr_size = sizeof(*hdr); ! 212: ! 213: if (!(hdr->magic[0] == 'H' && hdr->magic[1] == 'U')) { ! 214: errx(EXIT_FAILURE, "invalid magic"); ! 215: } ! 216: base_addr = be32toh(hdr->base_addr); ! 217: exec_addr = be32toh(hdr->exec_addr); ! 218: text_size = be32toh(hdr->text_size); ! 219: data_size = be32toh(hdr->data_size); ! 220: bss_size = be32toh(hdr->bss_size); ! 221: ! 222: uint32 reloc_size = be32toh(hdr->reloc_size); ! 223: ! 224: // 最適配置位置も可能だが今回見送り ! 225: load_addr = default_load_addr; ! 226: load_size = text_size + data_size; ! 227: LoadMem(load_addr, &file[hdr_size], load_size); ! 228: ! 229: // 再配置テーブルの file での位置 ! 230: uint32 reloc_pos = hdr_size + load_size; ! 231: ! 232: // 再配置 ! 233: IODeviceStream ds(ram); ! 234: uint32 offset = load_addr - base_addr; ! 235: uint32 reloc_end = reloc_pos + reloc_size; ! 236: uint32 A = load_addr; ! 237: uint32 B = base_addr; ! 238: uint32 C = A - B; ! 239: while (reloc_pos < reloc_end) { ! 240: putlog(1, "reloc_pos=%08x reloc_end=%08x", reloc_pos, reloc_end); ! 241: uint32 D; ! 242: D = be16toh(*(uint16 *)&file[reloc_pos]); ! 243: putlog(1, "D=%x", D); ! 244: reloc_pos += 2; ! 245: if (D == 1) { ! 246: D = be32toh(*(uint32 *)&file[reloc_pos]); ! 247: putlog(1, " odd, D=%x", D); ! 248: reloc_pos += 4; ! 249: } ! 250: if ((D & 1) == 0) { ! 251: A += D; ! 252: uint32 old = ds.Read32(A); ! 253: ds.Write32(A, old + C); ! 254: putlog(1, " Write_L A=%x, old=%x new=%x", A, old, old + C); ! 255: } else { ! 256: A += D - 1; ! 257: uint32 old = ds.Read16(A); ! 258: ds.Write16(A, old + C); ! 259: putlog(1, " Write_W A=%x, old=%x new=%x", A, old, old + C); ! 260: } ! 261: } ! 262: ! 263: exec_addr += offset; ! 264: ! 265: putmsg(1, "x format, base_addr=%08x, exec_addr=%08x", base_addr, exec_addr); ! 266: ! 267: return true; ! 268: } ! 269: ! 270: ! 271: bool ! 272: Human68k::LoadZ(uint8 *file, uint size) ! 273: { ! 274: ZFileHeader *hdr = (ZFileHeader *)file; ! 275: uint32 hdr_size = sizeof(*hdr); ! 276: ! 277: if (be16toh(hdr->magic1) != 0x601a) { ! 278: errx(EXIT_FAILURE, "invalid magic"); ! 279: } ! 280: text_size = be32toh(hdr->text_size); ! 281: data_size = be32toh(hdr->data_size); ! 282: bss_size = be32toh(hdr->bss_size); ! 283: base_addr = be32toh(hdr->base_addr); ! 284: exec_addr = base_addr; ! 285: ! 286: if (base_addr < 0x20000) { ! 287: errx(EXIT_FAILURE, "base, unsupported"); ! 288: } ! 289: ! 290: load_addr = base_addr; ! 291: load_size = text_size + data_size; ! 292: LoadMem(load_addr, &file[hdr_size], load_size); ! 293: ! 294: putmsg(1, "z format, base_addr=%08x, exec_addr=%08x", base_addr, exec_addr); ! 295: return true; ! 296: } ! 297: ! 298: bool ! 299: Human68k::LoadMem(uint32 addr, uint8 *src, uint size) ! 300: { ! 301: if (addr + size > ram_size) { ! 302: errx(EXIT_FAILURE, "file too large"); ! 303: } ! 304: ! 305: IODeviceStream ds(ram, addr); ! 306: for (uint32 i = 0; i < size; i++) { ! 307: ds.Write8(*src++); ! 308: } ! 309: return true; ! 310: } ! 311: ! 312: // file の拡張子が ext なら true を返す。ext は '.' を含む。 ! 313: bool ! 314: Human68k::isext(const char *file, const char *ext) ! 315: { ! 316: size_t len_file = strlen(file); ! 317: size_t len_ext = strlen(ext); ! 318: if (len_ext <= 0) { ! 319: return false; ! 320: } ! 321: if (len_file < len_ext) { ! 322: return false; ! 323: } ! 324: ! 325: return strcasecmp(&file[len_file - len_ext], ext) == 0; ! 326: } ! 327: ! 328: ! 329: // fileaddr: Human68k ファイル名のゲストVA ! 330: // atr: Human68k atr ! 331: // mode: unix open mode ! 332: // return: Human68k fileno ! 333: int32 ! 334: Human68k::OpenFile(uint32 fileaddr, uint16 atr, int mode) ! 335: { ! 336: // XXX: unix host only ! 337: ! 338: int32 fileno; ! 339: Human68k::File *f = NULL; ! 340: ! 341: // 開いているエントリを検索して Human fileno を取得 ! 342: for (int i = 0; i < FilesCount; i++) { ! 343: if (Files[i].fd == -1) { ! 344: fileno = i; ! 345: f = &Files[fileno]; ! 346: break; ! 347: } ! 348: } ! 349: if (f == NULL) { ! 350: return -1; ! 351: } ! 352: ! 353: char filename[256]; ! 354: char *p = filename; ! 355: ! 356: // ファイル名変換 ! 357: IODeviceStream ds(ram, fileaddr); ! 358: for (int i = 0; i < countof(filename) - 3; i++) { ! 359: uint8 c = ds.Read8(); ! 360: ! 361: if (c == 0) break; ! 362: if (c < 32 || c >= 127 || c == 0x5c) { ! 363: p += sprintf(p, "%02X", c); ! 364: } else { ! 365: *p++ = c; ! 366: } ! 367: } ! 368: *p = '\0'; ! 369: ! 370: putmsg(1, "OpenFile: %d %s", fileno, filename); ! 371: int fd = open(filename, mode, 0666); ! 372: if (fd == -1) { ! 373: warn("OpenFile.open"); ! 374: return -1; ! 375: } ! 376: ! 377: f->fd = fd; ! 378: f->filename = strdup(filename); ! 379: ! 380: return fileno; ! 381: } ! 382: ! 383: // fileno: Human68k fileno ! 384: int32 ! 385: Human68k::CloseFile(int32 fileno) ! 386: { ! 387: Human68k::File *f; ! 388: ! 389: if (fileno <= 0 || fileno >= FilesCount) { ! 390: warnx("CloseFile: unopened fileno=%d", fileno); ! 391: return -1; ! 392: } ! 393: f = &Files[fileno]; ! 394: putmsg(1, "CloseFile: %d %s", fileno, f->filename); ! 395: if (f->fd > 2) { ! 396: // stdin/out/err は閉じない ! 397: close(f->fd); ! 398: } ! 399: f->fd = -1; ! 400: free(f->filename); ! 401: return 0; ! 402: } ! 403: ! 404: // fileno: Human68k fileno ! 405: // dataaddr: data addr (guest VA) ! 406: // size: data length ! 407: int32 ! 408: Human68k::WriteFile(int32 fileno, uint32 dataaddr, uint32 size) ! 409: { ! 410: Human68k::File *f; ! 411: ! 412: if (fileno <= 0 || fileno >= FilesCount) { ! 413: warnx("WriteFile: unopened fileno=%d", fileno); ! 414: return -1; ! 415: } ! 416: ! 417: f = &Files[fileno]; ! 418: if (f->fd < 0) { ! 419: return -1; ! 420: } ! 421: ! 422: IODeviceStream ds(ram, dataaddr); ! 423: uint8 *buf = new uint8[size]; ! 424: for (int i = 0; i < size; i++) { ! 425: buf[i] = ds.Read8(); ! 426: } ! 427: ! 428: int32 rv = write(f->fd, buf, size); ! 429: ! 430: delete[] buf; ! 431: return rv; ! 432: } ! 433: ! 434: // fileno: Human68k fileno ! 435: // dataaddr: data addr (guest VA) ! 436: void ! 437: Human68k::FputsFile(int32 fileno, uint32 dataaddr) ! 438: { ! 439: Human68k::File *f; ! 440: ! 441: if (fileno <= 0 || fileno >= FilesCount) { ! 442: return; ! 443: } ! 444: ! 445: f = &Files[fileno]; ! 446: if (f->fd < 0) { ! 447: return; ! 448: } ! 449: ! 450: IODeviceStream ds(ram, dataaddr); ! 451: int size = 1024; ! 452: uint8 buf[size]; ! 453: bool eof = false; ! 454: ! 455: do { ! 456: int len = 0; ! 457: for (int i = 0; i < size; i++) { ! 458: buf[i] = ds.Read8(); ! 459: if (buf[i] == 0) { ! 460: eof = true; ! 461: break; ! 462: } ! 463: len++; ! 464: } ! 465: if (len > 0) { ! 466: write(f->fd, buf, len); ! 467: } ! 468: } while (!eof); ! 469: } ! 470: ! 471: ! 472: // Human68k DOSCALL Host Emulation ! 473: ! 474: void ! 475: Human68k::IOCS(m68kcpu *cpu) ! 476: { ! 477: switch (RegD(0) & 0xff) { ! 478: case 0x7f: // _ONTIME ! 479: { ! 480: putmsg(1, "IOCS ONTIME"); ! 481: uint64 t = gScheduler->GetVirtTime(); ! 482: // nanosec to 10msec, in day ! 483: RegD(0) = (t / 10_msec) % 8640000; ! 484: // nanosec to day ! 485: RegD(1) = t / 86400_sec; ! 486: break; ! 487: } ! 488: case 0x82: // _B_BPEEK ! 489: { ! 490: uint32 data = m68030_read_8(cpu, RegA(1)); ! 491: RegD(0) = (RegD(0) & 0xffffff00) | data; ! 492: RegA(1)++; ! 493: break; ! 494: } ! 495: case 0xac: // _SYS_STAT (ROM1.3) ! 496: switch (RegD(1)) { ! 497: case 0: ! 498: // MPU 状態の取得 ! 499: RegD(0) = ! 500: ((250) << 16) // 25.0MHz ! 501: | ((gMPU->HaveFPU() ? 1 : 0) << 15) // FPU ! 502: | ((0) << 14) // MMU ! 503: | ((3) << 0); // MPU Type ! 504: break; ! 505: case 1: ! 506: // キャッシュ状態の取得 ! 507: RegD(0) = 0; ! 508: break; ! 509: case 2: ! 510: // キャッシュを SRAM の設定値に設定 ! 511: RegD(0) = 0; ! 512: break; ! 513: case 3: ! 514: // キャッシュの消去 ! 515: RegD(0) = 0; ! 516: break; ! 517: case 4: ! 518: // キャッシュの設定 ! 519: RegD(0) = 0; ! 520: break; ! 521: default: ! 522: break; ! 523: } ! 524: break; ! 525: ! 526: default: ! 527: printf("Unimplemented IOCS $%02x\n", RegD(0) & 0xff); ! 528: exit(1); ! 529: } ! 530: } ! 531: ! 532: // F-Line 命令をこちらで処理する ! 533: bool ! 534: human68k_fline_callback(m68kcpu *cpu, void *arg) ! 535: { ! 536: auto *human68k = (Human68k *)arg; ! 537: return human68k->FLineOp(cpu); ! 538: } ! 539: ! 540: // F-Line 命令 ! 541: bool ! 542: Human68k::FLineOp(m68kcpu *cpu) ! 543: { ! 544: switch (RegIR) { ! 545: case 0xf600: // IOCS call emulation ! 546: IOCS(cpu); ! 547: break; ! 548: ! 549: case 0xff00: // EXIT ! 550: putmsg(1, "DOS EXIT"); ! 551: exit(0); ! 552: ! 553: case 0xff09: // PRINT ! 554: { ! 555: // STDOUT ! 556: uint32 dataptr = m68030_read_32(cpu, RegA(7)); ! 557: do { ! 558: int c = m68030_read_8(cpu, dataptr++); ! 559: if (c == 0) break; ! 560: printf("%c", c); ! 561: } while (1); ! 562: RegD(0) = 0; ! 563: break; ! 564: } ! 565: ! 566: case 0xff1e: // FPUTS ! 567: { ! 568: uint32 mesptr = m68030_read_32(cpu, RegA(7)); ! 569: uint16 fileno = m68030_read_16(cpu, RegA(7) + 4); ! 570: FputsFile(fileno, mesptr); ! 571: break; ! 572: } ! 573: ! 574: case 0xff20: // SUPER ! 575: { ! 576: uint32 data = m68030_read_32(cpu, RegA(7)); ! 577: ! 578: if (data == 0) { ! 579: m68030_set_sr(cpu, RegSR | 0x2000); ! 580: data = RegUSP; ! 581: RegD(0) = RegA(7); ! 582: RegA(7) = data; ! 583: putmsg(1, "SUPERVISOR MODE"); ! 584: } else { ! 585: m68030_set_sr(cpu, RegSR | 0x2000); ! 586: RegA(7) = data; ! 587: m68030_set_sr(cpu, RegSR & ~0x2000); ! 588: putmsg(1, "USER MODE"); ! 589: } ! 590: break; ! 591: } ! 592: ! 593: case 0xff25: // INTVCS ! 594: { ! 595: uint16 intno = m68030_read_16(cpu, RegA(7)); ! 596: uint32 addr = m68030_read_32(cpu, RegA(7) + 2); ! 597: ! 598: uint32 vecaddr = (intno & 0xff) * 4; ! 599: ! 600: if (intno <= 0xff) { ! 601: RegD(0) = m68030_read_32(cpu, vecaddr); ! 602: m68030_write_32(cpu, vecaddr, addr); ! 603: } else { ! 604: vecaddr += 0xd000; ! 605: RegD(0) = m68030_read_32(cpu, vecaddr); ! 606: m68030_write_32(cpu, vecaddr, addr); ! 607: } ! 608: break; ! 609: } ! 610: ! 611: case 0xff27: // GETTIM2 ! 612: { ! 613: // DUMMY ! 614: RegD(0) = 0; ! 615: break; ! 616: } ! 617: ! 618: case 0xff2a: // GETDATE ! 619: { ! 620: // DUMMY ! 621: RegD(0) = 0; ! 622: break; ! 623: } ! 624: ! 625: case 0xff30: // VERNUM ! 626: { ! 627: RegD(0) = 0x36380302; // ver3.02 ! 628: break; ! 629: } ! 630: ! 631: case 0xff35: // INTVCG ! 632: { ! 633: uint16 intno = m68030_read_16(cpu, RegA(7)); ! 634: ! 635: uint32 vecaddr = (intno & 0xff) * 4; ! 636: ! 637: if (intno <= 0xff) { ! 638: RegD(0) = m68030_read_32(cpu, vecaddr); ! 639: } else { ! 640: vecaddr += 0xd000; ! 641: RegD(0) = m68030_read_32(cpu, vecaddr); ! 642: } ! 643: break; ! 644: } ! 645: ! 646: case 0xff3c: // CREATE ! 647: { ! 648: uint32 file = m68030_read_32(cpu, RegA(7)); ! 649: uint16 atr = m68030_read_32(cpu, RegA(7) + 4); ! 650: ! 651: int32 fileno = OpenFile(file, atr, ! 652: O_CREAT | O_TRUNC | O_RDWR | O_SYNC); ! 653: RegD(0) = fileno; ! 654: break; ! 655: } ! 656: ! 657: case 0xff3e: // CLOSE ! 658: { ! 659: uint16 fileno = m68030_read_16(cpu, RegA(7)); ! 660: ! 661: CloseFile(fileno); ! 662: RegD(0) = 0; ! 663: break; ! 664: } ! 665: ! 666: case 0xff40: // WRITE ! 667: { ! 668: // putmsg(1, "DOS _WRITE at %08x", RegPPC); ! 669: uint16 fileno = m68030_read_16(cpu, RegA(7)); ! 670: uint32 dataptr = m68030_read_32(cpu, RegA(7) + 2); ! 671: uint32 size = m68030_read_32(cpu, RegA(7) + 6); ! 672: // putmsg(1, "WRITE(%d, 0x%08x, 0x%08x)\n", fileno, dataptr, size); ! 673: RegD(0) = WriteFile(fileno, dataptr, size); ! 674: break; ! 675: } ! 676: ! 677: case 0xff44: // IOCTRL ! 678: { ! 679: uint32 mode = m68030_read_16(cpu, RegA(7)); ! 680: uint32 fileno; ! 681: switch (mode) { ! 682: case 0: ! 683: fileno = m68030_read_16(cpu, RegA(7) + 2); ! 684: putmsg(1, "DOS IOCTRL(mode=%d, fileno=%d)", mode, fileno); ! 685: if (fileno == 0) { // STDIN ! 686: RegD(0) = 0x8081; // 100u'uuuu'100u'0001; ! 687: break; ! 688: } else if (fileno == 1) { // STDOUT ! 689: RegD(0) = 0x8082; // 100u'uuuu'100u'0010; ! 690: break; ! 691: } else if (fileno == 2) { // STDERR ! 692: RegD(0) = 0x8081; // 100u'uuuu'100u'0001; ! 693: break; ! 694: } else { ! 695: RegD(0) = -1; ! 696: } ! 697: break; ! 698: default: ! 699: errx(EXIT_FAILURE, "DOS IOCTRL(mode=%d) not impl.", mode); ! 700: } ! 701: break; ! 702: } ! 703: ! 704: case 0xff4a: // SETBLOCK ! 705: { ! 706: uint32 memptr = m68030_read_32(cpu, RegA(7)); ! 707: uint32 len = m68030_read_32(cpu, RegA(7) + 4); ! 708: putmsg(1, "DOS SETBLOCK(memptr=$%x len=$%x)", memptr, len); ! 709: // なにもせずに、できたという ! 710: RegD(0) = m68030_read_32(cpu, RegA(7) + 4); ! 711: break; ! 712: } ! 713: ! 714: case 0xff4c: // EXIT2 ! 715: { ! 716: uint32 data = m68030_read_16(cpu, RegA(7)); ! 717: putmsg(1, "DOS EXIT2(%d)", data); ! 718: exit(data); ! 719: } ! 720: ! 721: case 0xffac: // GETFCB ! 722: { ! 723: uint32 fileno = m68030_read_16(cpu, RegA(7)); ! 724: putmsg(1, "DOS GETFCB(fileno=%d)", fileno); ! 725: if (fileno <= 4) { ! 726: RegD(0) = 0x8000 + fileno * 0x60; ! 727: } else { ! 728: RegD(0) = -1; ! 729: } ! 730: break; ! 731: } ! 732: ! 733: case 0xfff7: // BUS_ERR ! 734: { ! 735: uint32 p1 = m68030_read_32(cpu, RegA(7)); ! 736: uint32 p2 = m68030_read_32(cpu, RegA(7) + 4); ! 737: uint16 size = m68030_read_16(cpu, RegA(7) + 8); ! 738: putmsg(1, "DOS BUS_ERR(size=%d p1=$%x p2=$%x)", size, p1, p2); ! 739: ! 740: RegD(0) = -1; ! 741: uint32 data; ! 742: try { ! 743: if (size == 1) { ! 744: data = m68030_read_8(cpu, p1); ! 745: } else if (size == 2 && ((p1 & 1) == 0)) { ! 746: data = m68030_read_16(cpu, p1); ! 747: } else if (size == 4 && ((p1 & 1) == 0)) { ! 748: data = m68030_read_32(cpu, p1); ! 749: } else { ! 750: break; ! 751: } ! 752: } catch (int cause) { ! 753: if (cause == M68K_EXCEP_BUSERR) { ! 754: RegD(0) = 2; ! 755: break; ! 756: } else { ! 757: throw; ! 758: } ! 759: } ! 760: ! 761: try { ! 762: if (size == 1) { ! 763: m68030_write_8(cpu, p2, data); ! 764: } else if (size == 2 && ((p2 & 1) == 0)) { ! 765: m68030_write_16(cpu, p2, data); ! 766: } else if (size == 4 && ((p2 & 1) == 0)) { ! 767: m68030_write_32(cpu, p2, data); ! 768: } else { ! 769: break; ! 770: } ! 771: } catch (int cause) { ! 772: if (cause == M68K_EXCEP_BUSERR) { ! 773: RegD(0) = 1; ! 774: break; ! 775: } else { ! 776: throw; ! 777: } ! 778: } ! 779: RegD(0) = 0; ! 780: break; ! 781: } ! 782: ! 783: default: ! 784: printf("Unimplemented DOSCALL $%02x at $%08X\n", RegIR, RegPPC); ! 785: exit(1); ! 786: } ! 787: return true; ! 788: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.