Annotation of nono/vm/human68k.cpp, revision 1.1.1.18

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"
1.1.1.17  root       25: #include "event.h"
1.1.1.9   root       26: #include "iodevstream.h"
                     27: #include "mainapp.h"
1.1.1.11  root       28: #include "mainbus.h"
1.1.1.12  root       29: #include "mainram.h"
1.1.1.9   root       30: #include "mpu680x0.h"
1.1.1.11  root       31: #include "power.h"
1.1.1.9   root       32: #include "scheduler.h"
                     33: #include <fcntl.h>
1.1.1.13  root       34: #include <time.h>
1.1.1.9   root       35: #include <sys/stat.h>
                     36: #include <sys/mman.h>
                     37: 
1.1.1.11  root       38: static bool human68k_fline_callback(MPU680x0Device *, void *arg);
1.1       root       39: 
1.1.1.12  root       40: #define RegD(n)        mpu680x0->reg.D[n]
                     41: #define RegA(n)        mpu680x0->reg.A[n]
1.1.1.9   root       42: 
1.1       root       43: // コンストラクタ
1.1.1.12  root       44: Human68kDevice::Human68kDevice()
1.1.1.11  root       45:        : inherited(OBJ_HUMAN68K)
1.1       root       46: {
                     47:        Files[0].fd = 0;
1.1.1.4   root       48:        Files[0].filename = "|stdin";
1.1       root       49:        Files[1].fd = 1;
1.1.1.4   root       50:        Files[1].filename = "|stdout";
1.1       root       51:        Files[2].fd = 2;
1.1.1.4   root       52:        Files[2].filename = "|stderr";
1.1       root       53: }
                     54: 
                     55: // デストラクタ
1.1.1.12  root       56: Human68kDevice::~Human68kDevice()
1.1       root       57: {
                     58: }
                     59: 
1.1.1.11  root       60: // 初期化
1.1       root       61: bool
1.1.1.12  root       62: Human68kDevice::Init()
1.1       root       63: {
                     64:        uint32 psp_base;
                     65:        uint8 *file;
1.1.1.13  root       66:        uint32 last_addr;
1.1.1.16  root       67:        uint32 ram_size;
1.1       root       68: 
1.1.1.12  root       69:        assert(gMainApp.exec_file);
                     70:        human68k_file = gMainApp.exec_file;
                     71:        human68k_arg = gMainApp.exec_arg;
                     72: 
                     73:        mainbus = GetMainbusDevice();
1.1.1.13  root       74:        mainram = GetMainRAMDevice();
1.1.1.12  root       75:        mpu680x0 = GetMPU680x0Device(mpu);
1.1.1.11  root       76: 
1.1.1.13  root       77:        // Fライン命令をこちらで処理する。
1.1.1.12  root       78:        mpu680x0->SetFLineCallback(human68k_fline_callback, this);
1.1       root       79: 
1.1.1.13  root       80:        IODeviceStream ds(mainram);
                     81: 
                     82:        // ワークを用意 (どこでやるか)。
1.1       root       83:        // $CBC.B MPU 種別 (3:68030)
1.1.1.13  root       84:        ds.Write1(0x0cbc, 3);
                     85:        // $CBD.B FPU 有無 (0xff:あり)。
1.1.1.14  root       86:        if (mpu680x0->HasFPU()) {
1.1.1.13  root       87:                ds.Write1(0x0cbd, 0xff);
1.1       root       88:        }
                     89: 
1.1.1.8   root       90:        putmsg(1, "arg=%s", human68k_arg.c_str());
1.1       root       91: 
1.1.1.13  root       92:        // 実行ファイルオープン。
1.1.1.6   root       93:        autofd file_fd = open(human68k_file, O_RDONLY);
1.1       root       94:        if (file_fd == -1) {
1.1.1.2   root       95:                warn("Human68k executable \"%s\" open failed", human68k_file);
1.1       root       96:                return false;
                     97:        }
                     98: 
                     99:        struct stat st;
                    100:        if (fstat(file_fd, &st) != 0) {
1.1.1.2   root      101:                warn("Human68k executable \"%s\" fstat failed", human68k_file);
1.1       root      102:                return false;
                    103:        }
                    104:        uint32 file_size;
                    105:        file_size = (uint32)st.st_size;
                    106:        putmsg(1, "file_size=%08x", file_size);
                    107: 
                    108:        // mmap
                    109:        file = (uint8 *)mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, file_fd, 0);
                    110:        if (file == MAP_FAILED) {
1.1.1.2   root      111:                warn("Human68k executable \"%s\" mmap failed", human68k_file);
1.1       root      112:                return false;
                    113:        }
                    114: 
1.1.1.13  root      115:        // 拡張子判別。
1.1       root      116:        if (isext(human68k_file, ".r")) {
1.1.1.13  root      117:                if (LoadR(file, file_size) == false) {
                    118:                        goto abort;
                    119:                }
1.1       root      120:        } else if (isext(human68k_file, ".x")) {
1.1.1.13  root      121:                if (LoadX(file, file_size) == false) {
                    122:                        goto abort;
                    123:                }
1.1       root      124:        } else if (isext(human68k_file, ".z")) {
1.1.1.13  root      125:                if (LoadZ(file, file_size) == false) {
                    126:                        goto abort;
                    127:                }
1.1       root      128:        } else {
1.1.1.13  root      129:                // ELF .o のロードを試行する。
                    130:                if (LoadELF(file, file_size) == false) {
1.1.1.7   root      131:                        if (file[0] == 0x48 && file[1] == 0x55) {
1.1.1.13  root      132:                                if (LoadX(file, file_size) == false) {
                    133:                                        goto abort;
                    134:                                }
1.1.1.7   root      135:                        } else if (file[0] == 0x60 && file[1] == 0x1a) {
1.1.1.13  root      136:                                if (LoadZ(file, file_size) == false) {
                    137:                                        goto abort;
                    138:                                }
1.1.1.7   root      139:                        } else {
1.1.1.13  root      140:                                errno = ENOEXEC;
                    141:                                warn("Human68k executable \"%s\"", human68k_file);
                    142:                                goto abort;
1.1.1.7   root      143:                        }
1.1       root      144:                }
                    145:        }
                    146:        munmap(file, file_size);
                    147: 
