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