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