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