1.1.1.13  root      148:        last_addr = load_addr + load_size + bss_size;
1.1.1.16  root      149:        ram_size = (uint32)mainram->GetSize();
1.1       root      150: 
                    151:        boot_addr = 0x200;
1.1.1.13  root      152:        ds.Write4(0, ram_size - 4);     // 初期 SSP
                    153:        ds.Write4(4, boot_addr);
1.1       root      154: 
                    155:        // TRAP #15 ベクタを書き込む。
1.1.1.13  root      156:        ds.Write4(0xbc, 0x1000);
1.1.1.14  root      157:        // TRAP #15 (IOCS コール) ハンドラを書き込む。
                    158:        // オレオレ F ライン命令 (エミュレータ内部命令) で処理して RTE するだけ。
                    159:        ds.Write2(0x1000, 0xfa00);
1.1.1.13  root      160:        ds.Write2(0x1002, 0x4e73);      // rte
1.1       root      161: 
1.1.1.11  root      162:        // STOP による停止。終了時に CPU を止めておくため。
1.1.1.13  root      163:        ds.Write4(0x1010, 0x4e722700);  // stop #$2700
1.1.1.11  root      164: 
1.1.1.15  root      165:        // MFP Timer-C ベクタを書き込む。
                    166:        ds.Write4(0x0114, 0x1020);
                    167:        // Timer-C で 10ミリ秒ごとに $9cc.w のワークを減算していく。
                    168:        // 0 になったら $9d6.l の稼働時間(分) をインクリメントして、
                    169:        // $9cc.w には $9ca.w の初期値 (6000 = 60秒 * 100) を再セット。
1.1.1.16  root      170:        ds.SetAddr(0x1020);
1.1.1.15  root      171:        ds.Write2(0x5378);                      // subq.w       #1,($9cc)
                    172:        ds.Write2(0x9cc);
                    173:        ds.Write2(0x660a);                      // bne  @f
                    174:        ds.Write2(0x31f8);                      // move.w       ($9ca),($9cc)
                    175:        ds.Write2(0x09ca);
                    176:        ds.Write2(0x09cc);
                    177:        ds.Write2(0x52b8);                      // addq.l       #1,($9d6)
                    178:        ds.Write2(0x09d6);
                    179:        ds.Write2(0x4e73);                      //@@: rte
                    180:        ds.Write2(0x9ca, 6000);         // $9ca: 初期値
                    181:        ds.Write2(0x9cc, 6000);         // いきなり初期化しておく。
                    182: 
1.1       root      183:        // コマンドライン文字列を書き込む。LASCII 形式
1.1.1.16  root      184:        ds.SetAddr(0xc001);
1.1       root      185:        for (int i = 0; i < 255; i++) {
                    186:                uint8 c = human68k_arg[i];
1.1.1.13  root      187:                ds.Write1(c);
1.1       root      188:                if (c == '\0') {
1.1.1.13  root      189:                        ds.Write1(0xc000, i);
1.1       root      190:                        break;
                    191:                }
                    192:        }
1.1.1.8   root      193:        // XXX: 255文字以上のときどうなるか調べること
1.1       root      194: 
                    195:        // PSP (process entry) を書き込む。
1.1.1.13  root      196:        // instructiontest.x はコマンドラインを指定するだけで動くようだ。
1.1       root      197:        // PSP はロードアドレス-256 の位置でなければならないようだ。
                    198:        psp_base = 0x1ff00;
1.1.1.16  root      199:        ds.SetAddr(psp_base);
1.1       root      200: 
1.1.1.13  root      201:        ds.Write4(-1);          // 1つ前のメモリ管理ポインタ
                    202:        ds.Write4(-1);          // このメモリを確保したプロセスのメモリ管理ポインタ
                    203:        ds.Write4(ram_size - 4 + 1);    // このメモリブロックの終わり+1 のアドレス
                    204:        ds.Write4(-1);          // 次のメモリ管理ポインタ
                    205: 
                    206:        ds.Write4(psp_base + 0x20, 0xc000);     // コマンドライン
                    207: 
1.1.1.16  root      208:        ds.SetAddr(boot_addr);
1.1.1.13  root      209:        ds.Write2(0x2c4f);              // move.l       a7,a6
                    210:        ds.Write2(0x2e7c);              // move.l       psp_base,a7
                    211:        ds.Write4(psp_base);
                    212:        ds.Write2(0x4e66);              // move.l       a6,usp
                    213:        ds.Write2(0x207c);              // move.l       psp_base,a0
                    214:        ds.Write4(psp_base);
                    215:        ds.Write2(0x227c);              // move.l       last_addr,a1
                    216:        ds.Write4(last_addr);
                    217:        ds.Write2(0x247c);              // move.l       #$c000,a2
                    218:        ds.Write4(0xc000);
                    219:        ds.Write2(0x267c);              // move.l       #$e000,a3
                    220:        ds.Write4(0xe000);
                    221:        ds.Write2(0x287c);              // move.l       exec_addr,a4
                    222:        ds.Write4(exec_addr);
                    223:        ds.Write2(0x2c49);              // move.l       a1,a6
1.1.1.15  root      224:        ds.Write2(0x46fc);              // move.w       #$0500,sr
                    225:        ds.Write2(0x0500);
1.1.1.13  root      226:        ds.Write2(0x4eb9);              // jsr.l        exec_addr
                    227:        ds.Write4(exec_addr);
                    228:        ds.Write2(0xff00);              // DOS          _EXIT
1.1       root      229: 
                    230:        putmsg(1, "LoadFile complete");
                    231:        return true;
1.1.1.13  root      232: 
                    233:  abort:
                    234:        munmap(file, file_size);
                    235:        return false;
1.1       root      236: }
                    237: 
1.1.1.13  root      238: // R 形式ファイルをロードする。
                    239: // 成功すれば true を返す。失敗すればエラーメッセージを表示して false を返す。
