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