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