1.1       root      240: bool
1.1.1.13  root      241: Human68kDevice::LoadR(const uint8 *file, uint size)
1.1       root      242: {
1.1.1.13  root      243:        // リロケータブルなのでどこでもいい。
1.1       root      244:        load_addr = default_load_addr;
                    245:        load_size = size;
1.1.1.13  root      246:        if (LoadMem(load_addr, &file[0], load_size) == false) {
                    247:                return false;
                    248:        }
1.1       root      249: 
1.1.1.13  root      250:        // R 形式はファイル先頭が実行開始位置。
1.1       root      251:        exec_addr = load_addr;
                    252:        text_size = load_size;
                    253:        putmsg(1, "r format");
                    254:        return true;
                    255: }
                    256: 
1.1.1.13  root      257: // X 形式ファイルをロードする。
                    258: // 成功すれば true を返す。失敗すればエラーメッセージを表示して false を返す。
1.1       root      259: bool
1.1.1.13  root      260: Human68kDevice::LoadX(const uint8 *file, uint size)
1.1       root      261: {
1.1.1.13  root      262:        auto *hdr = reinterpret_cast<const XFileHeader *>(file);
1.1       root      263:        uint hdr_size = sizeof(*hdr);
                    264: 
                    265:        if (!(hdr->magic[0] == 'H' && hdr->magic[1] == 'U')) {
1.1.1.13  root      266:                warnx("Human68k executable \"%s\" invalid magic", human68k_file);
                    267:                return false;
1.1       root      268:        }
                    269:        base_addr = be32toh(hdr->base_addr);
                    270:        exec_addr = be32toh(hdr->exec_addr);
                    271:        text_size = be32toh(hdr->text_size);
                    272:        data_size = be32toh(hdr->data_size);
                    273:        bss_size = be32toh(hdr->bss_size);
                    274: 
                    275:        uint32 reloc_size = be32toh(hdr->reloc_size);
                    276: 
1.1.1.13  root      277:        // 最適配置位置も可能だが今回見送り。
1.1       root      278:        load_addr = default_load_addr;
                    279:        load_size = text_size + data_size;
1.1.1.13  root      280:        if (LoadMem(load_addr, &file[hdr_size], load_size) == false) {
                    281:                return false;
                    282:        }
1.1       root      283: 
1.1.1.13  root      284:        // 再配置テーブルの file での位置。
1.1       root      285:        uint32 reloc_pos = hdr_size + load_size;
                    286: 
1.1.1.13  root      287:        // 再配置。
                    288:        IODeviceStream ds(mainram);
1.1       root      289:        uint32 offset = load_addr - base_addr;
                    290:        uint32 reloc_end = reloc_pos + reloc_size;
                    291:        uint32 A = load_addr;
                    292:        uint32 B = base_addr;
                    293:        uint32 C = A - B;
                    294:        while (reloc_pos < reloc_end) {
1.1.1.13  root      295:                putmsg(3, "reloc_pos=%08x reloc_end=%08x", reloc_pos, reloc_end);
1.1       root      296:                uint32 D;
1.1.1.13  root      297:                D = be16toh(*(const uint16 *)&file[reloc_pos]);
                    298:                putmsg(3, "D=%x", D);
1.1       root      299:                reloc_pos += 2;
                    300:                if (D == 1) {
1.1.1.13  root      301:                        D = be32toh(*(const uint32 *)&file[reloc_pos]);
                    302:                        putmsg(3, " odd, D=%x", D);
1.1       root      303:                        reloc_pos += 4;
                    304:                }
                    305:                if ((D & 1) == 0) {
                    306:                        A += D;
1.1.1.13  root      307:                        uint32 old = ds.Read4(A);
                    308:                        ds.Write4(A, old + C);
                    309:                        putmsg(3, " Write_L A=%x, old=%x new=%x", A, old, old + C);
1.1       root      310:                } else {
                    311:                        A += D - 1;
1.1.1.13  root      312:                        uint32 old = ds.Read2(A);
                    313:                        ds.Write2(A, old + C);
                    314:                        putmsg(3, " Write_W A=%x, old=%x new=%x", A, old, old + C);
1.1       root      315:                }
                    316:        }
                    317: 
                    318:        exec_addr += offset;
                    319: 
                    320:        putmsg(1, "x format, base_addr=%08x, exec_addr=%08x", base_addr, exec_addr);
                    321: 
                    322:        return true;
                    323: }
                    324: 
1.1.1.13  root      325: // Z 形式ファイルをロードする。
                    326: // 成功すれば true を返す。失敗すればエラーメッセージを表示して false を返す。
1.1       root      327: bool
1.1.1.13  root      328: Human68kDevice::LoadZ(const uint8 *file, uint size)
1.1       root      329: {
1.1.1.13  root      330:        auto *hdr = reinterpret_cast<const ZFileHeader *>(file);
1.1       root      331:        uint32 hdr_size = sizeof(*hdr);
                    332: 
                    333:        if (be16toh(hdr->magic1) != 0x601a) {
1.1.1.13  root      334:                warnx("Human68k executable \"%s\" invalid magic", human68k_file);
                    335:                return false;
1.1       root      336:        }
                    337:        text_size = be32toh(hdr->text_size);
                    338:        data_size = be32toh(hdr->data_size);
                    339:        bss_size = be32toh(hdr->bss_size);
                    340:        base_addr = be32toh(hdr->base_addr);
                    341:        exec_addr = base_addr;
                    342: 
                    343:        if (base_addr < 0x20000) {
1.1.1.13  root      344:                warnx("Human68k executable \"%s\" unsupported base specified",
                    345:                        human68k_file);
                    346:                return false;
1.1       root      347:        }
                    348: 
                    349:        load_addr = base_addr;
                    350:        load_size = text_size + data_size;
1.1.1.13  root      351:        if (LoadMem(load_addr, &file[hdr_size], load_size) == false) {
                    352:                return false;
                    353:        }
1.1       root      354: 
                    355:        putmsg(1, "z format, base_addr=%08x, exec_addr=%08x", base_addr, exec_addr);
                    356:        return true;
                    357: }
                    358: 
1.1.1.13  root      359: // なぜか m68k ELF .o が読める。
                    360: // 成功すれば true を返す。失敗すればエラーメッセージを表示して false を返す。
