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