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