1.1.1.7   root      361: bool
1.1.1.13  root      362: Human68kDevice::LoadELF(const uint8 *file, uint size)
1.1.1.7   root      363: {
1.1.1.11  root      364:        LoadInfo info(human68k_file, file, size);
1.1.1.16  root      365:        if (BootLoader::LoadExec(mainram, &info) == false) {
1.1.1.7   root      366:                return false;
                    367:        }
                    368: 
1.1.1.11  root      369:        // XXX load_size は esym のような気がする。
                    370:        // XXX text_size も今はやろうと思えば返せる構造になったが未対応。
                    371:        load_addr = info.entry;
1.1.1.7   root      372:        load_size = size;
1.1.1.11  root      373:        exec_addr = info.entry;
1.1.1.7   root      374:        text_size = size;
                    375:        return true;
                    376: }
                    377: 
1.1.1.13  root      378: // src から size バイトを RAM の addr 以降にロードする。
                    379: // 成功すれば true を返す。
                    380: // ファイルが RAM に収まらない場合はエラーメッセージを表示して false を返す。
1.1       root      381: bool
1.1.1.13  root      382: Human68kDevice::LoadMem(uint32 addr, const uint8 *src, uint size)
1.1       root      383: {
1.1.1.13  root      384:        if (addr + size >= mainram->GetSize()) {
                    385:                warnx("Human68k executable \"%s\": file too large", human68k_file);
                    386:                return false;
1.1       root      387:        }
                    388: 
1.1.1.13  root      389:        mainram->WriteMem(addr, src, size);
1.1       root      390:        return true;
                    391: }
                    392: 
                    393: // file の拡張子が ext なら true を返す。ext は '.' を含む。
                    394: bool
1.1.1.12  root      395: Human68kDevice::isext(const char *file, const char *ext)
1.1       root      396: {
                    397:        size_t len_file = strlen(file);
                    398:        size_t len_ext = strlen(ext);
1.1.1.13  root      399:        if (len_ext == 0) {
1.1       root      400:                return false;
                    401:        }
                    402:        if (len_file < len_ext) {
                    403:                return false;
                    404:        }
                    405: 
                    406:        return strcasecmp(&file[len_file - len_ext], ext) == 0;
                    407: }
                    408: 
                    409: 
1.1.1.7   root      410: // 仮想マシンの中から終了させる
1.1.1.13  root      411: // (MSXDOSDevice からも終了時に呼ぶ)。
1.1.1.11  root      412: // XXX code は未対応。
                    413: /*static*/ void
1.1.1.12  root      414: Human68kDevice::RequestExit(int code)
1.1.1.7   root      415: {
1.1.1.11  root      416:        // 電源を即切る
                    417:        auto power = GetPowerDevice();
1.1.1.12  root      418:        power->PushPowerButton();
1.1.1.11  root      419:        power->SetSystemPowerOn(false);
1.1.1.7   root      420: }
                    421: 
1.1.1.13  root      422: // F-Line 命令をこちらで処理する。
1.1       root      423: bool
1.1.1.11  root      424: human68k_fline_callback(MPU680x0Device *, void *arg)
1.1       root      425: {
1.1.1.13  root      426:        auto *human68k = reinterpret_cast<Human68kDevice *>(arg);
1.1.1.11  root      427:        return human68k->FLineOp();
1.1       root      428: }
                    429: 
