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