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