1.1.1.13  root      430: // F-Line 命令。
1.1       root      431: bool
1.1.1.12  root      432: Human68kDevice::FLineOp()
1.1       root      433: {
1.1.1.12  root      434:        switch (mpu680x0->GetIR()) {
1.1.1.14  root      435:         case 0xfa00:           // IOCS call emulation
1.1.1.11  root      436:                IOCS();
1.1       root      437:                break;
                    438: 
1.1.1.18! root      439:         case 0xfe11:           // FPACK __LTOS
        !           440:         {
        !           441:                putlog(1, "FPACK __LTOS");
        !           442:                uint32 data = RegD(0);
        !           443:                uint32 dst = RegA(0);
        !           444:                char buf[16];
        !           445:                snprintf(buf, sizeof(buf), "%d", data);
        !           446:                for (char *p = buf; ; p++, dst++) {
        !           447:                        uint8 c = *p;
        !           448:                        mainbus->HVWrite1(dst, c);
        !           449:                        if (c == 0) {
        !           450:                                break;
        !           451:                        }
        !           452:                }
        !           453:                // '\0' の位置を A0 に返す。
        !           454:                RegA(0) = dst;
        !           455:                break;
        !           456:         }
        !           457: 
1.1.1.13  root      458:         case 0xff00:           // _EXIT
                    459:                putlog(1, "DOS _EXIT");
1.1.1.11  root      460:                // XXX CPU の実行を止める。方式自体を I/O 方式に見直したときには
                    461:                // ちゃんとした方法を取る予定。
1.1.1.12  root      462:                mpu680x0->SetSR(mpu680x0->GetSR() | 0x2000);
                    463:                mpu680x0->reg.pc = 0x1010;
1.1.1.7   root      464:                RequestExit(0);
                    465:                break;
1.1       root      466: 
1.1.1.13  root      467:         case 0xff09:           // _PRINT
1.1       root      468:         {
1.1.1.13  root      469:                uint32 dataptr = mainbus->HVRead4(RegA(7));
                    470:                putlog(2, "DOS _PRINT($%06x)", dataptr);
1.1.1.11  root      471:                DOS_PRINT(dataptr);
1.1       root      472:                break;
                    473:         }
                    474: 
1.1.1.13  root      475:         case 0xff1e:           // _FPUTS
1.1       root      476:         {
1.1.1.13  root      477:                uint32 mesptr = mainbus->HVRead4(RegA(7));
                    478:                uint16 fileno = mainbus->HVRead2(RegA(7) + 4);
                    479:                putlog(2, "DOS _FPUTS(fileno=%d, mesptr=$%06x)", fileno, mesptr);
1.1       root      480:                FputsFile(fileno, mesptr);
                    481:                break;
                    482:         }
                    483: 
1.1.1.13  root      484:         case 0xff20:           // _SUPER
1.1       root      485:         {
1.1.1.13  root      486:                uint32 data = mainbus->HVRead4(RegA(7));
1.1       root      487: 
1.1.1.13  root      488:                putlog(1, "DOS _SUPER($%x) to %s", data,
                    489:                        (data == 0) ? "SUPERVISOR" : "USER");
1.1       root      490:                if (data == 0) {
1.1.1.12  root      491:                        mpu680x0->SetSR(mpu680x0->GetSR() | 0x2000);
                    492:                        data = mpu680x0->reg.usp;
1.1       root      493:                        RegD(0) = RegA(7);
                    494:                        RegA(7) = data;
                    495:                } else {
1.1.1.12  root      496:                        mpu680x0->SetSR(mpu680x0->GetSR() | 0x2000);
1.1       root      497:                        RegA(7) = data;
1.1.1.12  root      498:                        mpu680x0->SetSR(mpu680x0->GetSR() & ~0x2000);
1.1       root      499:                }
                    500:                break;
                    501:         }
                    502: 
1.1.1.13  root      503:         case 0xff25:           // _INTVCS
1.1       root      504:         {
1.1.1.13  root      505:                uint16 intno = mainbus->HVRead2(RegA(7));
                    506:                uint32 addr  = mainbus->HVRead4(RegA(7) + 2);
                    507:                putlog(1, "DOS _INTVCS(intno=$%02x, addr=$%06x)", intno, addr);
1.1       root      508: 
                    509:                uint32 vecaddr = (intno & 0xff) * 4;
                    510: 
                    511:                if (intno <= 0xff) {
1.1.1.13  root      512:                        RegD(0) = mainbus->HVRead4(vecaddr);
                    513:                        mainbus->HVWrite4(vecaddr, addr);
1.1       root      514:                } else {
                    515:                        vecaddr += 0xd000;
1.1.1.13  root      516:                        RegD(0) = mainbus->HVRead4(vecaddr);
                    517:                        mainbus->HVWrite4(vecaddr, addr);
1.1.1.6   root      518:                }
1.1       root      519:                break;
                    520:         }
                    521: 
1.1.1.13  root      522:         case 0xff27:           // _GETTIM2
1.1       root      523:         {
1.1.1.13  root      524:                struct tm tm;
                    525:                time_t now = time(NULL);
                    526:                localtime_r(&now, &tm);
                    527:                RegD(0) = (tm.tm_hour << 16)
                    528:                                | (tm.tm_min  << 8)
                    529:                                |  tm.tm_sec;
                    530:                putlog(1, "DOS _GETTIM2 -> $%08x", RegD(0));
1.1       root      531:                break;
                    532:         }
                    533: 
1.1.1.13  root      534:         case 0xff2a:           // _GETDATE
1.1       root      535:         {
1.1.1.13  root      536:                struct tm tm;
                    537:                time_t now = time(NULL);
                    538:                localtime_r(&now, &tm);
                    539:                RegD(0) = (tm.tm_wday << 16)
                    540:                                | ((tm.tm_year + 1900 - 1980) << 9)
                    541:                                | ((tm.tm_mon + 1) << 5)
                    542:                                |   tm.tm_mday;
                    543:                putlog(1, "DOS _GETDATE -> $%08x", RegD(0));
1.1       root      544:                break;
                    545:         }
                    546: 
1.1.1.13  root      547:         case 0xff30:           // _VERNUM
1.1       root      548:         {
                    549:                RegD(0) = 0x36380302;           // ver3.02
1.1.1.13  root      550:                putlog(1, "DOS _VERNUM -> $%08x", RegD(0));
1.1       root      551:                break;
                    552:         }
                    553: 
1.1.1.13  root      554:         case 0xff35:           // _INTVCG
1.1       root      555:         {
1.1.1.13  root      556:                uint16 intno = mainbus->HVRead2(RegA(7));
1.1       root      557:                uint32 vecaddr = (intno & 0xff) * 4;
                    558: 
                    559:                if (intno <= 0xff) {
1.1.1.13  root      560:                        RegD(0) = mainbus->HVRead4(vecaddr);
1.1       root      561:                } else {
                    562:                        vecaddr += 0xd000;
1.1.1.13  root      563:                        RegD(0) = mainbus->HVRead4(vecaddr);
1.1       root      564:                }
1.1.1.13  root      565:                putlog(1, "DOS _INTVCG(intno=%d) -> $%08x", intno, RegD(0));
1.1       root      566:                break;
                    567:         }
                    568: 
1.1.1.13  root      569:         case 0xff3c:           // _CREATE
1.1       root      570:         {
1.1.1.13  root      571:                uint32 file = mainbus->HVRead4(RegA(7));
                    572:                uint16 atr  = mainbus->HVRead2(RegA(7) + 4);
                    573:                putlog(1, "DOS _CREATE(file=$%x, atr=$%x)", file, atr);
1.1       root      574: 
                    575:                int32 fileno = OpenFile(file, atr,
                    576:                        O_CREAT | O_TRUNC | O_RDWR | O_SYNC);
                    577:                RegD(0) = fileno;
                    578:                break;
                    579:         }
                    580: 
1.1.1.13  root      581:         case 0xff3d:           // _OPEN
1.1       root      582:         {
1.1.1.13  root      583:                uint32 file = mainbus->HVRead4(RegA(7));
                    584:                uint16 mode = mainbus->HVRead2(RegA(7) + 4);
                    585:                int unix_mode = 0;
                    586:                bool ok = true;
                    587:                putlog(1, "DOS _OPEN(file=$%x, mode=$%x)", file, mode);
1.1       root      588: 
1.1.1.13  root      589:                // mode の辞書モード、シェアリングモードは無視している。
                    590:                switch (mode & 0x03) {  // read/write
                    591:                 case 2:
                    592:                        unix_mode |= O_RDWR;
                    593:                        break;
                    594:                 case 1:
                    595:                        unix_mode |= O_WRONLY;
                    596:                        break;
                    597:                 case 0:
                    598:                        unix_mode |= O_RDONLY;
                    599:                        break;
                    600:                 default:
                    601:                        RegD(0) = -12;  // アクセスモード異常
                    602:                        ok = false;
                    603:                        break;
                    604:                }
                    605: 
                    606:                if (ok) {
                    607:                        int32 fileno = OpenFile(file, 0, unix_mode | O_SYNC);
                    608:                        RegD(0) = fileno;
                    609:                }
                    610:                break;
                    611:         }
                    612: 
                    613:         case 0xff3e:           // _CLOSE
                    614:         {
                    615:                uint16 fileno = mainbus->HVRead2(RegA(7));
                    616: 
                    617:                putlog(1, "DOS _CLOSE(fileno=%d)", fileno);
1.1       root      618:                CloseFile(fileno);
                    619:                RegD(0) = 0;
                    620:                break;
                    621:         }
                    622: 
1.1.1.13  root      623:         case 0xff40:           // _WRITE
1.1       root      624:         {
1.1.1.13  root      625:                uint16 fileno  = mainbus->HVRead2(RegA(7));
                    626:                uint32 dataptr = mainbus->HVRead4(RegA(7) + 2);
                    627:                uint32 size    = mainbus->HVRead4(RegA(7) + 6);
                    628:                putlog(2, "DOS _WRITE(fileno=%u, dataptr=$%06x, size=$%08x)",
                    629:                        fileno, dataptr, size);
1.1       root      630:                RegD(0) = WriteFile(fileno, dataptr, size);
                    631:                break;
                    632:         }
                    633: 
1.1.1.13  root      634:         case 0xff44:           // _IOCTRL
1.1       root      635:         {
1.1.1.13  root      636:                uint32 mode = mainbus->HVRead2(RegA(7));
1.1       root      637:                uint32 fileno;
                    638:                switch (mode) {
1.1.1.13  root      639:                 case 0:        // IOCTRLGT 装置情報取得
                    640:                        fileno = mainbus->HVRead2(RegA(7) + 2);
1.1       root      641:                        if (fileno == 0) { // STDIN
                    642:                                RegD(0) = 0x8081; // 100u'uuuu'100u'0001;
                    643:                        } else if (fileno == 1) { // STDOUT
                    644:                                RegD(0) = 0x8082; // 100u'uuuu'100u'0010;
                    645:                        } else if (fileno == 2) { // STDERR
                    646:                                RegD(0) = 0x8081; // 100u'uuuu'100u'0001;
                    647:                        } else {
                    648:                                RegD(0) = -1;
                    649:                        }
1.1.1.13  root      650:                        putlog(1, "DOS _IOCTRL(mode=0(IOCTRLGT), fileno=%d) -> $%x",
                    651:                                fileno, RegD(0));
                    652:                        break;
                    653: 
                    654:                 case 7:        // IOCTRLOS 出力ステータス取得
                    655:                        fileno = mainbus->HVRead2(RegA(7) + 2);
                    656:                        if (fileno == 0) {
                    657:                                RegD(0) = 0;
                    658:                        } else if (fileno == 1 || fileno == 2) {
                    659:                                RegD(0) = -1;
                    660:                        } else {
                    661:                                int filemode = GetFileMode(fileno);
                    662:                                if (filemode < 0) {
                    663:                                        RegD(0) = filemode;
                    664:                                } else if (filemode == O_WRONLY || filemode == O_RDWR) {
                    665:                                        RegD(0) = -1;
                    666:                                } else {
                    667:                                        RegD(0) = 0;
                    668:                                }
                    669:                        }
                    670:                        putlog(1, "DOS _IOCTRL(mode=7(IOCTRLOS), fileno=%d) -> %d",
                    671:                                fileno, RegD(0));
1.1       root      672:                        break;
1.1.1.13  root      673: 
1.1       root      674:                 default:
1.1.1.13  root      675:                        errx(EXIT_FAILURE, "DOS _IOCTRL(mode=%d) not implemented", mode);
1.1       root      676:                }
                    677:                break;
                    678:         }
                    679: 
1.1.1.13  root      680:         case 0xff4a:           // _SETBLOCK
1.1       root      681:         {
1.1.1.13  root      682:                uint32 memptr = mainbus->HVRead4(RegA(7));
                    683:                uint32 len    = mainbus->HVRead4(RegA(7) + 4);
                    684:                putlog(1, "DOS _SETBLOCK(memptr=$%x, len=$%x)", memptr, len);
1.1       root      685:                // なにもせずに、できたという
1.1.1.13  root      686:                RegD(0) = mainbus->HVRead4(RegA(7) + 4);
1.1       root      687:                break;
                    688:         }
                    689: 
1.1.1.13  root      690:         case 0xff4c:           // _EXIT2
1.1       root      691:         {
1.1.1.13  root      692:                uint32 data = mainbus->HVRead2(RegA(7));
                    693:                putlog(1, "DOS _EXIT2(%d)", data);
1.1.1.7   root      694:                RequestExit(data);
                    695:                break;
1.1       root      696:         }
                    697: 
1.1.1.13  root      698:         case 0xffac:           // _GETFCB
1.1       root      699:         {
1.1.1.13  root      700:                uint32 fileno = mainbus->HVRead2(RegA(7));
                    701:                putlog(1, "DOS _GETFCB(fileno=%d)", fileno);
1.1       root      702:                if (fileno <= 4) {
                    703:                        RegD(0) = 0x8000 + fileno * 0x60;
                    704:                } else {
                    705:                        RegD(0) = -1;
                    706:                }
                    707:                break;
                    708:         }
                    709: 
1.1.1.13  root      710:         case 0xfff7:           // _BUS_ERR
1.1       root      711:         {
1.1.1.13  root      712:                uint32 p1   = mainbus->HVRead4(RegA(7));
                    713:                uint32 p2   = mainbus->HVRead4(RegA(7) + 4);
                    714:                uint16 size = mainbus->HVRead2(RegA(7) + 8);
                    715:                putlog(1, "DOS _BUS_ERR(size=%d p1=$%x p2=$%x)", size, p1, p2);
1.1       root      716: 
                    717:                RegD(0) = -1;
                    718:                uint32 data;
                    719:                try {
                    720:                        if (size == 1) {
1.1.1.13  root      721:                                data = mainbus->HVRead1(p1);
1.1       root      722:                        } else if (size == 2 && ((p1 & 1) == 0)) {
1.1.1.13  root      723:                                data = mainbus->HVRead2(p1);
1.1       root      724:                        } else if (size == 4 && ((p1 & 1) == 0)) {
1.1.1.13  root      725:                                data = mainbus->HVRead4(p1);
1.1       root      726:                        } else {
                    727:                                break;
                    728:                        }
                    729:                } catch (int cause) {
1.1.1.11  root      730:                        if (cause == M68K::EXCEP_BUSERR) {
1.1       root      731:                                RegD(0) = 2;
                    732:                                break;
                    733:                        } else {
                    734:                                throw;
                    735:                        }
                    736:                }
                    737: 
                    738:                try {
                    739:                        if (size == 1) {
1.1.1.13  root      740:                                mainbus->HVWrite1(p2, data);
1.1       root      741:                        } else if (size == 2 && ((p2 & 1) == 0)) {
1.1.1.13  root      742:                                mainbus->HVWrite2(p2, data);
1.1       root      743:                        } else if (size == 4 && ((p2 & 1) == 0)) {
1.1.1.13  root      744:                                mainbus->HVWrite4(p2, data);
1.1       root      745:                        } else {
                    746:                                break;
                    747:                        }
                    748:                } catch (int cause) {
1.1.1.11  root      749:                        if (cause == M68K::EXCEP_BUSERR) {
1.1       root      750:                                RegD(0) = 1;
                    751:                                break;
                    752:                        } else {
                    753:                                throw;
                    754:                        }
                    755:                }
                    756:                RegD(0) = 0;
                    757:                break;
                    758:         }
                    759: 
1.1.1.13  root      760:         case 0xffff:           // _CHANGE_PR
                    761:         {
                    762:                putlog(1, "DOS _CHANGE_PR");
                    763:                // なにもしない。
                    764:                break;
                    765:         }
                    766: 
1.1       root      767:         default:
1.1.1.11  root      768:                printf("DOSCALL $%02x at $%08X (NOT IMPLEMENTED)\n",
1.1.1.12  root      769:                        mpu680x0->GetIR(), mpu680x0->GetPPC());
1.1.1.7   root      770:                RequestExit(1);
                    771:                break;
1.1       root      772:        }
                    773:        return true;
                    774: }
