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

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

unix.superglobalmegacorp.com

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