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

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

unix.superglobalmegacorp.com

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