1.1.1.11  root      775: 
                    776: void
1.1.1.13  root      777: Human68kDevice::IOCS()
                    778: {
                    779:        // XXX 本当は HVRead*() の IsBusErr() を調べないといけない。
                    780: 
                    781:        // 呼び出し元っぽい PC を表示したい。
                    782:        uint32 pc = mainbus->HVRead4(RegA(7) + 2) - 2;
                    783:        if ((mainbus->HVRead2(pc - 2) & 0xff00) == 0x7000) {
                    784:                // moveq #imm, d0
                    785:                pc -= 2;
                    786:        }
                    787: 
                    788:        switch (RegD(0) & 0xff) {
                    789:         case 0x21:     // _B_PRINT
                    790:         {
                    791:                uint32 dataptr = RegA(1);
                    792:                putlog(2, "PC=$%06x IOCS _B_PRINT($%06x)", pc, dataptr);
                    793:                DOS_PRINT(dataptr);
                    794:                // 戻り値 d0 は表示後の位置だが無視。
                    795:                break;
                    796:         }
                    797:         case 0x7f:     // _ONTIME
                    798:         {
                    799:                putlog(1, "PC=$%06x IOCS _ONTIME", pc);
                    800:                uint64 t = scheduler->GetVirtTime();
                    801:                // nanosec to 10msec, in day
                    802:                RegD(0) = (t / 10_msec) % 8640000;
                    803:                // nanosec to day
                    804:                RegD(1) = t / 86400_sec;
                    805:                break;
                    806:         }
1.1.1.15  root      807:         case 0x80:     // _B_INTVCS
                    808:         {
                    809:                uint32 num = RegD(1);
                    810:                uint32 newaddr = RegA(1);
                    811:                uint32 oldaddr;
                    812:                if (num < 0x100) {
                    813:                        oldaddr = mainbus->HVRead4(num * 4);
                    814:                        mainbus->HVWrite4(num * 4, newaddr);
                    815:                        RegD(0) = oldaddr;
                    816:                } else {
                    817:                        printf("IOCS _B_INTVCS(#%04x) (NOT IMPLEMENTED)", num);
                    818:                        RequestExit(1);
                    819:                }
                    820:                break;
                    821:         }
1.1.1.13  root      822:         case 0x82:     // _B_BPEEK
                    823:         {
                    824:                uint32 data = mainbus->HVRead1(RegA(1));
                    825:                putlog(1, "PC=$%06x IOCS _B_BPEEK($%06x) -> $%02x", pc, RegA(1), data);
                    826:                RegD(0) = (RegD(0) & 0xffffff00) | data;
                    827:                RegA(1)++;
                    828:                break;
                    829:         }
                    830:         case 0xac: // _SYS_STAT (ROM1.3)
                    831:                switch (RegD(1)) {
                    832:                 case 0:
                    833:                        // MPU 状態の取得
                    834:                        RegD(0) =
                    835:                            ((250) << 16)       // 25.0MHz
1.1.1.14  root      836:                          | ((mpu680x0->HasFPU() ? 1 : 0) << 15)        // FPU
1.1.1.13  root      837:                          | ((0) << 14)         // MMU
                    838:                          | ((3) << 0);         // MPU Type
                    839:                        break;
                    840:                 case 1:
                    841:                        // キャッシュ状態の取得
                    842:                        RegD(0) = 0;
                    843:                        break;
                    844:                 case 2:
                    845:                        // キャッシュを SRAM の設定値に設定
                    846:                        RegD(0) = 0;
                    847:                        break;
                    848:                 case 3:
                    849:                        // キャッシュの消去
                    850:                        RegD(0) = 0;
                    851:                        break;
                    852:                 case 4:
                    853:                        // キャッシュの設定
                    854:                        RegD(0) = 0;
                    855:                        break;
                    856:                 default:
                    857:                        break;
                    858:                }
                    859:                putlog(1, "PC=$%06x IOCS _SYS_STAT(%x) -> $%x", pc, RegD(1), RegD(0));
                    860:                break;
                    861: 
                    862:         default:
1.1.1.14  root      863:                printf("IOCS $%02x at $%06x (NOT IMPLEMENTED)\n",
                    864:                        RegD(0) & 0xff, pc);
1.1.1.13  root      865:                RequestExit(1);
                    866:                break;
                    867:        }
                    868: }
                    869: 
                    870: void
