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