1.1.1.12  root      871: Human68kDevice::DOS_PRINT(uint32 dataptr)
1.1.1.11  root      872: {
                    873:        int c;
1.1.1.13  root      874:        while ((c = mainbus->HVRead1(dataptr++)) != 0) {
                    875:                putchar(c);
1.1.1.11  root      876:        }
                    877:        RegD(0) = 0;
                    878: }
1.1.1.13  root      879: 
                    880: // ファイルをオープンする。
                    881: // fileaddr: Human68k ファイル名のゲストアドレス
                    882: // atr: Human68k の属性
                    883: // mode: unix open mode
                    884: // 戻り値は Human68k fileno。
                    885: int32
                    886: Human68kDevice::OpenFile(uint32 fileaddr, uint16 atr, int mode)
                    887: {
                    888:        int32 fileno {};
                    889:        Human68kDevice::File *f = NULL;
                    890: 
                    891:        // 空いてるエントリを検索して Human fileno を取得。
                    892:        for (int i = 0; i < FilesCount; i++) {
                    893:                if (Files[i].fd == -1) {
                    894:                        fileno = i;
                    895:                        f = &Files[fileno];
                    896:                        break;
                    897:                }
                    898:        }
                    899:        if (f == NULL) {
                    900:                return -1;
                    901:        }
                    902: 
                    903:        // ファイル名変換。
                    904:        std::string filename;
                    905:        for (uint8 c; (c = mainbus->HVRead1(fileaddr++)) != '\0'; ) {
                    906:                if (c < 32 || c >= 127 || c == 0x5c) {
                    907:                        char hex[16];
                    908:                        snprintf(hex, sizeof(hex), "%02X", c);
                    909:                        filename += std::string(hex);
                    910:                } else {
                    911:                        filename += c;
                    912:                }
                    913:        }
                    914: 
                    915:        int fd = open(filename.c_str(), mode, 0666);
                    916:        if (fd == -1) {
                    917:                putmsg(1, "OpenFile: %s: %s", filename.c_str(), strerror(errno));
                    918:                return -1;
                    919:        }
                    920: 
                    921:        f->fd = fd;
                    922:        f->filename = filename;
                    923: 
                    924:        putmsg(1, "OpenFile: name=\"%s\" mode=$%x -> fileno=%u",
                    925:                filename.c_str(), mode, fileno);
                    926:        return fileno;
                    927: }
                    928: 
                    929: // ファイルをクローズする。
                    930: // fileno: Human68k fileno
                    931: int32
                    932: Human68kDevice::CloseFile(int32 fileno)
                    933: {
                    934:        Human68kDevice::File *f;
                    935: 
                    936:        if (fileno <= 0 || fileno >= FilesCount) {
                    937:                putmsg(1, "CloseFile: fileno=%d is not opened", fileno);
                    938:                return -1;
                    939:        }
                    940:        f = &Files[fileno];
                    941:        putmsg(1, "CloseFile: %d \"%s\"", fileno, f->filename.c_str());
                    942:        if (f->fd > 2) {
                    943:                close(f->fd);
                    944:        }
                    945:        f->fd = -1;
                    946:        f->filename.clear();
                    947:        return 0;
                    948: }
                    949: 
                    950: // ファイルに書き出す。
                    951: // fileno: Human68k fileno
                    952: // dataaddr: データのゲストアドレス
                    953: // size: データ長
                    954: int32
                    955: Human68kDevice::WriteFile(int32 fileno, uint32 dataaddr, uint32 size)
                    956: {
                    957:        Human68kDevice::File *f;
                    958: 
                    959:        if (fileno <= 0 || fileno >= FilesCount) {
                    960:                putmsg(1, "WriteFile: fileno=%d is not opened", fileno);
                    961:                return -1;
                    962:        }
                    963: 
                    964:        f = &Files[fileno];
                    965:        if (f->fd < 0) {
                    966:                return -1;
                    967:        }
                    968: 
                    969:        std::vector<uint8> buf(size);
                    970:        mainram->ReadMem(dataaddr, buf.data(), size);
                    971: 
                    972:        int32 rv = write(f->fd, buf.data(), size);
                    973:        return rv;
                    974: }
                    975: 
                    976: // 文字列をファイルに書き出す。
                    977: // fileno: Human68k fileno
                    978: // dataaddr: data addr (guest VA)
                    979: void
                    980: Human68kDevice::FputsFile(int32 fileno, uint32 dataaddr)
                    981: {
                    982:        Human68kDevice::File *f;
                    983: 
                    984:        if (fileno <= 0 || fileno >= FilesCount) {
                    985:                putmsg(1, "FputsFile: fileno=%d is not opened", fileno);
                    986:                return;
                    987:        }
                    988: 
                    989:        f = &Files[fileno];
                    990:        if (f->fd < 0) {
                    991:                return;
                    992:        }
                    993: 
                    994:        std::vector<uint8> buf;
                    995:        for (uint8 c; (c = mainbus->HVRead1(dataaddr++)) != '\0'; ) {
                    996:                buf.push_back(c);
                    997:        }
                    998:        if (buf.empty() == false) {
                    999:                write(f->fd, buf.data(), buf.size());
                   1000:        }
                   1001: }
                   1002: 
                   1003: // ファイルモードを取得する。
                   1004: // fileno: Human68k fileno
                   1005: // 戻り値: <0 Humak68k error code
                   1006: //       : >=0 unix file mode
                   1007: int
                   1008: Human68kDevice::GetFileMode(int32 fileno)
                   1009: {
                   1010:        Human68kDevice::File *f;
                   1011: 
                   1012:        if (fileno <= 0 || fileno >= FilesCount) {
                   1013:                return -2 /* FILE_NOT_FOUND */;
                   1014:        }
                   1015: 
                   1016:        f = &Files[fileno];
                   1017:        if (f->fd < 0) {
                   1018:                return -2 /* FILE_NOT_FOUND */;
                   1019:        }
                   1020: 
                   1021:        int fl = fcntl(f->fd, F_GETFL);
                   1022:        int accmode = fl & O_ACCMODE;
                   1023: 
                   1024:        return accmode;
                   1025: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.